应用程序在AsyncTask屏幕旋转时崩溃

时间:2014-09-29 04:40:17

标签: android android-fragments android-asynctask

我在一个活动的一个片段中使用AsyncTask。

AsyncTask工作正常,但在屏幕旋转时,它会丢失对activity的引用,变量返回NullPointerException,因此应用程序崩溃。

我查看了类似的问题,例如thisthisthisthis,但我不认为使用配置更改黑客是解决方案。

可能导致应用程序崩溃的代码(根据LogCat,NullPointerException位于以下行):

Context context = MyActivity.this.getApplicationContext();

我要在驻留在activity和fragment类之外的另一个函数中传递上下文。

提前谢谢。

更新:我的LogCat

09-29 09:40:53.415: E/AndroidRuntime(21997): FATAL EXCEPTION: AsyncTask #2
09-29 09:40:53.415: E/AndroidRuntime(21997): java.lang.RuntimeException: An error occured while executing doInBackground()
09-29 09:40:53.415: E/AndroidRuntime(21997):    at android.os.AsyncTask$3.done(AsyncTask.java:278)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.lang.Thread.run(Thread.java:856)
09-29 09:40:53.415: E/AndroidRuntime(21997): Caused by: java.lang.NullPointerException
09-29 09:40:53.415: E/AndroidRuntime(21997):    at com.example.CommonClasses.CommonFunctions.readFile(CommonFunctions.java:262)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at com.example.CommonClasses.CommonFunctions.readFileContents(CommonFunctions.java:308)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at com.example.android.AvailabilityFragment$AvailabilityData.doInBackground(AvailabilityFragment.java:160)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at com.example.android.AvailabilityFragment$AvailabilityData.doInBackground(AvailabilityFragment.java:1)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at android.os.AsyncTask$2.call(AsyncTask.java:264)
09-29 09:40:53.415: E/AndroidRuntime(21997):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)

2 个答案:

答案 0 :(得分:0)

试试这种方式

<activity
    android:name=".ActivityName"
    android:configChanges="orientation|screenSize|keyboardHidden"/>

答案 1 :(得分:0)

有很多解决方案。一个简单的方法就是使用所谓的“保留”片段。这是一种在某些Google示例中使用的方法。保留片段没有UI,并且在方向更改时保持不变。这通常被定义为您的活动的静态内部类,如下所示:

public static class RetainFragment extends Fragment {
    private static final String TAG = "RetainFragment";

    public RetainFragment() {}

    public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
        RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
        if (fragment == null) {
            fragment = new RetainFragment();
        }
        return fragment;
    }

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

然后,将您的AsyncTask放入RetainFragment中。调用onPostExecute时,您只需使用片段的getActivity()方法获取附加到的活动。

希望有所帮助,让我知道是否还有一些困惑!

修改 Here是保留片段的Google样本

编辑2:(根据评论)

public class A {

    // This class holds a reference to it's outer A instance. It can be
    // accessed using A.this.
    public class innerClassA {
        //...
    }

    // This class does not hold a reference to it's outer A instance.
    public static class innerClassB {
        //...
    }
}

编辑3:在评论中,我最终还是编写了完整的代码。对于任何感兴趣的人:

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        Button b = (Button) findViewById(R.id.aaa);
        b.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                RetainFragment retainFragment =
                        RetainFragment.findOrCreateRetainFragment(getFragmentManager());
                retainFragment.loadAsync();
            }
        });
    }

    private void handleResponse(String response) {
        // do something with the response...
    }

    public static class RetainFragment extends Fragment {
        private static final String TAG = "RetainFragment";

        public RetainFragment() {
        }

        public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
            RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
            if (fragment == null) {
                fragment = new RetainFragment();
                fm.beginTransaction().add(fragment, TAG).commit();
            }
            return fragment;
        }

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

        private void loadAsync() {
            new AsyncTask<Void, Void, String>() {
                @Override protected String doInBackground(Void... params) {
                    // Do some work...
                    return null;
                }

                @Override protected void onPostExecute(String response) {
                    MyActivity myActivity = (MyActivity)getActivity();
                    if (myActivity != null) {
                        myActivity.handleResponse(response);
                    }
                }
            }.execute();
        }
    }
}