154

我希望一些代码在后台连续运行。我不想在服务中这样做。有没有其他可能的方法?

我试过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();
                        }


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

                } 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

    }
4

8 回答 8

415

如果你需要:

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

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

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

然后使用以下使用 AsyncTask 的简洁高效的模式:

AsyncTask.execute(new Runnable() {
   @Override
   public void run() {
      //TODO your background code
   }
});
于 2015-07-21T21:03:02.907 回答
48

记住运行背景,连续运行是两个不同的任务。

对于长期后台进程,线程不是 Android 的最佳选择。但是,这是代码,请自行承担风险。

要以正确的方式处理它,您需要首先启动服务,在服务内部,您需要启动需要可运行的线程/异步任务。

请记住,Service 和 Thread 将在后台运行,但我们的任务需要触发(一次又一次调用)以获取更新,即一旦任务完成,我们需要调用函数以进行下一次更新。

Timer(周期性触发),Alarm(时基触发),Broadcast(事件基触发),递归会唤醒我们的函数。

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();
}

使用服务: 如果你启动一个服务,它会启动,它会执行任务,如果服务不是 STICKY,它会在任务执行后自行终止。此服务终止也可能是由代码中的异常或用户从设置中手动终止的。

START_STICKY(粘性服务)是 Android 提供的选项,如果服务终止,服务将自行重启。

还记得多处理和多线程之间的问题区别吗? Service 是一个后台进程(就像没有 UI 的活动一样),与您在活动中启动线程以避免负载在 MainThread(活动/UI 线程)上的方式相同,您需要在服务上启动线程以避免负载的方式相同服务。

在单个语句中,如果要运行后台继续任务,则需要启动 StickyService 并在事件库的服务中运行线程

于 2013-03-18T08:41:20.647 回答
36

简单的 3 线

我发现了一种简单的方法,这是@awardakBrandon Rude 的回答中的评论:

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

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

谢谢,@awardak

于 2019-11-04T22:05:09.633 回答
24

我希望一些代码在后台连续运行。我不想在服务中这样做。有没有其他可能的方法?

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

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

注意:也有可能IntentServiceResultReceiver它一起使用。

于 2013-03-18T08:37:44.123 回答
12

今天我正在寻找这个,布兰登鲁德先生给出了一个很好的答案。不幸的是,AsyncTask现在已弃用. 你仍然可以使用它,但它会给你一个警告,这很烦人。所以另一种方法是Executors像这样使用(in kotlin):


        Executors.newSingleThreadExecutor().execute(Runnable {
            // todo: do your background tasks
            runOnUiThread{
                // update ui if you are in an activity
            }
            /*
            requireActivity().runOnUiThread {
               // update views / ui if you are in a fragment
            }
            */
        })

java它看起来像这样:


        Executors.newSingleThreadExecutor().execute(() -> {
            // todo: background tasks
            runOnUiThread(() -> {
                // todo: update your ui / view in activity
            });

            /*
            requireActivity().runOnUiThread((Runnable) () -> {
                // todo: update your ui / view in Fragment
            });
            */
        });
于 2020-11-24T12:23:50.507 回答
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 示例。

更新:以上是答案不再有效。使用 kotlin 协程进行后台线程。

于 2013-03-18T08:44:00.880 回答
2
class Background implements Runnable {
    private CountDownLatch latch = new CountDownLatch(1);
    private  Handler handler;

    Background() {
        Thread thread = new Thread(this);
        thread.start();
        try {
            latch.await();
        } catch (InterruptedException e) {
           /// e.printStackTrace();
        }
    }

    @Override
    public void run() {
        Looper.prepare();
        handler = new Handler();
        latch.countDown();
        Looper.loop();
    }

    public Handler getHandler() {
        return handler;
    }
}
于 2018-03-03T17:05:25.993 回答
1

如果您需要使用不同的代码预先运行线程,这里是示例:

听众:

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();
于 2019-06-11T09:40:34.697 回答