FragmentTabHost 在 popBackStack 之后得到空片段

FragmentTabHost getting empty fragments after popBackStack

我已经尝试了 Whosebug 中的每一个 post 但都没有成功,我有一个 FragmentTabHost activity 带有标签 A B C D E

当我转到选项卡 A 然后转到选项卡 B 时一切正常,但是如果我 return 到选项卡 A 是空白,那么 return 到选项卡 B 也是空白!!

A -> B -> A = 空白 -> B = 空白

我按照此 post 使其正常工作 Dynamically changing the fragments inside a fragment tab host?,但选项卡之间的转换不起作用。

我尝试更改我的 BaseContainerFragment 以使用 getSupportFragmentManager 而不是 getChildFragmentManager 但没有成功,此时我还删除了 addToBackStack(null) 我没有想法,我们将不胜感激,谢谢。

这是包含使用片段创建选项卡的代码的 mainActivity。

public class ActivityMain extends FragmentActivity {

    public static final String TAB_1_TAG = "tab_1";
    public static final String TAB_2_TAG = "tab_2";
    public static final String TAB_3_TAG = "tab_3";
    public static final String TAB_4_TAG = "tab_4";
    public static final String TAB_5_TAG = "tab_5";
    private FragmentTabHost mTabHost;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
        mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
        mTabHost.getTabWidget().setDividerDrawable(null);
        mTabHost.getTabWidget().setStripEnabled(false);

        mTabHost.addTab(mTabHost.newTabSpec(TAB_1_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_account)), FragmentAccountContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_2_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_discounts)), FragmentPromotionsContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_3_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_payment)), FragmentAccountContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_4_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_gas)), FragmentAccountContainer.class, null);
        mTabHost.addTab(mTabHost.newTabSpec(TAB_5_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_rest)), FragmentAccountContainer.class, null);
    }

    @Override
    public void onBackPressed() {
        boolean isPopFragment = false;

        String currentTabTag = mTabHost.getCurrentTabTag();
        Log.e("ActivityMain", "currentTabTag: " + currentTabTag);
        if (currentTabTag.equals(TAB_1_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_1_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_2_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_2_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_3_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_3_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_4_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_4_TAG)).popFragment();
        } else if (currentTabTag.equals(TAB_5_TAG)) {
            isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_5_TAG)).popFragment();
        }
        Log.e("ActivityMain", "isPopFragment: " + isPopFragment);
        if (!isPopFragment) {
            finish();
        }
    }
}

这是我的允许回溯和替换片段的 BaseContainerFragment

public class BaseContainerFragment extends Fragment {

    public void replaceFragment(Fragment fragment, boolean addToBackStack) {
        FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
        if (addToBackStack) {
            transaction.addToBackStack(null);
        }
        transaction.replace(R.id.container_framelayout, fragment);
        transaction.commit();
        getChildFragmentManager().executePendingTransactions();
    }

    public boolean popFragment() {
        Log.e("test", "pop fragment: " + getChildFragmentManager().getBackStackEntryCount());
        boolean isPop = false;
        if (getChildFragmentManager().getBackStackEntryCount() > 0) {
            isPop = true;
            getChildFragmentManager().popBackStack();
        }
        return isPop;
    }
}

这是第一个选项卡的容器(这个选项卡包含 2 个活动,一个是主要的,另一个是在列表视图上调用的)

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myPrefs = this.getActivity().getSharedPreferences("getLogin", Context.MODE_PRIVATE);
    idUser = myPrefs.getInt("idUser", 0);

    d(TAG, "idUser: " + idUser);
    /*
    Map<String,?> keys = myPrefs.getAll();

    for(Map.Entry<String,?> entry : keys.entrySet()){
        Log.d("map values",entry.getKey() + ": " +
                entry.getValue().toString());
    }
    */
    context = getActivity();
    pDialog = new SweetAlertDialog(context, PROGRESS_TYPE);


    // Check if Internet present
    if (!isOnline(context)) {
        // Internet Connection is not present
        makeText(context, "Error en la conexion de Internet",
                LENGTH_LONG).show();
        // stop executing code by return
        return;
    }

    new asyncGetFeedClass(context).execute();

}

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

    toolbar = (Toolbar) v.findViewById(R.id.toolbar);
    TextView mTitle = (TextView) toolbar.findViewById(toolbar_title);
    mTitle.setText("TARJETAS");

    list = (ListView) v.findViewById(R.id.list);

    // Click event for single list row
    list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {

            FragmentAccount fragment = new FragmentAccount();
            // if U need to pass some data
            Bundle bundle = new Bundle();

            if (listBalance.get(position).get(TAG_ACCOUNT_BANKACCOUNTS_ID) != null) {
                bundle.putString("idBankAccount", listBalance.get(position).get(TAG_ACCOUNT_BANKACCOUNTS_ID));
                bundle.putString("idGiftCard", "0");
            } else if (listBalance.get(position).get(TAG_ACCOUNT_GIFTCARDS_ID) != null) {
                bundle.putString("idGiftCard", listBalance.get(position).get(TAG_ACCOUNT_GIFTCARDS_ID));
                bundle.putString("idBankAccount", "0");
            } else {
                bundle.putString("idBankAccount", "0");
                bundle.putString("idGiftCard", "0");
            }

            fragment.setArguments(bundle);
            ((BaseContainerFragment) getParentFragment()).replaceFragment(fragment, false);
        }
    });

    return v;
}

选项卡 #1

的主要 class
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myPrefs = this.getActivity().getSharedPreferences("getLogin", Context.MODE_PRIVATE);
    idUser = myPrefs.getInt("idUser", 0);

    d(TAG, "idUser: " + idUser);
    /*
    Map<String,?> keys = myPrefs.getAll();

    for(Map.Entry<String,?> entry : keys.entrySet()){
        Log.d("map values",entry.getKey() + ": " +
                entry.getValue().toString());
    }
    */
    context = getActivity();
    pDialog = new SweetAlertDialog(context, PROGRESS_TYPE);

    // Check if Internet present
    if (!isOnline(context)) {
        // Internet Connection is not present
        makeText(context, "Error en la conexion de Internet",
                LENGTH_LONG).show();
        // stop executing code by return
        return;
    }

    Bundle bundle = this.getArguments();
    idBankAccount = Integer.parseInt(bundle.getString(FragmentCardHolder.TAG_ACCOUNT_BANKACCOUNTS_ID, "0"));
    idGiftCard = Integer.parseInt(bundle.getString(FragmentCardHolder.TAG_ACCOUNT_GIFTCARDS_ID, "0"));

    if(idBankAccount > 0){
        new asyncGetBankTransactions(context).execute();
    } else if(idGiftCard > 0) {
        new asyncGetGiftCardTransactions(context).execute();
    } else {
        new asyncGetX111Transactions(context).execute();
    }
}

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

    toolbar = (Toolbar) v.findViewById(id.toolbar);
    TextView mTitle = (TextView) toolbar.findViewById(toolbar_title);
    mTitle.setText("MI CUENTA");
    toolbar.setNavigationIcon(R.drawable.icon_user);
    toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            goToCards();
        }
    });

    layoutAccount = (LinearLayout) v.findViewById(id.layoutAccount);
    layoutGetCredit = (LinearLayout) v.findViewById(id.layoutGetCredit);
    layoutTransactions = (LinearLayout) v.findViewById(id.layoutTransactions);

    btnAccount = (Button) v.findViewById(id.btnMyBalance);
    btnGetCredit = (Button) v.findViewById(id.btnGetCredit);
    btnSendCredit = (Button) v.findViewById(id.btnSendCredit);
    btnTransactions = (Button) v.findViewById(id.btnTransactions);

    list = (ListView) v.findViewById(id.list);

    btnTransactions.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            layoutAccount.setVisibility(View.GONE);
            layoutGetCredit.setVisibility(View.GONE);
            layoutTransactions.setVisibility(View.VISIBLE);
        }
    });

    btnGetCredit.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            layoutAccount.setVisibility(View.GONE);
            layoutGetCredit.setVisibility(View.VISIBLE);
            layoutTransactions.setVisibility(View.GONE);
        }
    });

    btnAccount.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            layoutAccount.setVisibility(View.VISIBLE);
            layoutGetCredit.setVisibility(View.GONE);
            layoutTransactions.setVisibility(View.GONE);
        }
    });

    return v;
}

private void goToCards() {
    FragmentCardHolder fragment = new FragmentCardHolder();
    ((BaseContainerFragment) getParentFragment()).replaceFragment(fragment, true);
}

你为什么要跟踪碎片并自己弹出它们?您不需要那样做,也不应该覆盖 onBackPressed()。让 FragmentManager 处理片段事务。

如果 activity 中有片段,请使用

FragmentManager fManager = getFragmentManager();

或者如果您想支持 Android 3.0 之前的设备,请使用

FragmentManager fManager = getSupportFragmentManager();

如果片段在另一个片段中,则使用

FragmentManager fManager = getChildFragmentManager();

拥有 fManager 后,要显示片段,请使用

fManager.beginTransaction().add(R.id.fragment_parent, new FirstTabFragment()).commit();

其中 fragment_parent 是您要放置片段的父视图。

当你想切换到下一个片段时,使用

fManager.beginTransaction().replace(R.id.fragment_parent, new SecondTabFragment())
                           .addToBackStack(null)
                           .commit();

由于您将其添加到后退堆栈,因此当您返回时,您将看到您的第一个片段。而已。

此外,您很容易意识到这会导致您的片段每次都从头开始创建,您可以通过初始化一次并重新使用它们来防止这种情况。

HTH

我认为问题出在代码的隐藏部分,您将第一个片段添加到容器(FragmentAccountContainer 和 FragmentPromotionsContainer classes)。我建议你在 BaseContainerFragment.class 中创建带有示例签名的抽象方法 protected abstract Fragment getFirstFragment(); 因此,具体容器 class 将覆盖此方法并将第一个片段的 return 新实例添加到超级 class 中,然后在父 class 中使用添加事务将其添加到片段容器中。

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        addFragment(getFirstFragment(), false);
    }
}

请注意,您应该在添加片段之前检查 savedInstanceState 是否为 null,以避免在 activity 系统重新创建时重复。 在嵌套片段中,您可以像以前那样使用替换 ((BaseContainerFragment) getParentFragment()).replaceFragment(___, true);

另外,我对您的代码有一些建议。你不能像@NecipAllef 建议的那样避免在 activity 中覆盖 onBackPressed,因为 known bug with default back logic and child fragment manager ,但你可以简化对 popFragment 的调用,比如

@Override
public void onBackPressed() {
    String currentTabTag = mTabHost.getCurrentTabTag();
    boolean isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(currentTabTag)).popFragment();
    if (!isPopFragment) {
        super.onBackPressed();
    }
}

为了将包设置为片段,我建议使用结构方法模式,例如

public class TestFragment extends Fragment {
    public static Fragment newInstance(String text){
        Fragment fragment = new TestFragment();
        Bundle args = new Bundle();
        args.putString("text", text);
        fragment.setArguments(args);
        return fragment;
    }
}

Ps:我为你创建了一个 simple project 具有描述的逻辑