片段在网络时失去活动(android)

时间:2017-09-28 20:37:32

标签: android android-fragments android-lifecycle

我从Fragments启动大部分网络调用,然后使用回调告诉Fragment网络任务是否成功,并相应地更新ui。

在罕见的场合(.25%的会话)中,由于getActivity()在我的回调中的代码运行时返回null,我的程序因空指针异常而崩溃。我知道我可以对getActivity()使用空检查来防止这种情况发生,但是处理这个问题的最佳做法是什么?

空检查似乎只是一个防撞工具,因为程序仍然需要来自网络任务的数据。

代码如下所示:

private void queryServer() {
    // networking task should query server for user id, if successful store it 
    // in user preferences to be accessed by fragment in callback
    new networkingTask(new VolleyCallback() {
        @Override
        public void onSuccess() {
            // code below needs null check on getActivity - but what else?
            mUserId = new UserPreferences(getActivity()).getUserId();
        }

        @Override
        public void onFail() {
            // booooo
        }
    });
}

1 个答案:

答案 0 :(得分:1)

正如我在上面的评论中所述,可能发生的事情是系统正在停止或销毁活动/碎片对。这将由于各种原因而发生,例如屏幕方向改变。因为您的处理程序是片段对象上的方法,所以在调用返回时您正在使用“死”片段。有几种模式可以解决这个问题。简而言之,您需要让您的处理程序了解当前片段,并且您可以通过使用生命周期方法来实现此目的。

以下是您可以使用的模式示例。我试图尽量减少这个例子。

import android.app.Activity;
import android.app.Fragment;

public class MyFragment extends Fragment {

    // This is static so that it will not go out of scope when the original
    // fragment is destroy.  This allows it to be access from all MyFragment
    // instances.
    static MyResponseProcessor processor = new MyResponseProcessor();

    // This will be the class that handles your network call.  
    public static class MyResponseProcessor {

        // This instance variable is alway a reference to the currently displayed fragment.
        private Fragment activeFragement;

        public void setActiveFragement(Fragment activeFragement) {
            this.activeFragement = activeFragement;
        }

        // This method, which is for demonstration purposes, shows how you would handle a network response.
        public void handleResponse(SomeResponseObject) {
            if (activeFragement != null) {
                // Now you can get the activity
                Activity activity = activeFragement.getActivity();
            } else {
                // Yes it is possible that there is no active fragment.  
                // If the user has stayed on the same screen, then the
                // fragment of interest will likely be re-created, and 
                // this window of time with no fragment will be brief.
                //
                // Note that this null-check is very different than the 
                // null-check you describe.  In your case the reference is
                // guaranteed to be null forever.  In this case, the reference
                // will eventually become non-null.
            }
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        // At this point in the fragment lifecycle, the fragment is both running and is attached to an Activity.
        // Thus "getActivity" calls are safe from this point onward.
        processor.setActiveFragement(this);
    }

    @Override
    public void onStop() {
        super.onStop();
        // At this point in the fragment lifecycle, the fragment has been stopped and is about to lose its connection to the activity.
        // So after this point, calls to "getActivity" are probably not safe.
        // DISCLAIMER - I have not tested this.  You might want to do this in a
        // different method such as "onDestroyView()"
        processor.setActiveFragement(null);
    }
}