【问题标题】:Why are those objects null when I return to application?当我返回应用程序时,为什么这些对象为空?
【发布时间】:2017-07-20 07:04:05
【问题描述】:

我有一个带有 TabLayout 和几个片段的 MainActivity。创建应用程序后,一切正常,但是,当应用程序在后台运行并返回时,我得到一个空指针异常。我在 Fragments 的 OnCreateView 方法中创建的对象为空。

这是我的 FragmentPagerAdapter 类:

public class SectionsPagerAdapter extends FragmentPagerAdapter {
    private FragmentStrobe fragmentStrobe = null;
    private FragmentFlashLight fragmentFlashLight = null;
    private FragmentDisco fragmentDiscoLight = null;
    private FragmentShaking fragmentShaking = null;
    private FragmentPoliceLights fragmentPoliceLights = null;

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                if(fragmentDiscoLight == null){
                    fragmentDiscoLight = new FragmentDisco();
                }
                return fragmentDiscoLight;
            case 1:
                if(fragmentStrobe == null){
                    fragmentStrobe = new FragmentStrobe();
                }
                return fragmentStrobe;
            case 2:
                if(fragmentFlashLight == null){
                    fragmentFlashLight = new FragmentFlashLight();
                }
                return fragmentFlashLight;
            case 3:
                if(fragmentShaking == null){
                    fragmentShaking = new FragmentShaking();
                }
                return fragmentShaking;
            case 4:
                if(fragmentPoliceLights == null){
                    fragmentPoliceLights = new FragmentPoliceLights();
                }
                return fragmentPoliceLights;
            default:
                return null;
        }
    }

    @Override
    public int getCount() {
        return 5;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return null;
    }
}

在我的 MainActivity 中,片段顶部的按钮很少。单击此按钮时,我正在调用 Fragment 中的方法;

private void initializeButtonStart(){
    buttonStart = (Button) findViewById(R.id.start);

    buttonStart.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            myPreferences.setBoolPreferences(MyPreferences.MY_PREFS_START,
                    !myPreferences.getBoolPreferences(MyPreferences.MY_PREFS_START, MyPreferences.MY_PREFS_START_DEFAULT));

            setIcon();

            ((FragmentInterface) mSectionsPagerAdapter.getItem(tabLayout.getSelectedTabPosition())).onRunPermissionChanged();
        }
    });
}

这是来自一个片段的代码。

public class FragmentDisco extends Fragment implements FragmentInterface {

private static final double IMAGE_RATIO = 1.08158;

private View viewBackground;

private View rootView;

private ImageView imageViewDiscoBall;

private Bitmap bitmap;

private Disco disco;

private MyPreferences myPreferences;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    rootView = inflater.inflate(R.layout.fragment_discolight, container, false);

    disco = new Disco(getContext());

    myPreferences = new MyPreferences(getContext());

    bitmap = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.disco_start);

    initializeView();
    initializeImageView();

    return rootView;
}

private void initializeView(){
    viewBackground = getActivity().findViewById(R.id.viewMain);
}

private void initializeImageView(){
    imageViewDiscoBall = (ImageView) rootView.findViewById(R.id.discoBall);

    imageViewDiscoBall.setImageBitmap(bitmap);

    imageViewDiscoBall.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            imageViewDiscoBall.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            int width = imageViewDiscoBall.getWidth();
            int resultHeight = (int)((float) width * IMAGE_RATIO);

            ViewGroup.LayoutParams layoutParams = imageViewDiscoBall.getLayoutParams();
            layoutParams.height = resultHeight;
            imageViewDiscoBall.setLayoutParams(layoutParams);
        }
    });
}


@Override
public void onResume() {
    super.onResume();
}

@Override
public void onStop() {
    super.onStop();

    stopDisco();
}

@Override
public void onTabSelected() {
    if(myPreferences == null || imageViewDiscoBall == null || viewBackground == null || disco == null){
        return;
    }

    if(myPreferences.getBoolPreferences(MyPreferences.MY_PREFS_START, MyPreferences.MY_PREFS_START_DEFAULT) &&
            (myPreferences.getIntPreferences(MyPreferences.MY_PREFS_CURRENT_FRAGMENT, MyPreferences.MY_PREFS_CURRENT_FRAGMENT_DEFAULT) == MainActivity.FRAGMENT_DISCO)){
        disco.start(viewBackground, imageViewDiscoBall);
    }
}

@Override
public void onTabUnselected() {
    stopDisco();
}

@Override
public void onRunPermissionChanged() {
    if(myPreferences == null || imageViewDiscoBall == null || viewBackground == null || disco == null){
        System.out.println("NULLL !!!!!!");
        return;
    }

    if(myPreferences.getBoolPreferences(MyPreferences.MY_PREFS_START, MyPreferences.MY_PREFS_START_DEFAULT)){
        disco.start(viewBackground, imageViewDiscoBall);
    } else {
        stopDisco();
    }
}

private void stopDisco(){
    if(disco == null || imageViewDiscoBall == null || viewBackground == null){
        return;
    }

    disco.stop();

    viewBackground.setBackgroundColor(Color.TRANSPARENT);
    imageViewDiscoBall.setImageBitmap(bitmap);
}
}

大多数时候,当我从后台返回时,片段中调用的方法会打印“NULL!!!”。我该如何解决这个问题?

【问题讨论】:

  • 什么是myPreferences?你没有展示你是如何声明它的。您也可以使用 debug 来确定什么是 null。
  • 我编辑了这个问题。我现在添加了整个 Fragment 类。

标签: java android android-fragments android-tablayout


【解决方案1】:

Android 正在从内存中清除您的数据以节省内存空间和电力。如果您的设备内存不足,操作系统必须清除后台任务(另请参阅,如果您的后台任务限制在设置 -> 开发人员设置 -> 设备上的后台进程限制。)以正常工作,这可能会发生得更快。使用前台应用程序,确保它获得足够的内存等资源。

所以为了防止这种情况,

  • 仅在需要它们的范围内制作大型对象,例如加载将使用它们的图像对象。
  • 使用 savedInstances 让您的活动恢复到之前的状态。
  • 为了使用 savedInstances,您必须使您的对象可序列化。

【讨论】:

  • 感谢您的回答,那么我必须将 Fragments 保存在 savedInstances 中吗?也许你可以澄清一下?
  • 没有。片段之类的东西必须在适配器的 getFragment 方法中创建。别处无处。这将让您创建内存更轻的应用程序。
  • 这是你应该做的。在识别变量方面取得进展,例如应用程序在哪个部分工作。现在在 'OnPause()' 方法上,您将这些变量保存在 savedInstances 中。在 'OnResume()' 方法上,android 会返回这些变量。因此,恢复活动状态。片段也是如此,保存当前状态并恢复它。例如,您在包含列表视图的第三个选项卡中,并且您在第 11 个项目上做某事。因此,将 3、11 和工作标识符保存在 savedInstances 中,恢复后,您将移至第 3 个选项卡,然后告诉片段转到第 11 个项目,依此类推。
【解决方案2】:

我建议将功能从 onCreate() 转移到 onResume() 方法。 onCreate() 方法仅在活动创建时调用,而 onResume() 总是在您返回活动时调用(被销毁的情况除外)。如需更多信息,请参阅https://developer.android.com/guide/components/activities/activity-lifecycle.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-22
    相关资源
    最近更新 更多