Android Fragment 生命周期问题(onActivityResult 上的 NullPointerException) [英] Android Fragment lifecycle issue (NullPointerException on onActivityResult)

查看:23
本文介绍了Android Fragment 生命周期问题(onActivityResult 上的 NullPointerException)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到一个问题,我找不到任何解释.我有一个使用 TabManager 显示片段的 FragmentActivity,如下所示:

I get an issue which for I cannot find any explanation. I have a FragmentActivity that displays fragments using a TabManager, as follows :

public class WorkOrderFormTabFragmentActivity extends FragmentActivity {
TabHost mTabHost;
TabManager mTabManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.work_order_form_tab_new);
    mTabHost = (TabHost)findViewById(android.R.id.tabhost);
    mTabHost.setup();

    mTabManager = new TabManager(this, mTabHost, R.id.realtabcontent);

    mTabManager.addTab(mTabHost.newTabSpec("form").setIndicator("Form"),
            WorkOrderFormFragment.class, null);
    mTabManager.addTab(mTabHost.newTabSpec("pictures").setIndicator("Pictures"),
            PictureListFragment.class, null);

    if (savedInstanceState != null) {
        mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("tab", mTabHost.getCurrentTabTag());
}

public static class TabManager implements TabHost.OnTabChangeListener {
    private final FragmentActivity mActivity;
    private final TabHost mTabHost;
    private final int mContainerId;
    private final HashMap<String, TabInfo> mTabs = new HashMap<String, TabInfo>();
    TabInfo mLastTab;

    static final class TabInfo {
        private final String tag;
        private final Class<?> clss;
        private final Bundle args;
        private Fragment fragment;

        TabInfo(String _tag, Class<?> _class, Bundle _args) {
            tag = _tag;
            clss = _class;
            args = _args;
        }
    }

    static class DummyTabFactory implements TabHost.TabContentFactory {
        private final Context mContext;

        public DummyTabFactory(Context context) {
            mContext = context;
        }

        @Override
        public View createTabContent(String tag) {
            View v = new View(mContext);
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }
    }

    public TabManager(FragmentActivity activity, TabHost tabHost, int containerId) {
        mActivity = activity;
        mTabHost = tabHost;
        mContainerId = containerId;
        mTabHost.setOnTabChangedListener(this);
    }

    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
        tabSpec.setContent(new DummyTabFactory(mActivity));
        String tag = tabSpec.getTag();

        TabInfo info = new TabInfo(tag, clss, args);

        info.fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);
        if (info.fragment != null && !info.fragment.isDetached()) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            ft.detach(info.fragment);
            ft.commit();
        }

        mTabs.put(tag, info);
        mTabHost.addTab(tabSpec);
    }

    @Override
    public void onTabChanged(String tabId) {
        TabInfo newTab = mTabs.get(tabId);
        if (mLastTab != newTab) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                    //ft.detach(mLastTab.fragment);
                    ft.hide(mLastTab.fragment);
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    newTab.fragment = Fragment.instantiate(mActivity,
                            newTab.clss.getName(), newTab.args);
                    ft.add(mContainerId, newTab.fragment, newTab.tag);
                } else {
                    //ft.attach(newTab.fragment);
                    ft.show(newTab.fragment);
                }
            }

            mLastTab = newTab;
            ft.commit();
            mActivity.getSupportFragmentManager().executePendingTransactions();
        }
    }
}

在此 FragmentActivity 的第二个选项卡中,用户可以管理图片列表并使用相机添加更多图片.

In the second tab of this FragmentActivity user can manage a list of pictures and use the camera to add more pictures.

片段代码:

public class PictureListFragment extends Fragment {

static final int TAKE_PICTURE_ACTIVITY = 1;
static final int EDIT_PICTURE_ACTIVITY = 2;

FormPictureListAdapter lvAdapter;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewgrp,
    Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View cont = inflater.inflate(R.layout.form_picture_list, viewgrp, false);

    LinearLayout container = (LinearLayout)cont.findViewById(R.id.formPictureListLayout);
    try{

        final Context context = getActivity();
        ListView ls2 = new ListView(context);
        // clear previous results in the LV
        ls2.setAdapter(null);
        // populate
        ArrayList<MFPicture> pictures = new ArrayList<MFPicture>();
        //pictures.add(0, new MFPicture());
        pictures.addAll(((MFApplication)getActivity().getApplication()).getCurrentForm().getPictures());

        lvAdapter = new FormPictureListAdapter(context, pictures);
        ls2.setAdapter(lvAdapter);
        LinearLayout.LayoutParams Params = new LinearLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT, 0, 1f);
        ls2.setLayoutParams(Params);
        ls2.setOnItemClickListener(new OnItemClickListener() {
          public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
              final MFPicture picture = ((MFPictureView)view).getPicture();
              final int idx = position;
              DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
                  @Override
                  public void onClick(DialogInterface dialog, int which) {
                      switch (which){
                      case DialogInterface.BUTTON_POSITIVE:
                          //Edit picture
                          EditPictureActivity.setPicture(picture);
                          Intent configurationOpen = new Intent(getActivity(), EditPictureActivity.class);
                          startActivityForResult(configurationOpen, EDIT_PICTURE_ACTIVITY);
                          break;

                      case DialogInterface.BUTTON_NEGATIVE:
                          //Delete picture
                          ((MFApplication)getActivity().getApplication()).getCurrentForm().getPictures().remove(idx);  
                          MFUtils.deleteFile(picture.getPath());
                          lvAdapter.updatePictureList(((MFApplication)getActivity().getApplication()).getCurrentForm().getPictures());
                          lvAdapter.notifyDataSetChanged();
                          break;
                      }
                  }
              };
              AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
              builder.setMessage(getResources().getString(R.string.wo_bem_regie_list_el_action)).setPositiveButton(getResources().getString(R.string.wo_bem_regie_list_el_edit), dialogClickListener)
                    .setNegativeButton(getResources().getString(R.string.wo_bem_regie_list_el_delete), dialogClickListener).show();
          }
         });
        container.addView(ls2);

        LayoutInflater layoutInflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view=layoutInflater.inflate(R.layout.add_btn_bottom,container);
        view.setBackgroundResource(R.drawable.list_selector_even);
        TextView text = (TextView)view.findViewById(R.id.title);
        text.setText(getResources().getString(R.string.wo_picturelist_add));
        view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v){
                v.setBackgroundResource(R.drawable.list_selector_even);
                String pictureFile = ((MFApplication)getActivity().getApplication()).getNextPictureFile();
                String picPath = MFUtils.MF_STORAGE_PATH+"/"+pictureFile;
                Log.e("FormPictureListActivity", "PicturePath : "+picPath);
                //setBackgroundResource(android.R.drawable.list_selector_background);
                try {
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(picPath)));
                    startActivityForResult(intent, TAKE_PICTURE_ACTIVITY);
                } catch (ActivityNotFoundException e) {
                    Log.e("FormPictureListActivity", "Call failed", e);
                }
            }
      });
    }
    catch(Exception e){
      e.printStackTrace();
      Log.e("FormPictureListActivity", "Error:", e);
    }

    return cont;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    //super.onActivityResult(requestCode, resultCode, data);
    String pictureFile = ((MFApplication)getActivity().getApplication()).getPictureFile();
    Log.d("FormPictureListActivity", "ActivityResult:"+resultCode);
    Log.d("FormPictureListActivity", "ActivityResult-picFile:"+pictureFile);
    if (requestCode == TAKE_PICTURE_ACTIVITY){
        if(resultCode == getActivity().RESULT_OK){
            Log.d("FormPictureListActivity", "ActivityResult:OK");
            MFPicture picture = new MFPicture(MFPicture.TYPE_PICTURE, MFUtils.MF_STORAGE_PATH+"/"+pictureFile);
            ((MFApplication)getActivity().getApplication()).getCurrentForm().getPictures().add(picture);
            lvAdapter.updatePictureList(((MFApplication)getActivity().getApplication()).getCurrentForm().getPictures());
            lvAdapter.notifyDataSetChanged();
            EditPictureActivity.setPicture(picture);
            Intent configurationOpen = new Intent(getActivity(), EditPictureActivity.class);
            startActivityForResult(configurationOpen, EDIT_PICTURE_ACTIVITY);
        }
    }
    else if (requestCode == EDIT_PICTURE_ACTIVITY){
        EditPictureActivity.getPicture().setComment(EditPictureActivity.getPicture().getCommentUIValue());
        lvAdapter.updatePictureList(((MFApplication)getActivity().getApplication()).getCurrentForm().getPictures());
        lvAdapter.notifyDataSetChanged();
    }
}
}

在我的测试设备(Nexus 5、Galaxy Nexus、Galaxy Mini 2)上一切正常,但我不时收到来自我无法访问的其他设备(主要是运行 Android 4.0.4 的设备)的错误:

Everything works well on my test devices (Nexus 5, Galaxy Nexus, Galaxy Mini 2) but I receive from time to time errors from other devices I have no access to (mainly devices running Android 4.0.4) :

java.lang.RuntimeException: Unable to resume activity 

{com.mf.mobile.android/com.mf.mobile.android.WorkOrderFormTabFragmentActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=131073, result=-1, data=null} to activity {com.mf.mobile.android/com.mf.mobile.android.WorkOrderFormTabFragmentActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2616)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2644)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2130)
at android.app.ActivityThread.access$600(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1248)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4645)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:809)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:576)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=131073, result=-1, data=null} to activity {com.mf.mobile.android/com.mf.mobile.android.WorkOrderFormTabFragmentActivity}: java.lang.NullPointerException
at android.app.ActivityThread.deliverResults(ActivityThread.java:3156)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2599)
... 12 more
Caused by: java.lang.NullPointerException
at com.timewise.mobile.android.fragments.PictureListFragment.onActivityResult(PictureListFragment.java:138)
at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:166)
at android.app.Activity.dispatchActivityResult(Activity.java:4662)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3152)
... 13 more

NPE 出现在这行代码中:lvAdapter.updatePictureList(((MframeApplication)getActivity().getApplication()).getCurrentForm().getPictures());

The NPE appears on this line of code : lvAdapter.updatePictureList(((MframeApplication)getActivity().getApplication()).getCurrentForm().getPictures());

这表示此时lvAdapter变量为空.但是这个变量应该是在 Fragment 的 onCreateView 中设置的...这让我觉得,在某些时候 Fragment 可能已经在没有调用 onCreateView 的情况下重新创建了.

This means that at this time lvAdapter variable is null. But this variable should have been set in onCreateView of Fragment... Which makes me think that, at some point Fragment may have been recreated without calling onCreateView.

我找不到有关此问题的任何解释.你能帮我解决这个问题吗?

I cannot find any explanation about this issue. Can you help me on this one?

非常感谢

推荐答案

好吧,我认为如果用户打开您的应用程序然后点击主页按钮,然后点击显示正在运行的应用程序按钮(那个位于主页按钮的右侧)或在某些手机上按住主页按钮并选择您的应用返回到它.然后,如果您查看生命周期,它将调用 onResume(这是上面堆栈跟踪中的内容),而不会再次调用 onCreateView.

Ok, I think this can happen if the user has your app open and then hits the home button, then either hits the show running applications button (the one that is to the right of the home button) or holds down the home button on some phones and selects your app to go back to it. Then, if you look at the lifecycle it will call onResume (which is what is in the stack trace above) without calling onCreateView again.

片段生命周期

现在,您应该能够通过进入 Nexus 5 上的开发人员"选项并选择不保留活动"来模拟这种情况以查看其发生情况.然后打开您的应用程序,转到该片段点击主页按钮,然后点击正在运行的应用程序按钮并选择您的应用程序,我认为它会显示该异常.

Now, you should be able to mimic this to see it happening by going into the Developer options on your Nexus 5, and selecting Don't keep activities. Then open your app, go to that fragment hit the home button, then the running apps button and select your app and I think it will show you that exception.

这篇关于Android Fragment 生命周期问题(onActivityResult 上的 NullPointerException)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆