Android - 更改活动时出现多线程问题

时间:2011-03-04 15:59:28

标签: android multithreading android-asynctask

我有一个带操作栏的主菜单。在创建时,我运行一个线程,命中我的服务器以获取当前状态。当完成时,线程调用一个处理程序,该处理程序启动一个循环遍历项目的持续运行的线程,并使用另一个处理程序调用来更改操作栏中的测试。问题是,当我更改视图时,我会得到android.view.WindowLeakedView not attached to window manager

以下是一些示例代码

public class MainMenuActivity extends ProtectedWithActionBarActivity{
    private int STATUS_COUNTER;
    private final int RESULT_STATUS_LOADED = 2000;
    private final int RESULT_SHOW_STATUS = 2001;
    private CurrentStatusModel currentStatus;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.mainmenu);

        ActionBar footerbar = (ActionBar)findViewById(R.id.footerbar);

        footerbar.setTitle("Currently connected to " + PreferencesHelper.getCurrentEnvironment().name());


        STATUS_COUNTER = 0;

        statusLoadThread.start();
    }

    Thread statusLoadThread = new Thread()
    {
        @Override
        public void run()
        {
            //set currentStatus with data from server
        }
    };

    Thread statusDisplayThread = new Thread()
    {
        int sleep = 5000;
        boolean threadDone = false;

        public void done()
        {
            threadDone = true;
        }

        @Override
        public void run()
        {
            while(true)
            {
                //pick message to send to handler
                //increment STATUS_COUNTER or reset to 0 when out of bounds

                try 
                {
                    sleep(sleep);
                } 
                catch (InterruptedException e) 
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    };

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch(msg.what)
        {
            case RESULT_STATUS_LOADED:
                statusDisplayThread.start();
                break;
            case RESULT_SHOW_STATUS:
                ActionBar footerbar = (ActionBar)findViewById(R.id.footerbar);

                String message = ((Object[])msg.obj)[0].toString();
                OnClickListener listener = (OnClickListener)((Object[])msg.obj)[1];

                footerbar.setTitle(message);
                    footerbar.setOnTitleClickListener(listener);

                break;
            case ActivityBase.RESULT_ERROR:

                break;
        }
    }
    };
}

我不确定我所做的事情是不是错了,或者是否有一些显而易见的事情让我失踪了。需要发生的是线程需要在我改变屏幕时停止。我应该在开始下一个活动之前使用Thread.interrupt();吗?

3 个答案:

答案 0 :(得分:1)

AsyncTasc允许您实现doInBackground(),您的线程可以在其中执行任务。这与您从Thread获得的功能类似。

当您覆盖onPreExecute()onPostExecute()这两者都在UI线程上执行时,会发生真正的魔力。这样可以防止您收到有关未附加活动的消息。

修改 - 此answer包含AsyncTask的一个小代码示例,可以帮助您入门。

答案 1 :(得分:0)

您正在尝试在拥有活动已从窗口系统分离后更新UI元素。

如果你使用AsyncTask而不是vanilla线程(不需要处理程序)和cancel()来自Activity.onPause()的后台任务,那么你的生活会变得更加简单。 / p>

答案 2 :(得分:0)

你不能在onPause中设置每个Thread检查的标志吗?如果设置了标志,则线程退出其循环。因此,每当Activity移至后台时,您Thread的每个都将停止。您需要处理重新启动onResume中的线程。您也可以使用AsyncTask方法,但不能保证在调用cancel()方法时实际取消,只有尝试取消任务。