[英]Communicating between Fragments Android in Java
好的,我有一個簡單的問題。 以下是在 Fragment 之間進行通信的一種非常簡單且基本的方法,但我從未見過有人使用它。 我想知道使用這種方法有什么缺點。 如果有人有任何意見,請在答案中告訴我。 謝謝
public class MyActivity extends Activity {
FragmentOne fragmentOne;
FragmentTwo fragmentTwo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
private void showFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, fragment).commit();
}
public void showFragmentOne() {
if(fragmentOne == null){
fragmentOne = FragmentOne();
}
showFragment(fragmentOne);
}
public void showFragmentTwo(String name) {
if(fragmentTwo == null)
fragmentTwo = new FragmentTwo();
fragmentTwo.setData(name);
showFragment(fragmentTwo);
}
}
片段一的代碼:
public class FragmentOne extends Fragment {
private MyActivity myActivity;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
myActivity = getActivity() instanceOf MyActivity ? (MyActivity) getActivity() : null;
button.setOnClickListener(() -> {
if(myActivity != null)
myActivity.showFragmentTwo(editText.getText().toString()); //assuming there's an edit text
}
return inflater.inflate(R.layout.fragment_one, container, false);
}
以及 fragmentTwo 的代碼
public class FragmentTwo extends Fragment {
private String name;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
textView.setText(name); //assuming there's a textview
return inflater.inflate(R.layout.fragment_two, container, false);
}
public void setData(String name){
this.name = name;
}
}
PS請忽略縮進等,我沒有復制這段代碼,我實際上輸入了整個內容。
FragmentOne fragmentOne; FragmentTwo fragmentTwo; public void showFragmentOne() { if(fragmentOne == null){ fragmentOne = FragmentOne(); } //... } public void showFragmentTwo(String name) { if(fragmentTwo == null) { fragmentTwo = new FragmentTwo(); } //...
當 Android 使用它們的無參數構造函數而不是使用您在此處創建的實例重新創建您的 Fragment 實例時,這將在低內存條件后中斷。
盡管從技術上講,在這種特殊情況下,您使用的是fragmentManager.beginTransaction().replace().commit()
,因此您的實例將獲勝,系統重新創建的實例將被覆蓋。 當您使用replace
而不是add
時,您也不會得到“多個重疊片段”。
但是,您將無法通過Fragment.onSaveInstanceState
/ Fragment.onCreate(Bundle)
恢復 Fragment,因為您將使用自己的未初始化片段覆蓋系統重新創建的片段。
基本上,這種方法會導致狀態丟失。
開箱即用,預期的解決方案是使用
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new FragmentOne(), "one").commit();
}
}
public void showFragmentTwo(String name) {
FragmentTwo fragmentTwo = new FragmentTwo();
Bundle bundle = new Bundle();
bundle.putString("name", name);
fragmentTwo.setArguments(bundle);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment, fragmentTwo, "two")
.addToBackStack(null)
.commit();
}
}
您可能會使用findFragmentByTag
找到片段。
雖然我個人不喜歡 Fragment backstack,但我相信如果您跟蹤描述您應該擁有的片段的標識符會容易得多,這些標識符可以為您提供給定的標簽,並且您可以將片段設置為您想要的任何 state不必僅僅因為您向前導航就刪除片段(因此失去其視圖+狀態)。
您可以在此處查看我傾向於用於片段的方法。
使用以下代碼,我可以將任何 Fragment 設置為我想要的任何 state 中,而無需依賴addToBackStack
。
public class FragmentStateChanger {
private FragmentManager fragmentManager;
private int containerId;
public FragmentStateChanger(FragmentManager fragmentManager, int containerId) {
this.fragmentManager = fragmentManager;
this.containerId = containerId;
}
public void handleStateChange(StateChange stateChange) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.disallowAddToBackStack();
// here you could animate based on direction
List<Key> previousKeys = stateChange.getPreviousKeys();
List<Key> newKeys = stateChange.getNewKeys();
for(Key oldKey : previousKeys) {
Fragment fragment = fragmentManager.findFragmentByTag(oldKey.getFragmentTag());
if(fragment != null) {
if(!newState.contains(oldKey)) {
fragmentTransaction.remove(fragment);
} else if(!fragment.isDetached()) {
fragmentTransaction.detach(fragment);
}
}
}
for(Key newKey : newKeys) {
Fragment fragment = fragmentManager.findFragmentByTag(newKey.getFragmentTag());
if(newKey.equals(stateChange.topNewKey())) {
if(fragment != null) {
if(fragment.isRemoving()) {
fragment = newKey.createFragment();
fragmentTransaction.replace(containerId, fragment, newKey.getFragmentTag());
} else if(fragment.isDetached()) {
fragmentTransaction.attach(fragment);
}
} else {
fragment = newKey.createFragment();
fragmentTransaction.add(containerId, fragment, newKey.getFragmentTag());
}
} else {
if(fragment != null && !fragment.isDetached()) {
fragmentTransaction.detach(fragment);
}
}
}
fragmentTransaction.commitAllowingStateLoss();
}
}
然后我可以這樣使用:
public class MainActivity
extends AppCompatActivity
implements StateChanger {
private static final String TAG = "MainActivity";
@BindView(R.id.fragment)
ViewGroup root;
FragmentStateChanger fragmentStateChanger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
fragmentStateChanger = new FragmentStateChanger(getSupportFragmentManager(), R.id.fragment);
Navigator.configure()
.setStateChanger(this)
.install(this, root, History.single(FragmentOneKey.create()));
}
@Override
public void onBackPressed() {
if(!Navigator.onBackPressed(this)) {
super.onBackPressed();
}
}
public void showSecondFragment(String data) {
Navigator.getBackstack(this).goTo(FragmentTwoKey.create(data));
}
// this handles navigation from any nav state to any other nav state
@Override
public void handleStateChange(@NonNull StateChange stateChange, @NonNull Callback completionCallback) {
if(stateChange.isTopNewKeyEqualToPrevious()) {
completionCallback.stateChangeComplete();
return;
}
fragmentStateChanger.handleStateChange(stateChange);
completionCallback.stateChangeComplete();
}
}
如果沒有方便地說backstack.goTo(SomeScreen())
而不是雜耍交易,就無法真正想象 Fragments。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.