如何在回收者视图适配器中获取上下文


129

我正在尝试使用Picasso库来将URL加载到imageView,但是我无法context正确使用Picasso库。

public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.ViewHolder> {
    private List<Post> mDataset;



    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public class ViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView txtHeader;
        public ImageView pub_image;
        public ViewHolder(View v) {
            super(v);
            txtHeader = (TextView) v.findViewById(R.id.firstline);
            pub_image = (ImageView) v.findViewById(R.id.imageView);


        }
    }




    // Provide a suitable constructor (depends on the kind of dataset)
    public FeedAdapter(List<Post> myDataset) {
        mDataset = myDataset;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public FeedAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.feedholder, parent, false);
        // set the view's size, margins, paddings and layout parameters
        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element

        holder.txtHeader.setText(mDataset.get(position).getPost_text());

        Picasso.with(this.context).load("http://i.imgur.com/DvpvklR.png").into(holder.pub_image);


    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.size();
    }

}

Answers:


290

您在这里有一些选择:

  1. Context作为参数传递给FeedAdapter并将其保留为类字段
  2. Context在需要时使用依赖项注入进行注入。我强烈建议您阅读有关内容。有一个很棒的工具-Dagger by Square
  3. 从任何View对象获取它。在您的情况下,这可能适合您:

    holder.pub_image.getContext()

    作为pub_image一个ImageView


64
我更喜欢第三个选项,从视图中获取上下文。这是最简单,最直接的解决方案。
迪克·卢卡斯

或者更好的方法是传递Picasso实例,而不是将Picasso实例保存在类实例上并延迟加载它。
埃里克·科克伦

8
每个ViewHolder都包含一个在构造函数中传递的itemView实例。像这样使用它:
itemView.getContext

1
你不能做第二件事,可以吗?我尝试过,但这最终将成为您的任务,ApplicationContext并且与活动无关,从而导致Glide内部运行时崩溃。
boltup_im_coding

如果我想使用#2,如何将组件对象传递给适配器?
Ezio

32

您可以添加全局变量:

private Context context;

然后从这里分配上下文:

@Override
public FeedAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
    // create a new view
    View v=LayoutInflater.from(parent.getContext()).inflate(R.layout.feedholder, parent, false);
    // set the view's size, margins, paddings and layout parameters
    ViewHolder vh = new ViewHolder(v);
    // set the Context here 
    context = parent.getContext();
    return vh;
}

快乐的装饰:)


也为我工作!谢谢
肯尼·达比里

21
我强烈建议AGAINST具有上下文的全局引用。这可能会导致可怕的内存泄漏问题!!
solidak '17

1
如果您将Viewholder子类化,它可以是私有的。
r3dm4n

如果适配器连接到RecyclerView,则可以保证仍然需要该上下文。如果您可以取消附加适配器,那么它仍然可以使用,除非出于某种原因在分离后对该适配器拥有强大的引用,在这种情况下,您应该清除缓存的上下文,可以使用诸如之类的方法onDetachedFromRecyclerView
androidguy

19

简短答案:

Context context;

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
    context = recyclerView.getContext();
}

解释为什么其他答案不太好:

  1. Context完全不需要传递给适配器,因为RecyclerView您可以从类内部访问它
  2. 获得ContextViewHolder水平意味着你每次都这样做,你绑定或创建ViewHolder。您重复操作。
  3. 我认为您不必担心任何内存泄漏。如果您的适配器在Activity使用寿命之外徘徊(这很奇怪),则说明您已经存在泄漏。

在这种情况下,我们应该实现onDetachedFromRecyclerView()并释放上下文吗?

@JohnPang并不是真的,除非您要极度防御。如果将适配器引用保留在“活动”中,则很安全。
Maciej Beimcik

17

您可以使用pub_image上下文(holder.pub_image.getContext()):

@Override
public void onBindViewHolder(ViewHolder ViewHolder, int position) {

    holder.txtHeader.setText(mDataset.get(position).getPost_text());

    Picasso.with(holder.pub_image.getContext()).load("http://i.imgur.com/DvpvklR.png").into(holder.pub_image);


}

6

您可以定义:

Context ctx; 

onCreate初始化ctx为:

ctx=parent.getContext(); 

注意:Parent是一个ViewGroup。


5

首先全球宣布

Context mContext;

通过修改构造函数来传递上下文。

public FeedAdapter(List<Post> myDataset, Context context) {
    mDataset = myDataset;
    this.mContext = context;
}

然后在mContext需要的地方使用


5

您可以像这样使用view.getContext()

holder.tv_room_name.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Toast.makeText(v.getContext(), "", Toast.LENGTH_SHORT).show();


        }
    });


4

创建FeedAdapter的构造函数:

Context context; //global
public FeedAdapter(Context context)
{
   this.context = context;  
}

和活动中

FeedAdapter obj = new FeedAdapter(this);

2

首先添加一个全局变量

Context mContext;

然后将您的构造函数更改为此

public FeedAdapter(Context context, List<Post> myDataset) {
    mContext = context;
    mDataset = myDataset;
}

创建适配器时传递您的上下文。

FeedAdapter myAdapter = new FeedAdapter(this,myDataset);

1
View mView;
mView.getContext();

尽管这段代码可以解决问题,但包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加说明,并指出适用的限制和假设。评分
嘟嘟声
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.