将数据从 RecyclerView.Adapter 传递到片段 onClick

Posted

技术标签:

【中文标题】将数据从 RecyclerView.Adapter 传递到片段 onClick【英文标题】:Passing data from RecyclerView.Adapter to fragment onClick 【发布时间】:2019-08-19 16:18:19 【问题描述】:

我试图弄清楚如何将数据从 RecyclerView 中的单击项目获取到片段中的列表视图。我似乎无法弄清楚如何做到这一点,因为我无法让我的捆绑包工作。

我尝试过 *** 上提供的各种解决方案,但都没有奏效。我已经设法从 recyclerview 获取信息,但我一直在试图弄清楚如何将它传递给片段。有人可以帮帮我吗?

适配器类:

public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder> 

    private Context context;

    ArrayList<FoodActivity> list;
    public FoodAdapter(ArrayList<FoodActivity> list)
        this.list = list;
    


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_item_food, parent, false);

        return new ViewHolder(view);
    

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) 
        holder.foods.setText(list.get(position).getName());
        holder.carbo.setText(list.get(position).getCarbohydrates());
        holder.protein.setText(list.get(position).getProtein());
        holder.fats.setText(list.get(position).getFats());

        //Get items from recyclerview when user clicks them. Then send them to FoodFragment
        holder.itemView.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 

                String foods = list.get(position).getName();
                String carbo = list.get(position).getCarbohydrates();
                String protein = list.get(position).getProtein();
                String fats = list.get(position).getFats();

                Toast.makeText(v.getContext(), "test: " + foods, Toast.LENGTH_SHORT).show();


            
        );
    


    @Override
    public int getItemCount() 
        return list.size();
    

    class ViewHolder extends RecyclerView.ViewHolder 
        TextView foods, carbo, fats, protein;

        public ViewHolder(View itemView) 
            super(itemView);

            carbo = itemView.findViewById(R.id.carbo);
            protein = itemView.findViewById(R.id.protein);
            fats = itemView.findViewById(R.id.fats);
            foods = itemView.findViewById(R.id.food);
        
    

数据来自的Fragment:

public class TrackingFragment extends Fragment 

    DatabaseReference databaseReference;
    ArrayList<FoodActivity> list;
    RecyclerView recyclerView;
    SearchView searchView;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment_tracking, container, false);

        databaseReference = FirebaseDatabase.getInstance().getReference().child("foods");
        recyclerView = view.findViewById(R.id.rv);
        searchView = view.findViewById(R.id.searchFood);

        return view;
    

    @Override
    public void onStart() 
        super.onStart();

        if(databaseReference != null)
            databaseReference.addValueEventListener(new ValueEventListener() 
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                    if(dataSnapshot.exists())
                        list = new ArrayList<>();
                        for(DataSnapshot ds : dataSnapshot.getChildren())
                            list.add(ds.getValue(FoodActivity.class));
                        
                        FoodAdapter adapter = new FoodAdapter(list);
                        recyclerView.setAdapter(adapter);


                    
                

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) 
                    Toast.makeText(getActivity(), databaseError.getMessage(), Toast.LENGTH_SHORT).show();
                
            );
        
        if(searchView != null)
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
                @Override
                public boolean onQueryTextSubmit(String query) 
                    return false;
                

                @Override
                public boolean onQueryTextChange(String newText) 
                    search(newText);
                    return true;
                
            );
        
    

    private void search(String str)
        ArrayList<FoodActivity> searchList = new ArrayList<>();
        for(FoodActivity object : list)
            if(object.getName().toLowerCase().contains(str.toLowerCase()))
                searchList.add(object);
            
        
        FoodAdapter foodAdapter = new FoodAdapter(searchList);
        recyclerView.setAdapter(foodAdapter);
    


以及它需要去的类:

public class FoodFragment extends Fragment 

    ImageButton addFood;

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

        addFood = view.findViewById(R.id.addFood);

        addFood.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 

                FragmentTransaction fr = getFragmentManager().beginTransaction();
                fr.replace(R.id.fragment_container, new TrackingFragment());
                fr.addToBackStack(null).commit();
            
        );

        return view;
    


【问题讨论】:

根据这段代码很难说你在哪里使用FoodFragment。两个片段是否在同一个活动中?你有TrackingFragmentFoodAdapter,对吗? 我不完全确定你的意思。从带有bottomNavigationView 的MenuActivity 调用FoodFragment,然后从FoodFragment 调用TrackingFragment。 FoodAdapter 已连接到 TrackingFrackment 是的。 但是你的布局到底是怎么设计的?你有一个 MenuActivity,它显示 FoodFragment,当你选择一些东西时,你用 TrackingFragment 替换你的食物 Fragment,还是你打开一个新的 Activity,它显示 Tracking Fragment? 在 MenuActivity 中,我在 FrameLayout 中有一个 fragment_container。每当我必须显示新片段时,我只需替换该容器中的片段。 【参考方案1】:

最简单的就是在activity中添加你需要的变量,用onClick()设置它们的值,然后在其他fragment中检索数据:

活动中:

String foods;

public String getFoods() 
    return foods;


public void setFoods(String foods) 
    this.foods = foods;

在适配器中:

   holder.itemView.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
           ((YourActivity)getActivity()).setFoods("Any value");
        
    );

在目标片段中:

String foods = ((YourActivity)getActivity()).getFoods();

【讨论】:

这与 Kotlin 兼容吗? 是的,为什么不呢?但是这种方式太简单了,我不适合认真的开发人员。我建议你在适配器中使用回调。【参考方案2】:

如下向你的适配器添加一个接口

public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder> 

interface OnClickListener 
    void onClick(FoodActivity clickedItem);


private OnClickListener mCallback; 
private ArrayList<FoodActivity> list;

public FoodAdapter(ArrayList<FoodActivity> list)
    this.list = list;


public void setOnClickListener(OnClickListener callback) 
    mCallback = callback;



@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_item_food, parent, false);

    return new ViewHolder(view);


@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) 
    holder.foods.setText(list.get(position).getName());
    holder.carbo.setText(list.get(position).getCarbohydrates());
    holder.protein.setText(list.get(position).getProtein());
    holder.fats.setText(list.get(position).getFats());

    //Get items from recyclerview when user clicks them. Then send them to FoodFragment
    holder.itemView.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            if (mCallback != null)
                mCallback.onClick(list.get(position));
        
    );



@Override
public int getItemCount() 
    return list.size();


class ViewHolder extends RecyclerView.ViewHolder 
    TextView foods, carbo, fats, protein;

    public ViewHolder(View itemView) 
        super(itemView);

        carbo = itemView.findViewById(R.id.carbo);
        protein = itemView.findViewById(R.id.protein);
        fats = itemView.findViewById(R.id.fats);
        foods = itemView.findViewById(R.id.food);
    


【讨论】:

感谢您抽出宝贵时间回答。我已经尝试在 FoodFragment 中获取数据,但似乎无法让它工作(我之前没有使用过接口,我尝试过的东西也没有奏效)。你介意告诉我如何检索这些数据吗?【参考方案3】:

当涉及到整个堆栈时,android 有时会有点复杂:

01 RecyclerView 适配器

/** 01. Some Adapter */
public class SomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> 
    
    private WeakReference<Context> mContext;

    /** Constructor */
    public SomeAdapter(@NonNull Context context) 
        this.mContext = new WeakReference<>(context);
    

    @NonNull
    protected Context getContext() 
        return this.mContext.get();
    

    /** Call to Activity from within the adapter. */
    private void someMethod() 
        SomeActivity activity = (SomeActivity) getContext();
        synchronized(activity) activity.showLoginDialog();
    

02 AppCompatActivity

/** 02. Some Activity */
public class SomeActivity extends AppCompatActivity 

    @Nullable
    private BaseFragment currentFragment = null;

    /** Constructor */
    public SomeActivity() 

    public void setCurrentFragment(Fragment fragment) 
        this.currentFragment = fragment;
    

    /** Call to the current Fragment. */
    public void someMethod() 
        if (currentFragment != null) 
            currentFragment.someMethod();
        
    

03 片段

/** Some Fragment */
public class SomeFragment extends Fragment 

    /** Constructor */
    public SomeFragment() 

    @Override
    public void onAttach(@NonNull Context context) 
        super.onAttach(context);
        ((BaseActivity) context).setCurrentFragment(this);
    

    @Override
    public void onDetach() 
        super.onDetach();
        ((BaseActivity) getActivity()).setCurrentFragment(this);
    

【讨论】:

【参考方案4】:

要将数据从 FoodAdapter 获取到 TrackingFragment,您可以将 TrackingFragment(或其实现的接口,理想情况下)作为参数添加到 FoodAdapter 构造函数,然后使用该实例将 ViewHolder 点击转发到 TrackingFragment 进行处理。

要将数据从 TrackingFragment 获取到 FoodFragment,请使用 setTargetFragment/onActivityResult 模式进行片段 片段通信。这个答案有一个例子:https://***.com/a/13733914/3238938

【讨论】:

以上是关于将数据从 RecyclerView.Adapter 传递到片段 onClick的主要内容,如果未能解决你的问题,请参考以下文章

我无法从另一个带有 recyclerview.adaper 的片段中打开带有 recyclerview.adapter 的片段

如何从 RecyclerView.Adapter<CardAdapter.ViewHolder> 打开片段

从 RecyclerView Adapter Android 隐藏和显示多个视图持有者

recyclerview Adapter

RecyclerView的使用

RecyclerView的使用