如何在Android上的后台线程上运行代码?

时间:2013-03-18 08:24:44

标签: android multithreading

我想要一些代码在后台持续运行。我不想在服务中这样做。还有其他方法吗?

我已尝试在Thread中调用Activity课程,但我的Activity会在后台保留一段时间然后停止。 Thread课程也停止工作。

class testThread implements Runnable 
    {
        @Override
        public void run() 
        {
            File file = new File(Environment.getExternalStorageDirectory(),"/BPCLTracker/gpsdata.txt");
            int i=0;

        RandomAccessFile in = null;

        try
        {
            in = new RandomAccessFile(file, "rw");


        } 
        catch (FileNotFoundException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //String line =null;
        while (true) 
        {
            HttpEntity entity=null;
            try 
            {
                if (isInternetOn()) 
                {
                        while ((line = in.readLine()) != null)
                        {

                            HttpClient client = new DefaultHttpClient();
                            String url = "some url";
                            HttpPost request = new HttpPost(url);
                            StringEntity se = new StringEntity(line);
                            se.setContentEncoding("UTF-8");
                            se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
                            entity = se;
                            request.setEntity(entity);
                            HttpResponse response = client.execute(request);
                            entity = response.getEntity();
                            i++;
                        }
                        if((line = in.readLine()) == null && entity!=null)
                        {
                            file.delete();
                            testThread t = new testThread();
                            Thread t1 = new Thread(t);
                            t1.start();
                        }


                }// end of if
                else
                {
                    Thread.sleep(60000);

                } // end of else
            }// end of try
            catch (NullPointerException e1)
            {
                e1.printStackTrace();
            } 
            catch (InterruptedException e2) 
            {
                e2.printStackTrace();
            }
            catch (IOException e1) 
            {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }// end of while
    }// end of run

7 个答案:

答案 0 :(得分:310)

如果您需要:

  1. 在后台线程上执行代码

  2. 执行不接触/更新UI的代码

  3. 执行(短)代码,最多需要几秒钟才能完成

  4. 然后使用以下干净且高效的模式,它使用AsyncTask:

    AsyncTask.execute(new Runnable() {
       @Override
       public void run() {
          //TODO your background code
       }
    });
    

答案 1 :(得分:34)

对于长期后台进程,线程不是Android的最佳选择。但是,这是代码,并且风险自负......

请记住服务或线程将在后台运行,但我们的任务需要触发(一次又一次地调用)以获取更新,即一旦任务完成,我们需要调用该功能以进行下一次更新。

定时器(周期性触发),闹钟(时基触发),广播(事件基础触发),递归将唤醒我们的功能。

public static boolean isRecursionEnable = true;

void runInBackground() {
    if (!isRecursionEnable)
        // Handle not to start multiple parallel threads
        return;

    // isRecursionEnable = false; when u want to stop
    // on exception on thread make it true again  
    new Thread(new Runnable() {
        @Override
        public void run() {
            // DO your work here
            // get the data
            if (activity_is_not_in_background) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // update UI
                        runInBackground();
                    }
                });
            } else {
                runInBackground();
            }
        }
    }).start();
}

答案 2 :(得分:18)

  

我想要一些代码在后台持续运行。我不想要   在服务中做到这一点。还有其他方法吗?

您正在寻找的最有可能的机制是AsyncTask。它直接指定用于在后台线程上执行后台处理。此外,它的主要优点是提供了一些在Main(UI)线程上运行的方法,如果您想要告知用户任务进度或使用从后台进程检索的数据更新UI,则可以更新UI。

如果您不知道如何从这里开始是很好的教程:

注意:此外,还可以使用IntentServiceResultReceiver同时使用。

答案 3 :(得分:4)

简单的3-Liner

一种简单的操作方式,我在@awardakBrandon Rude's answer中找到了这条评论:

new Thread( new Runnable() { @Override public void run() { 
  // Run whatever background code you want here.
} } ).start();

我不确定这是否或如何比使用AsyncTask.execute更好,但这似乎对我们有用。关于差异的任何评论将不胜感激。

谢谢@awardak

答案 4 :(得分:2)

AsyncTask的替代方案是robospice。 https://github.com/octo-online/robospice

robospice的一些功能。

1.异步执行(在后台AndroidService中)网络请求(例如:使用Spring Android的REST请求)。在UI线程上,当结果准备好时,通知你应用程序。

2.强类型!您使用POJO发出请求,并获得POJO作为请求结果。

3.对用于请求的POJO和您在项目中使用的Activity类都没有约束。

4.caches结果(在Json中使用Jackson和Gson,或Xml,或平面文本文件,或二进制文件,甚至使用ORM Lite)。

5.当您的活动(或任何其他上下文)显示网络请求的结果时,当且仅当它们仍然存在时

6.完全没有内存泄漏,比如Android Loaders,不像Android AsyncTasks通过他们的UI线程通知你的活动。

7.使用简单但强大的异常处理模型。

开始的样品。 https://github.com/octo-online/RoboSpice-samples

https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result的robospice样本。

答案 5 :(得分:0)

如果您需要使用不同的代码预先运行线程,请参见以下示例:

监听器:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

线程类

public class ESLThread extends AsyncTask<Void, Void, List> {


    private ESLThreadListener mListener;

    public ESLThread() {

        if(mListener != null){

            mListener.onBackground();
        }
    }

    @Override
    protected List doInBackground(Void... params) {

        if(mListener != null){

            List list = mListener.onBackground();

            return list;
        }

        return null;
    }

    @Override
    protected void onPostExecute(List t) {
        if(mListener != null){

            if ( t != null) {
                mListener.onPostExecute(t);
            }
        }

    }


    public void setListener(ESLThreadListener mListener){

        this.mListener = mListener;
    }
}

运行不同的代码:

  ESLThread thread = new ESLThread();
                        thread.setListener(new ESLThreadListener() {
                            @Override
                            public List onBackground() {
                                List<EntityShoppingListItems>  data = RoomDB.getDatabase(context).sliDAO().getSL(fId);

                                return data;

                            }

                            @Override
                            public void onPostExecute(List t) {

                                List<EntityShoppingListItems> data = (List<EntityShoppingListItems>)t;
                                adapter.setList(data);
                            }
                        });

                        thread.execute();

答案 6 :(得分:0)

今天我正在寻找这个,布兰登·鲁德先生给了excellent answer。不幸的是,AsyncTask现在是depricated,您仍然可以使用它,但是它给您一个警告,非常烦人。因此,另一种方法是像这样Executors中使用kotlin


    val someRunnable = object : Runnable{
      override fun run() {
        // todo: do your background tasks
        requireActivity().runOnUiThread{
          // update views / ui if you are in a fragment
        };
        /*
        runOnUiThread {
          // update ui if you are in an activity
        }
        * */
      }
    };
    Executors.newSingleThreadExecutor().execute(someRunnable);

java中看起来像这样:


        Runnable someRunnable = new Runnable() {
            @Override
            public void run() {
                // todo: background tasks
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // todo: update your ui / view in activity
                    }
                });

                /*
                requireActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // todo: update your ui / view in Fragment
                    }
                });*/
            }
        };

        Executors.newSingleThreadExecutor().execute(someRunnable);