Fragment onCreateView 和 onActivityCreated 调用两次

2023-11-22

我正在使用 Android 4.0 ICS 和片段开发一个应用程序。

请考虑 ICS 4.0.3(API 级别 15)API 演示示例应用程序中的修改示例:

public class FragmentTabs extends Activity {

private static final String TAG = FragmentTabs.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final ActionBar bar = getActionBar();
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

    bar.addTab(bar.newTab()
            .setText("Simple")
            .setTabListener(new TabListener<SimpleFragment>(
                    this, "mysimple", SimpleFragment.class)));

    if (savedInstanceState != null) {
        bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
        Log.d(TAG, "FragmentTabs.onCreate tab: " + savedInstanceState.getInt("tab"));
        Log.d(TAG, "FragmentTabs.onCreate number: " + savedInstanceState.getInt("number"));
    }

}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}

public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
    private final Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;
    private final Bundle mArgs;
    private Fragment mFragment;

    public TabListener(Activity activity, String tag, Class<T> clz) {
        this(activity, tag, clz, null);
    }

    public TabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
        mArgs = args;

        // Check to see if we already have a fragment for this tab, probably
        // from a previously saved state.  If so, deactivate it, because our
        // initial state is that a tab isn't shown.
        mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
        if (mFragment != null && !mFragment.isDetached()) {
            Log.d(TAG, "constructor: detaching fragment " + mTag);
            FragmentTransaction ft = mActivity.getFragmentManager().beginTransaction();
            ft.detach(mFragment);
            ft.commit();
        }
    }

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if (mFragment == null) {
            mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
            Log.d(TAG, "onTabSelected adding fragment " + mTag);
            ft.add(android.R.id.content, mFragment, mTag);
        } else {
            Log.d(TAG, "onTabSelected attaching fragment " + mTag);
            ft.attach(mFragment);
        }
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        if (mFragment != null) {
            Log.d(TAG, "onTabUnselected detaching fragment " + mTag);
            ft.detach(mFragment);
        }
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT).show();
    }
}

public static class SimpleFragment extends Fragment {
    TextView textView;
    int mNum;

    /**
     * When creating, retrieve this instance's number from its arguments.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(FragmentTabs.TAG, "onCreate " + (savedInstanceState != null ? ("state " + savedInstanceState.getInt("number")) : "no state"));
        if(savedInstanceState != null) {
            mNum = savedInstanceState.getInt("number");
        } else {
            mNum = 25;
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        Log.d(TAG, "onActivityCreated");
        if(savedInstanceState != null) {
            Log.d(TAG, "saved variable number: " + savedInstanceState.getInt("number"));
        }
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        Log.d(TAG, "onSaveInstanceState saving: " + mNum);
        outState.putInt("number", mNum);
        super.onSaveInstanceState(outState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(FragmentTabs.TAG, "onCreateView " + (savedInstanceState != null ? ("state: " + savedInstanceState.getInt("number")) : "no state"));
        textView = new TextView(getActivity());
        textView.setText("Hello world: " + mNum);
        textView.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
        return textView;
    }
}

}

以下是运行此示例然后旋转手机检索到的输出:

06-11 11:31:42.559: D/FragmentTabs(10726): onTabSelected adding fragment mysimple
06-11 11:31:42.559: D/FragmentTabs(10726): onCreate no state
06-11 11:31:42.559: D/FragmentTabs(10726): onCreateView no state
06-11 11:31:42.567: D/FragmentTabs(10726): onActivityCreated
06-11 11:31:45.286: D/FragmentTabs(10726): onSaveInstanceState saving: 25
06-11 11:31:45.325: D/FragmentTabs(10726): onCreate state 25
06-11 11:31:45.340: D/FragmentTabs(10726): constructor: detaching fragment mysimple
06-11 11:31:45.340: D/FragmentTabs(10726): onTabSelected attaching fragment mysimple
06-11 11:31:45.348: D/FragmentTabs(10726): FragmentTabs.onCreate tab: 0
06-11 11:31:45.348: D/FragmentTabs(10726): FragmentTabs.onCreate number: 0
06-11 11:31:45.348: D/FragmentTabs(10726): onCreateView state: 25
06-11 11:31:45.348: D/FragmentTabs(10726): onActivityCreated
06-11 11:31:45.348: D/FragmentTabs(10726): saved variable number: 25
06-11 11:31:45.348: D/FragmentTabs(10726): onCreateView no state
06-11 11:31:45.348: D/FragmentTabs(10726): onActivityCreated

我的问题是,为什么 onCreateView 和 onActivityCreated 被调用两次?第一次使用具有已保存状态的 Bundle,第二次使用 null savingInstanceState?

这会导致在旋转时保持片段状态出现问题。


我也对此摸不着头脑有一段时间了,由于戴夫的解释有点难以理解,我将发布我的(显然有效的)代码:

private class TabListener<T extends Fragment> implements ActionBar.TabListener {
    private Fragment mFragment;
    private Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    public TabListener(Activity activity, String tag, Class<T> clz) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
        mFragment=mActivity.getFragmentManager().findFragmentByTag(mTag);
    }

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if (mFragment == null) {
            mFragment = Fragment.instantiate(mActivity, mClass.getName());
            ft.replace(android.R.id.content, mFragment, mTag);
        } else {
            if (mFragment.isDetached()) {
                ft.attach(mFragment);
            }
        }
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        if (mFragment != null) {
            ft.detach(mFragment);
        }
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }
}

正如您所看到的,除了不在构造函数中分离并使用替换而不是添加.

经过多次头痛和反复试验后,我发现在构造函数中找到片段似乎使双重 onCreateView 问题神奇地消失了(我假设当通过 ActionBar.setSelectedNavigationItem() 路径调用时,onTabSelected 的结果为 null保存/恢复状态)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Fragment onCreateView 和 onActivityCreated 调用两次 的相关文章

  • 如何在 Android / Java 中获取图像的分辨率

    如何在 Android 中找到任何图像的分辨率 获取存储在磁盘中的图像大小的有效方法 例如获取用户选择上传的图像文件的大小 是使用BitmapFactory Options并设置inJustDecodeBounds为真 这样做你就会获取图像
  • TypedArray 的 getResourceId 方法

    我正在阅读有关的文档获取资源Id https developer android com reference android content res TypedArray html getResourceId int 20int 方法 它说
  • Android 中用虚拟键盘捕捉按键按下的情况?

    使用物理键盘 您可以使用按键监听器 http developer android com reference android text method KeyListener html 就像是 myEditText setOnKeyListe
  • 对话框上的 EditText 不返回任何文本

    我太累了 找不到错误 我没有发现任何错误 但我没有从 editText 收到任何文本 请看下面的代码 活动密码 xml
  • GridView 中多次调用 getView()

    我的 Activity 由包含 40 多个元素的 GridView 组成 开始活动后 用户最多可以看到 15 个项目 3 行 每行 5 个项目 我在 getView 正文中编写传递给获取 View 的 LogCat 编号 Log i get
  • 将正确的上下文传递给 greendao 的 OpenHelper 构造函数

    如果我理解正确的话 在使用数据库时 我必须执行以下操作 DaoMaster OpenHelper helper new DaoMaster OpenHelper this test db null Override public void
  • ProGuard 无法与 Windows 中使用的 Joda Time 一起编译

    实际上 这是一个答案 而不是一个问题 我确实在 Windows 上花了很多时间 使用 JodaTime 并使用 ProGuard 将其包含在我的 Android 项目中 混淆器配置 libraryjars C Users Reto Docu
  • 使用 RecyclerView 适配器在运行时更改布局屏幕

    我有两个布局文件 如下所示 如果列表中存在数据 则我显示此布局 当列表为空时 我会显示此布局 现在我想在运行时更改布局 当用户从列表中删除最后一项时 我想将布局更改为第二张图片中显示的 空购物车布局 In getItemCount Recy
  • 如何从一个代码库创建多个 Android 应用

    我有一个 Android 代码库 它使用带有设置的 API 来获取多个应用程序的不同数据 所有应用程序都使用相同的代码库 但进行一两个设计调整 那么如何重用主代码库而不必每次都复制整个 Android 项目呢 iPhone 在同一个项目中使
  • Android 应用被 Google Play 拒绝

    我最近向 Google Play 商店提交了一个 Android 应用程序 但收到一条消息说我的应用程序已被拒绝 我不确定问题是什么 也找不到确切的解决方案 拒绝原因 违反了禁止行为条款 内容政策 经过定期审核后 我们确定您的应用程序支持
  • Firestore - RecycleView - 图像持有者

    我不知道如何编写图像的支架 我已经设置了 2 个文本 但我不知道图像的支架应该是什么样子 你能帮我告诉我图像的文字应该是什么样子才能正确显示吗 holder artistImage setImageResource model getArt
  • Renderscript 示例构建错误

    所以我想尝试使用 RenderScript 的示例 并在 Eclipse 中导入了 HelloWorld 但它给了我这样的错误 2011 10 25 13 10 48 HelloWorld home mileoresko workspace
  • 如何以编程方式断开拨出呼叫

    我使用以下代码以编程方式断开呼叫 但它不起作用 private void callDisconnect try TelephonyManager manager TelephonyManager this getSystemService
  • 如何在android中设置多个闹钟,在这种情况下最后一个闹钟会覆盖以前的闹钟

    我正在开发一个Android应用程序 用户可以在其中设置提醒时间 但我在以下代码中遇到一个问题 即最后一个警报会覆盖之前的所有警报 MainActivity java public void setreminders DatabaseHan
  • 如何持续更新MPAndroidChart中的Y轴值

    我希望 LineChart 中的轴能够实时调整其最大值和最小值 当新数据的 Y 值增加 正值和负值 时 像 ResetAxisMaxValue 和 ResetAxisMinValue 这样的函数可以很好地工作 但是 一旦信号再次变低 Y 值
  • Android Studio - 值必须 ≥ 0

    我在 Android Studio 中收到与光标有关的错误 我的代码中有以下行 String data cursor getString cursor getColumnIndex columnIndex columnIndex 被传递到该
  • java.lang.IllegalArgumentException:找不到片段的 id 0x1020002 (android:id/content) 的视图

    我正在尝试从一个片段移动到另一个片段 它在片段事务期间显示以下错误 java lang IllegalArgumentException No view found for id 0x1020002 android id content f
  • onClick 未在带有子项的 LinearLayout 上触发

    我有一个自定义的 LinearLayout 和一个较小的 TextView 子级 我希望能够单击 TextView 未覆盖的区域 因此我将 clickable true 和 onclicklistener 设置为 LinearLayout
  • Android 从命令行停止模拟器

    这个问题与如何通过命令行关闭Android模拟器 https stackoverflow com questions 5912403 how to shut down android emulator via cmd 但是 在尝试第一个答案
  • onBackPressed 隐藏 不破坏 Activity

    我知道如何取消后退按键 以便活动 主窗口保持可见 public void onBackPressed return 我的目标是隐藏该活动 但是 在没有完成它的情况下 您如何在 onBackPressed 事件中做到这一点 即我想达到 onP

随机推荐