在调用removeCallbacks()时,在新线程上启动的runnable不会停止

时间:2013-09-30 13:15:39

标签: java android multithreading

我有以下代码。

//This is global for the activity.
Handler handler = new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {   
               //update the UI
    }
};

在我的onResume()中,我启动了一个运行runnable的新线程。

protected void onResume()
{
    super.onResume();

    Thread t = new Thread(runnable);
    t.start();
}

我的runnable如下:

Runnable runnable = new Runnable()
{
    public void run()
    {
                  // some networking stuff 
                  // some db stuff
                  // whatever


        handler.sendEmptyMessage(0);
        handler.postDelayed(new Runnable()
        {
            public void run()
            {
                new Thread(runnable).start();
            }
        }, 30000);
    }
}

我在onPause()中有这个:

protected void onPause()
    {       
        super.onPause();
            handler.removeCallbacks(runnable);
    }

最后我调用了handler.sendEmptyMessage(0);以便调用handleMessage(Message msg)并进行UI更改,然后重复执行任务但是启动一个新的runnable,它会启动一个运行该命令的新线程同样可以运行。

澄清问题:

  1. 我在onResume()中启动一个新线程,这意味着runnable没有在UI线程上运行,但是,处理程序是在UI线程上创建的,并且自然地附加到UI线程。如何完美地改变UI?

  2. 假设是handler.removeCallbacks(runnable),但是,每当我缩小应用程序时,runnable仍然会每30秒继续运行一次。 (这可能是因为它位于新线程上,与创建的Handler无关)。我怎么能让它停下来?

1 个答案:

答案 0 :(得分:1)

public class MainActivity extends Activity {

    public static final int UPDATE = 1;
    public static final int WORK = 2;

    private Handler uiHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case UPDATE:
                // Perform UI updates here
                ....
                // UI Updates done, schedule WORK in 30 seconds:
                this.sendMessageDelayed(this.obtainMessage(WORK), 30000);
                break;
            case WORK:
                new Thread(doWork).start();
                break;

            default:
                super.handleMessage(msg);
            }
        }

    };

private WeakReference<Handler> handlerRef = new WeakReference<Handler>( uiHandler );

    private Runnable doWork = new Runnable() {

        @Override
        public void run() {
            // This will run on a different thread.

            // If UI is still around, tell it to update
            Handler ui = handlerRef.get();
            if( ui != null )
                ui.sendEmptyMessage(MainActivity.UPDATE);
        }
    };  

    @Override
    protected void onPause() {
        uiHandler.removeMessages(WORK);
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Resume UI updates in 500ms, allowing UI to settle
        uiHandler.sendMessageDelayed(uiHandler.obtainMessage(WORK), 500);
    }

    ....
}

此模式在UI线程上使用单个Handler。后台工作在Runnable中完成,ui Handler将发布到新线程,因此避免NetworkOnMainThreadException - 更重要的是 - 无响应的UI。此外,在后台进程完成后30秒安排新的更新,以避免对长时间运行的更新征税。后台线程使用WeakReference到ui处理程序,因此如果在线程工作时Activity被终止,它将不会向其发送UI更新。