代码之家  ›  专栏  ›  技术社区  ›  Red M

根据从片段A收集的数据,使用较少的样板代码从活动中启动片段B

  •  6
  • Red M  · 技术社区  · 8 年前

    我有以下设置:

    1. 我有一个 Activity 启动一个 FragmentA 是的。
      碎片 包含 recyclerView 还有一个 adapter 是的。

    2. 我有一个 interfaceA 在实现于 碎片 这样我就可以知道哪个位置被点击了。

    3. 我有时间 interfaceB 我在 碎片 ,它在 活动 启动的 碎片 在步骤1中。
    4. 最后,我要发射 FragmentB 从 活动 根据我得到的数据 接口B 是的。

    一切正常 然而,流程是乏味的,并且需要大量的样板代码。

    目标 就是拥有 activity 发射 fragmentB 其中包含来自 碎片 .

    问题 :能否以不同的方式实现?

    代码如下:

    活动 启动fragmenta:

    Fragment fragment = fragmentManager.findFragmentByTag(FragmentA.class.getName());
        if (fragment == null) {
    
            fragment = Fragment.instantiate(this, FragmentA.class.getName());
        }
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction
                .replace(R.id.fragmentLayout, fragment, FragmentA.class.getName())
                .addToBackStack(FragmentA.class.getName())
                .commit();
    

    内部 碎片 我们有 回收服务 ,和 接口A 实施于 适配器 以下内容:

    适配器类:

            public class AdapterA extends RecyclerView.Adapter< AdapterA.ViewHolderA> {
    
            //instances
            private Context context;
            private List<Data> dataList;
            private OnItemClickListener onItemListClickListener;
    
            //Constructor
            public AdapterA (Context context, List<Data> dataList, OnItemClickListener onItemListClickListener {
            this.context = context;
            this.dataList = dataList;
            this.onItemListClickListener = onItemListClickListener;
        }
    
    onCreateViewHolder....
    onBindViewHolder....
    getItemCount...
    
    class ViewHolderA RecyclerView.ViewHolder {
    //instances..
    //Constructor...
    
    }
            }
    

    interface 类接口A:

    public interface OnItemClickListener {
        void onItemClick(View view, int position);
    }
    

    接口 类接口B:

    public interface SingleItemEventListener {
        void onSingleItemClicked(int position);
    }
    

    碎片 班级:

    //Instances
    private AdapterA adapter;
    private RecyclerView recyclerView;
    private onSingleItemClicked singleItemEventListener;
    
    onAttach...
    onCreateView...
    
    @Override
    public void onStart() {
        super.onStart();
    
        //Setting adapter
        onSetAdapter();
    }
    
    private void onSetAdapter() {
        List<Data> dataList;
    
        dataList = getData();
    
        adapter = new AdapterA(context, dataList, new OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                singleItemEventListener.onSingleItemClicked(position);
            }
        });
    

    在 活动 ,我们正在实施 onSingleItemClicked 回调以接收事件并启动 碎片 从接口回调接收数据时:

    ActivityA implements SingleItemEventListener {
    @Override
        public void onSingleItemClicked(int position) {
    Data data = getData(position);
    
    if (data != null) {
    Bundle bundle = new Bundle();
    bundle.putParcelable("single_data_key", data);
    Fragment fragmentB = fragmentManager.findFragmentByTag(FragmentB.class.getName());
    
            if (fragmentB == null && bundle != null) {
                fragmentB = Fragment.instantiate(this, FragmentB.class.getName(), bundle);
            }
    
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction
                    .replace(R.id.FragmentLayout, fragmentB, FragmentB.class.getName())
                    .addToBackStack(FragmentB.class.getName())
                    .commit();
    }
    }
    }
    
    4 回复  |  直到 8 年前
        1
  •  3
  •   TpoM6oH    8 年前

    添加 ViewModel 并使用它在所有组件、活动和这两个片段之间进行通信。

    您可以从片段访问活动的viewmodel

    MyViewModel model = ViewModelProviders.of(getActivity()).get(MyViewModel.class);
    

    使用 LiveData 为了进行交流,从片段向其发送一个操作,并在活动中聆听它以启动另一个片段。

        2
  •  0
  •   abhishesh    8 年前

    您可以只使用单个接口而不是两个接口来执行相同的任务,也可以在片段和活动之间共享视图模型。

    方法1:使用单一接口

    将接口定义为

    public interface FragmentCallbackListener {
        void onItemClick(View view, int position);
    }
    

    让您的活动实现它:

    ActivityA extend Activity implements FragmentCallbackListener {
        @Override
        public void onItemClick(View view, int position) {
           .... 
        }
    }
    

    附加到实现fragmentCallbackListener的活动的片段应重写片段的onattach(),如下所示:

    public class FragmentA extends Fragment {
        private FragmentCallbackListener mListener;
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
    
            // This makes sure that the container activity has implemented
            // the listener. If not, it throws an exception
            try {
                mListener = (FragmentCallbackListener) activity;
            } catch (ClassCastException e) {
                throw new ClassCastException(activity.toString()
                    + " must implement FragmentCallbackListener");
            }
        }
     }
    

    将同一侦听器实例传递给适配器:

    adapter = new AdapterA(context, dataList, mListener);
    

    方法2:使用共享视图模型

    将视图模型定义为:

    public class SharedViewModel extends ViewModel {
        private final MutableLiveData<Data> selected = new MutableLiveData<Data>();
    
        public void select(Data data) {
            selected.setValue(data);
        }
    
        public LiveData<Data> getSelected() {
            return selected;
        }
    } 
    

    内部碎片

    public class FragmentA extends Fragment {
        private SharedViewModel model;
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
            ...
            adapter = new AdapterA(context, datalist, model);
        }
    }
    

    在适配器的视图onclicklistener中:

    view.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                model.select(view.getTag()); //or use getData(position) to return selected data
            }
        });
    

    内部活动

    ActivityA extend Activity {
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            SharedViewModel model = ViewModelProviders.of(this).get(SharedViewModel.class);
            model.getSelected().observe(this, data -> {
            // launch the new fragment B with selected data
            });
        }
    }
    

    有关详细信息,请阅读 https://developer.android.com/training/basics/fragments/communicating

        3
  •  0
  •   Nick Cardoso    8 年前

    如果没有外部库,你考虑过使用广播吗?

    它仍然需要样板文件,但是根据您的意见可以更干净一些(活动不需要是任何接口的实例,您不需要任何“上帝对象”模型)

    在fragmenta的适配器中,当单击某个项时,将发送一个带有显式操作和参数的广播作为附加项。在活动中注册(和注销)广播接收器(无需更改清单)。最后接收器像往常一样开始碎片化。

    片段A/适配器

    Intent item = new Intent(MY_CONSTANT);
    item.putExtra(MY_EXTRA_CONSTANT, position);
    getActivity().sentBroadcast(intent);
    

    活动

    private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int position = intent.getIntExtra(MY_EXTRA_CONSTANT, -1);
            //TODO: Move your FragmentB transaction here
        }
    };
    
    void onPause() {
       unregisterReceiver(myReceiver);
    }
    
    void onResume() {
       IntentFilter intentFilter = new IntentFilter();
       intentFilter.addAction(MY_CONSTANT);
       registerReceiver(myReceiver, intentFilter);
    }
    
        4
  •  -2
  •   Viraj Patel    8 年前

    你能做到的 不使用 Interface, BroadcastReceiver 和 ViewModel 是的。
    检查以下代码:

    活动a.java

    public class ActivityA extends AppCompatActivity {
    
        ActivityTestBinding mBinding;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mBinding = DataBindingUtil.setContentView(this, R.layout.activity_test);
    
            pushFragment(new FragmentA());
        }
    
        /**
         * @param fragment pass fragment you want to replace
         */
        public void pushFragment(Fragment fragment) {
            String backStateName = fragment.getClass().getName();
            FragmentManager manager = getSupportFragmentManager();
            boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
    
            if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) {
    //        if fragment not in back stack, create it.
                FragmentTransaction ft = manager.beginTransaction();
                ft.replace(R.id.container, fragment, backStateName);
                ft.addToBackStack(backStateName);
                ft.commit();
            }
        }
    
        @Override
        public void onBackPressed() {
            try {
                if (getSupportFragmentManager().getBackStackEntryCount() <= 1) {
                    finish();
                } else {
                    getSupportFragmentManager().popBackStack();
                }
            } catch (Exception e) {
                super.onBackPressed();
            }
        }
    }
    

    在这里 pushFragment 方法对所有片段都是通用的。
    在 onBackPressed() 它将检查backstackentrycount。如果计数小于或等于1,则表示只有最后一个片段在backback中,并且 finish(); 将被调用和退出应用程序。如果backstackentrycount中有>1个计数,则它将弹出最后一个片段。

    在你的 adaptera.java语言 以下内容:

    itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
    
                        if (context instanceof ActivityA) {
                            FragmentB mFragmentB = new FragmentB();
                            Bundle bundle = new Bundle();
                            bundle.putParcelable("single_data_key", dataList.get(getAdapterPosition()));
                            mFragmentB.setArguments(bundle);
                            ((ActivityA) context).pushFragment(mFragmentB);
                        } 
                    }
                });
    

    你已经过去了 context 关于活动的。所以你可以检查一下 if (context instanceof ActivityA) 然后你可以打电话 推进碎片 使用类型转换的活动方法。

    所以这不是你可以集成到你的android项目中的样板代码。