【问题标题】:Android: Create a background thread that runs periodically and does UI tasks?Android:创建一个定期运行并执行 UI 任务的后台线程?
【发布时间】:2015-10-09 15:04:27
【问题描述】:

好的,所以我知道如何执行后台任务,我知道如何执行周期性任务(使用 postdelayed 和 runnable 句柄),我也知道如何从后台线程(通过处理程序)执行 UI 任务,但我不是能够执行在 UI 线程上执行某些操作的周期性后台任务。

我每分钟都在尝试执行一些后台任务,我必须在其中进行网络调用。通话结束后,根据输出我必须更新 UI。我试图做这样的事情

private void DoTask() {
        Thread thread = new Thread() {
            public void run() {
                Looper.prepare();
                final Handler handler = new Handler();
                handler.post(netRunnable);
                Looper.loop();
            }
        };
        thread.start();
}

Runnable netRunnable = new Runnable() {
    @Override
    public void run() {
        handler.getLooper().prepare();
        final Handler handler1 = new Handler(Looper.getMainLooper());
        if ( do background work and check result){
            handler1.post(new Runnable() {
                @Override
                public void run() {
                    //Do UI Task
                }
            });
        }
        handler.getLooper().loop();
        handler.postDelayed(netRunnable, 60000);
    }
}

我了解我的实现可能存在一些基本缺陷,但我不知道如何正确执行此任务。现在它给出了Only one Looper may be created per thread的错误。我明白了它想说的话。但是任何人都可以建议以正确的方式执行此操作。

【问题讨论】:

标签: android multithreading android-handler


【解决方案1】:

您可以使用异步任务。这些是为它设计的:

http://developer.android.com/reference/android/os/AsyncTask.html

它允许你在后台执行一个网络调用,然后当你得到结果时,在 UI 线程上执行一个动作

声明:

 private class MyTask extends AsyncTask<Input, Void, Output> {
 protected Output doInBackground(Input... inputs) {
       // do something on the network
       return myOutput;// use this to transmit your result
 }

 protected void onPostExecute(Output result) {
     // do something on UI thread with the result
 }

}

如果你想重复它,只需创建一个 runnable 来启动它,并在每次调用后安排下一个:

MyTask myTask;
Handler handler = new Handler();

    Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                MyTask myTask = new MyTask();
                myTask.execute(myArg);
                handler.postDelayed(netRunnable, 60000); // schedule next call
            }
        }

第一次启动它:

handler.postDelayed(myRunnable, 60000);

或者,如果您想立即启动它:

handler.post(myRunnable);

当您的活动被销毁时,不要忘记取消任务:

myTask.cancel(true);

【讨论】:

  • 如果在 asyncTask 运行时旋转手机会怎样?
  • 取决于是否触发了配置更改事件。如果是这样,则该活动被销毁并且需要取消 AsyncTask。如果没有配置变化,activity不会被销毁,所以我认为是可以的。
  • 如果我看this,我认为任务不会那么容易取消。您也可能会丢失对有效活动的引用。取消网络任务也可能不是最好的主意。
  • 我不认为这就是链接的真正含义。这是否真的会取消任何东西取决于你在做什么。您仍然可以检查任务是否已被取消。此外,如果您愿意,网络任务可以自行继续。
  • 我的意思是:您不能简单地调用myTask.cancel(true) 并且任务会自动停止。您必须在任务的 doInBackground 中处理这种情况。而且因为您可能会丢失对 Activity 的引用,所以您还必须检查它。在使用 AsyncTasks 时,您应该注意一些要点。
【解决方案2】:

也许你会更好,创建一个单独的(Intent)Service 并使用 postDelayed 定期调用它。在您的 Activity 中创建一个 BroadcastReceiver 并在那里处理 UI 更改。

处理来自其他线程的 UI 更改的另一个提示:这是不可能的。因此,您需要调用 runOnUiThread。 Here is how to use it

【讨论】:

  • Intent 服务是一种选择,但我不想使用它有两个原因。首先,我不需要在应用程序处于后台时执行任务,这是使用 IntentService 的主要原因。其次,我的需求是定期自我运行的东西,我认为它可以以更简单的方式完成。无论如何感谢您的回复。
【解决方案3】:

如果活动频繁切换,为什么不倒转职责。您可以创建一个执行周期性网络任务的服务。

那么, - 要么您的活动定期调用此服务以获取价值。 - 或者您使用侦听器系统:您创建一个接口,您的活动必须实现该接口才能从任务完成中获得通知

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-20
    • 1970-01-01
    • 2022-11-19
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-26
    相关资源
    最近更新 更多