Android 异步任务屏幕旋转时应用程序崩溃

Android 异步任务屏幕旋转时应用程序崩溃,android,android-fragments,android-asynctask,Android,Android Fragments,Android Asynctask,我正在活动的一个片段中使用AsyncTask AsyncTask工作正常,但在屏幕旋转时,它会丢失对活动的引用,变量返回NullPointerException,因此应用程序崩溃 我研究了类似的问题,如、、和,但我不认为使用配置更改黑客是解决方案 可能导致应用程序崩溃的代码(根据LogCat,NullPointerException位于下一行): 我必须在activity and fragment类之外的另一个函数中传递上下文 先谢谢你 更新:我的日志 09-29 09:40:53.415: E

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

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

我研究了类似的问题,如、、和,但我不认为使用配置更改黑客是解决方案

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

我必须在activity and fragment类之外的另一个函数中传递上下文

先谢谢你

更新:我的日志

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)
这样试试

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

有很多解决方案。一个简单的方法是使用所谓的“保留”片段。这是一种在一些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()
方法来获取它所附加到的活动

希望对你有所帮助,如果还有一些困惑,请告诉我

编辑:是保留片段的谷歌示例

编辑2:(根据评论)

编辑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();
        }
    }
}
公共类MyActivity扩展活动{
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
按钮b=(按钮)findViewById(R.id.aaa);
b、 setOnClickListener(新视图。OnClickListener(){
@覆盖公共void onClick(视图v){
补缺补缺补缺=
findOrCreateRetainFragment(getFragmentManager());
retainFragment.loadAsync();
}
});
}
私有void handleResponse(字符串响应){
//对回应做点什么。。。
}
公共静态类保留扩展片段{
私有静态最终字符串TAG=“RetainFragment”;
公共再收费(){
}
公共静态重新整理findOrCreateRetainFragment(FragmentManager fm){
RetainFragment=(RetainFragment)fm.findFragmentByTag(TAG);
if(片段==null){
fragment=新的RetainFragment();
fm.beginTransaction().add(fragment,TAG.commit();
}
返回片段;
}
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstance(真);
}
私有void loadAsync(){
新建异步任务(){
@覆盖受保护字符串doInBackground(无效…参数){
//做一些工作。。。
返回null;
}
@重写受保护的void onPostExecute(字符串响应){
MyActivity MyActivity=(MyActivity)getActivity();
如果(myActivity!=null){
myActivity.HandlerResponse(响应);
}
}
}.execute();
}
}
}

Hey在执行任何操作之前,您必须检查其是否为null。发布logcat跟踪please@Panther它总是空的,因为活动在屏幕旋转后被破坏。这会不会导致AsyncTask在屏幕旋转后不运行?而不是
MyActivity.this.getApplicationContext()使用
Context.getApplicationContext()
Activity.getApplication()
此处出现的空指针
CommonFunctions.readFile(CommonFunctions.java:262)
试着找出它是什么:-/我宁愿不要,因为Android开发者指南不推荐它:我知道Android不推荐它,但它并不否认使用它。如果在运行时没有支持多种语言和键盘stiffs,您可以使用它。我在许多项目中都使用过它,但由于这种方法,没有发现这么大的问题。我宁愿在考虑使用它之前先探索其他不太老套的选项。谢谢你的回复。这看起来很优雅。问题:我必须使用静态类才能使这个解决方案工作吗?如果它不是静态的,您将有内存泄漏。使片段类静态不会导致将来出现一些不可预见的异常吗?我不知道,我只是把它扔出去。因为这不是我应用程序中的唯一片段。还有许多其他的,它们是通过创建片段的对象并将其传递给
fragmentManager
来调用的。其中一些片段是在同一个活动上实例化的。将类设为静态意味着它不会保留对其包含的类(即本例中的活动)的引用。这不是问题。如果它不是静态的,这将是一个问题,因为非静态内部类保留对其包含类的隐式强引用,因此即使在系统使用它之后,它也会持久化活动实例(导致内存泄漏)。
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 {
        //...
    }
}
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();
        }
    }
}