下部のナビゲーションタブでフラグメントを変更するアクティビティがあります。これらのタブを前後にクリックすると、ある時点で機能しなくなります。いくつかのログを入れたので、コードは問題なく実行されます。しかし、フラグメントは切り替えられていません。
コードはkotlinにありますが、かなり単純です
fun showTabFragment(tag: String) {
val currentFragment: Fragment? = supportFragmentManager.fragments?.lastOrNull()
var fragment = supportFragmentManager.findFragmentByTag(tag)
val fragmentExists = fragment != null
if (fragment == null) {
when (tag) {
TAG_LOGBOOK -> fragment = LogbookFragment()
TAG_RECIPES -> fragment = RecipesFragment()
TAG_PROFILE -> fragment = ProfileFragment()
else -> fragment = MeetingPlacesFragment()
}
}
val transaction = supportFragmentManager.beginTransaction()
if (currentFragment != null) {
Log.i("jacek", "hiding " + currentFragment.javaClass.simpleName)
transaction.hide(currentFragment)
}
if (fragmentExists) {
Log.i("jacek", "showing " + fragment.javaClass.simpleName)
transaction.show(fragment)
} else {
Log.i("jacek", "adding " + fragment.javaClass.simpleName)
transaction.add(R.id.container, fragment, tag)
}
transaction.commit()
}
破片はかなり重いです。私はいくつかの軽量のものを試してみますが、それでも私の意見では問題にはならないはずです。他に試すことができるものはありますか?
最新のサポートライブラリを使用しています-25.2.0また、フラグメントを再作成せずにクロスフェードアニメーションを追加することが重要であるため、フラグメントを置き換えることには興味がありません。
非表示または表示したいフラグメントの同じインスタンスを再利用する必要があります。
private fun replaceFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction().apply {
if (fragment.isAdded) {
show(fragment)
} else {
add(R.id.fmFragmentContainer, fragment)
}
supportFragmentManager.fragments.forEach {
if (it != fragment && it.isAdded) {
hide(it)
}
}
}.commit()
}
@ALiの答えは良いですが、5つのフラグメントがあると想像してみてください。これは、フラグメントを表示/非表示にする別の方法です。
// in BaseFragment
public abstract String getTAG();
//in FragmentA, FragmentB and FragmentC
public String getTAG(){
return TAG;
}
//Activity containing the fragments
//Android.support.v4.app.Fragment;
private FragmentA fragmentA; //inherited BaseFragment
private FragmentB fragmentB; //inherited BaseFragment
private FragmentC fragmentC; //inherited BaseFragment
private ConcurrentHashMap<String,BaseFragment> mapOfAddedFragments = new ConcurrentHashMap<>();
/**
* Displays fragment A
*/
private void displayFragmentA() {
displayFragment(fragmentA)
}
/**
* Displays fragment B
*/
private void displayFragmentB() {
displayFragment(fragmentB)
}
/**
* Displays fragment C
*/
private void displayFragmentC() {
displayFragment(fragmentC)
}
/**
* Loads a fragment using show a fragment
* @param fragment
*/
private void displayFragment(BaseFragment fragment){
if(!mapOfAddedFragments.containsKey(fragment.getTAG()))
mapOfAddedFragments.put(fragment.getTAG(), fragment);
showFragment(fragment.getTAG(), R.id.containerBody);
}
/**
* Displays a fragment and hides all the other ones
* @param fragmentTag is the tag of the fragment we want to display
*/
private void showFragment(String fragmentTag, @IdRes int containerViewId){
FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
BaseFragment fragment = null;
fragment = mapOfAddedFragments.get(fragmentTag);
if(fragment != null) {
if (fragment.isAdded())
ft.show(fragment);
else { //fragment needs to be added to the frame container
ft.add(containerViewId, fragment, fragment.getTAG());
}
}
else //the chosen fragment doesn't exist
return;
//we hide the other fragments
for (ConcurrentHashMap.Entry<String, BaseFragment> entry : mapOfAddedFragments.entrySet()){
if(!entry.getKey().equals(fragmentTag)){
BaseFragment fragmentTemp = entry.getValue();
// Hide the other fragments
if(fragmentTemp != null)
if(fragmentTemp.isAdded())
ft.hide(fragmentTemp);
}
}
//commit changes
ft.commit();
}
そして、それらをインスタンス化するには、アクティビティのonCreate()メソッドでこれを行うことができます。
//don't forget to get the .TAG elsewhere before using them here
//never call them directly
private void instantiateFragments(Bundle inState) {
if (inState != null) {
fragmentA = inState.containsKey(FragmentA.TAG) ?
(FragmentA) getSupportFragmentManager().getFragment(inState, FragmentA.TAG):
FragmentA.newInstance(FragmentA.TAG,"0");
fragmentB = inState.containsKey(FragmentB.TAG) ?
(FragmentB) getSupportFragmentManager().getFragment(inState, FragmentB.TAG):
FragmentB.newInstance(FragmentB.TAG,"1");
fragmentc = inState.containsKey(FragmentC.TAG) ?
(FragmentC) getSupportFragmentManager().getFragment(inState, FragmentC.TAG):
FragmentC.newInstance(FragmentC.TAG,"2");
}
else{
fragmentA = FragmentA.newInstance(FragmentA.TAG,"0");
fragmentB = FragmentB.newInstance(FragmentB.TAG,"1");
fragmentc = FragmentC.newInstance(FragmentC.TAG,"2");
}
}
Shujaat ALi Khanの質問に従って編集:
BaseFragmentはsupport4フラグメントを拡張します。
public abstract class BaseFragment extends Fragment {
public abstract String getTAG();
//whatever we can add to be inherited
}
FragmentAの例:
public class FragmentA extends BaseFragment {
// Store instance variables
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
public static final String TAG = "FragmentA";
// newInstance constructor for creating fragment with arguments
public static FragmentA newInstance(String param1, String param2) {
FragmentA fragment = new FragmentA();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
// Store instance variables based on arguments passed
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragmentA, container, false);
return view;
}
//other lifecycle methods
@Override
public String getTAG() {
return TAG;
}
}
最後にR.id.containerBody
は、これらのフラグメントを含むアクティビティ内のフラグメントを含むFrameLayoutのIDです。
ここでの問題は、「現在の」フラグメントを非表示にしている場合でも、メモリにロードされている他のフラグメントがあり、一貫性のない動作を与えることです。
表示したいフラグメントを除くすべてのフラグメントを非表示にすることで、これを修正できるはずです。
この答えに感謝します。 Androidで非表示フラグメントを表示
例えば:
private FragmentA fragmentA;
private FragmentB fragmentB;
private FragmentC fragmentC;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentA = FragmentA.newInstance();
fragmentB = FragmentB.newInstance();
fragmentC = FragmentC.newInstance();
}
protected void displayFragmentA() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (fragmentA.isAdded()) {
ft.show(fragmentA);
} else {
ft.add(R.id.fragement_container, fragmentA);
}
if (fragmentB.isAdded()) { ft.hide(fragmentB); }
if (fragmentC.isAdded()) { ft.hide(fragmentC); }
ft.commit();
}
同様に、displayFragmentB()およびdisplayFragmentC()の関数を作成する必要があります