runOnUiThread在旋转屏幕时杀死App

时间:2014-06-07 09:37:14

标签: android multithreading android-asynctask autorotate activity-lifecycle

我想我知道为什么会这样。

当旋转屏幕时,Activity被销毁并重新创建,runOnUiThread()方法引用旧的(已破坏的)Activity,它不再有效,因此android会抛出runtimeexception

为了证明这一点,我有这段代码:

@ContentView(R.layout.activity_start)
public class StartActivity extends RoboSherlockFragmentActivity {

    @Inject
    private EventManager eventManager;

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

        if (savedInstanceState == null) {
            Fragment newFragment = new WelcomeFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.fragment_container, newFragment).commit();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        //Do some short initialization here like read shared prefs
                        //and then decide for example whether to login or skip the login

                        //If the rotation happens while sleeping the app will certainly crash
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                addFragmentToStack();
                            }
                        });
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            }).start();
        }
    }

    void addFragmentToStack() {
        Fragment newFragment = new LoginOrRegisterFragment();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.fragment_container, newFragment);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.commit();
    }
}

我是否必须使用asynctask这样的简单任务?如果是这样我怎么处理轮换呢?因为回调引用也会出错。

3 个答案:

答案 0 :(得分:1)

try this

new Handler(getMainLooper()).postDelayed(new Runnable(){

             if(!isFinishing()){
                  addFragmentToStack();
               }
          },200);

代替你的线程代码

当活动处于被摧毁的过程中时,会调用

isFinishing()

似乎你所要做的就是在200毫秒过后执行任务。 没有必要为此打开一个新线程,处理程序将执行 如果您想确保代码将在主线程上执行,请更加友好 你创建了一个调用主循环器的处理程序 Handler(getMainLooper())它将使此处理程序在主线程上执行其任务

答案 1 :(得分:0)

AsyncTask会产生同样的崩溃。您可以简单地覆盖onPause()并找到一种方法来通知线程即将销毁Activity。就像检查变量的空值一样。

public void run() {
       if(someVariable != null)
           addFragmentToStack();
}

或者您可以使用回调片段(不带视图)来跟踪配置更改。这个article是一个很好的开始。我更喜欢这种方法,因为它是一种非常干净的方法。

答案 2 :(得分:0)

我遇到了类似的问题并通过使用保留片段解决了这个问题,我在每个OnCreate上存储对Activity的引用,例如retainFragment.activity = this; 。在runOnUiThread中,我检查保留的引用是否是当前的Activity,例如if(retainFragment.activity == MainActivity.this)..