Как получить контекст в адаптере представления recycler


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();
    }

}

Ответы:


290

Здесь у вас есть несколько вариантов:

  1. Передайте Contextв качестве аргумента FeedAdapter и сохраните его как поле класса
  2. Используйте инъекцию зависимостей, чтобы внедрить, Contextкогда вам это нужно. Я настоятельно рекомендую прочитать об этом. Для этого есть отличный инструмент - Dagger by Square.
  3. Получите это с любого Viewобъекта. В вашем случае это может сработать для вас:

    holder.pub_image.getContext()

    Как pub_imageи файл ImageView.


64
Я предпочитаю третий вариант, получение контекста из представления. Это самое простое и понятное решение.
Dick Lucas

или, что гораздо лучше, передать экземпляр Picasso вместо того, чтобы удерживать экземпляр Picasso в экземпляре класса и лениво загружать его.
Eric Cochran

8
Каждый ViewHolder содержит экземпляр itemView, который вы передаете в конструктор. Используйте его вот так: itemView.getContext ()
Андрей Лупса

1
Вы не можете сделать №2, не так ли? Я пробовал это, но в конечном итоге это будет ваш, ApplicationContextа не привязанный к активности, что приведет к сбою во время выполнения из Glide.
boltup_im_coding 05

как передать объект компонента адаптеру, если я хочу использовать №2?
Эцио

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
Я настоятельно рекомендую ПРОТИВ иметь глобальные ссылки на Context. Это может привести к ужасным проблемам с утечкой памяти !!
solidak

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. Получение Contextна ViewHolderуровне означает, что вы делаете это каждый раз, когда связываете или создаете файл ViewHolder. Вы дублируете операции.
  3. Я не думаю, что вам нужно беспокоиться об утечке памяти. Если ваш адаптер задерживается за пределами вашего Activityсрока службы (что было бы странно), значит, у вас уже есть утечка.

В таком случае должны ли мы реализовать onDetachedFromRecyclerView()и выпустить контекст?
Джон Панг

@JohnPang - нет, если только вы не хотите защищаться. Если вы сохраните ссылку на адаптер в Activity, вы в безопасности.
Maciej Beimcik

17

Вы можете использовать pub_image context ( 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(); 

Примечание. Родитель - это 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;  
}

и в Activity

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();

Хотя этот код может решить вопрос, в том числе объяснение того, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, приведет к большему количеству голосов за. Помните, что вы отвечаете на вопрос для будущих читателей, а не только для человека, который задает его сейчас. Пожалуйста , измените свой ответ , чтобы добавить объяснения и дать указание о том , что применять ограничения и допущения. Из отзыва
двойной гудок
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.