You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Toolbar返回图标双击触发NullPointerException:FragmentActivity.onBackPressed()异常

解决Toolbar返回图标点击两次后崩溃的NullPointerException问题

你的问题核心在于Fragment销毁后,之前设置的Toolbar导航点击监听器仍持有Fragment引用,导致调用getActivity()时返回null,进而触发空指针异常。

问题根源分析

你的ImageDetailFragment在onCreateView中直接给宿主PagesActivity的Toolbar设置了新的NavigationOnClickListener,但当Fragment被弹出栈(第一次点击返回回到PagesActivity),Fragment的生命周期走到onDestroyView,此时Fragment已和Activity解除关联,getActivity()会返回null。但你设置的Toolbar点击监听器并未被移除,第二次点击返回按钮时,触发的还是Fragment里的旧监听器,这时候调用getActivity().onBackPressed()自然会抛出NPE。

另外,PagesActivity本身已经通过onOptionsItemSelected处理了Toolbar返回按钮的逻辑,Fragment重新设置监听器会和Activity的原有逻辑冲突。

解决方案:恢复Toolbar原有监听器

我们需要在Fragment销毁视图时,把Toolbar的导航点击监听器恢复成Activity原来的状态,同时在调用getActivity()前做非空判断。

修改ImageDetailFragment的代码,添加以下逻辑:

package com.example.android.evilsecretgallery; 

import android.graphics.Bitmap; 
import android.os.Build; 
import android.os.Bundle; 
import android.support.annotation.NonNull; 
import android.support.annotation.Nullable; 
import android.support.v4.app.Fragment; 
import android.support.v7.app.AppCompatActivity; 
import android.support.v7.widget.Toolbar; 
import android.transition.TransitionInflater; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import com.bumptech.glide.Glide; 
import com.bumptech.glide.request.target.SimpleTarget; 
import com.bumptech.glide.request.transition.Transition; 
import com.github.chrisbanes.photoview.PhotoView; 

public class ImageDetailFragment extends Fragment { 
    private static final String EXTRA_IMAGE = "image_item"; 
    private static final String EXTRA_TRANSITION_NAME = "transition_name"; 
    // 保存Activity原来的Toolbar导航监听器
    private View.OnClickListener originalToolbarNavListener;

    public ImageDetailFragment() { 
        // Required empty public constructor 
    } 

    public static ImageDetailFragment newInstance(ImageModel image, String transitionName) { 
        ImageDetailFragment fragment = new ImageDetailFragment(); 
        Bundle args = new Bundle(); 
        args.putParcelable(EXTRA_IMAGE, image); 
        args.putString(EXTRA_TRANSITION_NAME, transitionName); 
        fragment.setArguments(args); 
        return fragment; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        postponeEnterTransition(); 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
            setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move)); 
        } 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
        View rootView = inflater.inflate(R.layout.fragment_image_detail, container, false); 
        Toolbar toolbar = getActivity().findViewById(R.id.toolbar); 
        // 保存Activity原来的导航监听器
        originalToolbarNavListener = toolbar.getNavigationOnClickListener();
        
        toolbar.setTitle(" ES "); 
        toolbar.setTitleTextAppearance(getActivity(), R.style.EvilTextAppearance); 
        toolbar.setNavigationOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View view) { 
                // 先判断Activity是否存在,避免NPE
                AppCompatActivity hostActivity = (AppCompatActivity) getActivity();
                if (hostActivity != null) {
                    hostActivity.onBackPressed();
                }
            } 
        }); 
        return rootView; 
    } 

    @Override 
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 
        super.onViewCreated(view, savedInstanceState); 
        final ImageModel image = getArguments().getParcelable(EXTRA_IMAGE); 
        String transitionName = getArguments().getString(EXTRA_TRANSITION_NAME); 
        final PhotoView imageView = view.findViewById(R.id.detail_image); 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
            imageView.setTransitionName(transitionName); 
        } 
        Glide.with(getActivity()) 
             .asBitmap() 
             .load(image.getUrl()) 
             .into(new SimpleTarget<Bitmap>() { 
                 @Override 
                 public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { 
                     startPostponedEnterTransition(); 
                     imageView.setImageBitmap(resource); 
                 } 
             }); 
    } 

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Toolbar toolbar = getActivity().findViewById(R.id.toolbar);
        if (toolbar != null) {
            // 恢复Activity原来的Toolbar导航监听器
            toolbar.setNavigationOnClickListener(originalToolbarNavListener);
        }
    }
}

额外优化建议

  • 如果你使用AndroidX Fragment,可以用requireActivity()代替getActivity(),它会在Activity为null时抛出更明确的IllegalStateException,方便调试,但仍建议在调用前做非空判断。
  • 复杂场景下,尽量避免Fragment直接修改宿主Activity的UI组件逻辑,可以通过接口回调或者ViewModel让Activity统一处理导航逻辑,减少组件耦合。

内容的提问来源于stack exchange,提问作者Simone Atzeni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:14:18