关闭飞行模式后,为啥 Android 应用程序会通过 Activity 和 Fragment 生命周期方法

Posted

技术标签:

【中文标题】关闭飞行模式后,为啥 Android 应用程序会通过 Activity 和 Fragment 生命周期方法【英文标题】:Why does an Android app go through the activity and fragment lifecycle methods when airplane mode is turned off关闭飞行模式后,为什么 Android 应用程序会通过 Activity 和 Fragment 生命周期方法 【发布时间】:2021-03-21 23:55:20 【问题描述】:

我正在构建一个 android 应用程序,发生的一件令人惊讶的事情是,当我在应用程序处于前台时关闭飞行模式时它会崩溃。我尝试在活动的各种生命周期方法(onPauseonCreateonResume)和显示活动onCreate 的片段中包含日志。碰巧所有这些回调方法都按以下顺序调用:

显示片段中的onPause

onPause 在 MainActivity

onCreate 在 MainActivity 中

onViewCreated 在 MainActivity 的 onCreate 中显示的片段中

显示片段中的onStart

MainActivity 中的onStart

显示片段中的onResume

由于NullPointerException,应用程序最终在显示的片段中的onPause 中崩溃。

我试图跟踪所有这些回调,它们是因为在显示的片段的onPause 中,有一些状态我保存在 SharedPreferences 中以在片段恢复时恢复它们,显然它们引发了异常。

能否请您帮助我理解为什么在应用程序处于前台时关闭飞行模式时应用程序会经历所有这些生命周期方法,以及防止应用程序在发生这种情况时崩溃的最佳方法?我浏览了几篇关于这个问题的帖子,但没有找到任何答案。

这里是代码

public class MainActivity extends AppCompatActivity

    public static FragmentManager fragmentManager;
    public static final String LOG_TAG = "LOG_TAG";


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        Log.i(LOG_TAG, "Main activity created");
        super.onCreate(savedInstanceState);

        // init airplane mode receiver
        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        BroadcastReceiver receiver = new BroadcastReceiver() 
            @Override
            public void onReceive(Context context, Intent intent) 

                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
                if(isAirplaneModeOn)
                    Log.i(LOG_TAG, "Airplane mode turned on");// handle Airplane Mode on
                 else 
                    Log.i(LOG_TAG, "Airplane mode turned off");
                
            
        ;
        this.registerReceiver(receiver, intentFilter);


        setContentView(R.layout.activity_main);
        fragmentManager = getSupportFragmentManager();
        displayFragment(new MapFragment());
    


    @Override
    protected void onPause() 
        super.onPause();
        Log.i(LOG_TAG, "Main activity paused");
    


    @Override
    protected void onResume() 
        super.onResume();
        Log.i(LOG_TAG, "Main activity resumed");
    


    public void displayFragment(Fragment fragmentActivity)

        // start the transaction
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, fragmentActivity).
                    addToBackStack(fragmentActivity.getClass().getSimpleName()).commit();
    

还有片段

public class MapsFragment extends Fragment implements
        OnMapReadyCallback 


    public MapsFragment() 
        // Required empty public constructor
        super();
    


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_map, container, false);
    


    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
        FrameLayout map_frame = view.findViewById(R.id.map_frame);

        // configure map
        MapView mapFragment = view.findViewById(R.id.map_view);
        mapFragment.onCreate(savedInstanceState);
        mapFragment.onResume();
        mapFragment.getMapAsync(this);
        View mapView = mapFragment.getRootView();
        super.onViewCreated(mapView, savedInstanceState);
    

    @Override
    public void onResume() 
        super.onResume();
        Log.i(LOG_TAG, "MapFragment resumed");
    


    @Override
    public void onPause() 
        super.onPause();
        Log.i(LOG_TAG, "Map fragment paused");
    

    @Override
    public void onMapReady(GoogleMap googleMap) 
        Log.i(LOG_TAG, "onMapReadyCalled");
        MapsInitializer.initialize(getActivity());
    

非常感谢您。

【问题讨论】:

为什么不在崩溃后立即读取 Stacktrace 日志? 99% 的时间都是不言自明的...... 【参考方案1】:

我刚刚意识到,在我的代码中,我在 MainActivity 的 onCreate 中显示了 MapFragment,导致应用崩溃。当应用程序处于前台时关闭飞行模式时,我无法让应用程序不通过生命周期方法。但是在我的 MainActivity 的 onStart 中显示 MapFragment 解决了这个问题。

@Override
    protected void onStart() 
        super.onStart();
        if (getCurrentFragment() == null) 
            displayFragment(new MapFragment(), null, false, true);
        
    

其中 getCurrentFragment() 是我定义的用于返回当前显示的片段的方法。

【讨论】:

以上是关于关闭飞行模式后,为啥 Android 应用程序会通过 Activity 和 Fragment 生命周期方法的主要内容,如果未能解决你的问题,请参考以下文章

为啥飞行模式开启时 CLLocationManager 不会失败?

如何知道广播接收器中飞行模式是打开还是关闭?

如何调用“关闭飞行模式”通知

与 ios 7 的新测试飞行兼容性

电脑飞行模式怎么关闭,飞行模式灰色默认开启,WLAN选项消失。

如何在 Android 上检测飞行模式?