繁体   English   中英

Java中的片段Android之间的通信

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM