วิธีรับบริบทในอะแด็ปเตอร์มุมมองรีไซเคิล


130

ฉันพยายามใช้ไลบรารี 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();
    }

}

คำตอบ:


291

คุณมีทางเลือกสองสามทางที่นี่:

  1. ส่งผ่านContextเป็นอาร์กิวเมนต์ไปยัง FeedAdapter และเก็บไว้เป็นฟิลด์คลาส
  2. ใช้การฉีดแบบพึ่งพาเพื่อฉีดContextเมื่อคุณต้องการ ฉันขอแนะนำอย่างยิ่งให้อ่านเกี่ยวกับเรื่องนี้ มีเครื่องมือที่ยอดเยี่ยมสำหรับสิ่งนั้น - Dagger by Square
  3. รับจากViewวัตถุใด ๆ ในกรณีของคุณสิ่งนี้อาจได้ผลสำหรับคุณ:

    holder.pub_image.getContext()

    ตามที่pub_imageเป็นImageView.


66
ฉันชอบตัวเลือกที่สามรับบริบทจากมุมมอง เป็นวิธีแก้ปัญหาที่ง่ายและตรงไปตรงมาที่สุด
Dick Lucas

หรือที่ดีกว่านั้นคือส่งผ่านอินสแตนซ์ Picasso แทนที่จะถืออินสแตนซ์ Picasso ไว้บนอินสแตนซ์ของคลาสและขี้เกียจโหลด
Eric Cochran

8
ViewHolder แต่ละรายการมีอินสแตนซ์ของ itemView ที่คุณส่งผ่านในตัวสร้าง ใช้แบบนี้: itemView.getContext ()
Andrei Lupsa

2
คุณไม่สามารถทำ # 2 ได้หรือไม่? ฉันลองแล้ว แต่สิ่งนี้จะกลายเป็นของคุณApplicationContextและไม่เชื่อมโยงกับกิจกรรมซึ่งนำไปสู่ความผิดพลาดของรันไทม์จากภายใน Glide
boltup_im_coding

1
จะส่งออบเจ็กต์ส่วนประกอบไปยังอะแด็ปเตอร์ในกรณีที่ฉันต้องการใช้ # 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;
}

มีความสุข Codding :)


ทำงานให้ฉันด้วย! ขอบคุณ
Kenny Dabiri

21
ฉันขอแนะนำอย่างยิ่งให้ AGAINST อ้างอิงบริบททั่วโลก ซึ่งอาจนำไปสู่ปัญหาหน่วยความจำรั่วที่น่ากลัว !!
solidak

1
หากคุณเป็นผู้ดูคลาสย่อยก็สามารถเป็นแบบส่วนตัวได้
r3dm4n

หากเชื่อมต่ออะแด็ปเตอร์เข้ากับ RecyclerView บริบทนั้นจะได้รับการรับรองว่าจำเป็นต่อไป หากคุณอาจถอดอะแด็ปเตอร์ออกก็ยังใช้ได้เว้นแต่จะมีเหตุผลบางประการที่คุณมีการอ้างอิงที่ชัดเจนถึงอะแด็ปเตอร์นี้หลังจากถอดออกแล้วซึ่งในกรณีนี้คุณควรล้างบริบทที่แคชออกมีวิธีการเช่นonDetachedFromRecyclerViewหรือบางอย่าง
androidguy

20

คำตอบสั้น ๆ :

Context context;

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

คำอธิบายว่าทำไมคำตอบอื่น ๆ จึงไม่ดี:

  1. การส่งผ่านContextไปยังอะแดปเตอร์นั้นไม่จำเป็นโดยสิ้นเชิงเนื่องจากRecyclerViewคุณสามารถเข้าถึงได้จากในชั้นเรียน
  2. การได้รับContextในViewHolderระดับหมายความว่าคุณทำทุกครั้งที่คุณผูกหรือสร้างไฟล์ViewHolder. คุณทำซ้ำการดำเนินการ
  3. ฉันไม่คิดว่าคุณต้องกังวลเกี่ยวกับการรั่วไหลของหน่วยความจำ หากอะแดปเตอร์ของคุณอยู่นอกActivityอายุการใช้งานของคุณ(ซึ่งน่าจะแปลก) แสดงว่าคุณมีไฟรั่วแล้ว

ในกรณีนี้เราจะใช้onDetachedFromRecyclerView()และเผยแพร่บริบทหรือไม่?
John Pang

@JohnPang ไม่ได้จริงๆเว้นแต่คุณต้องการที่จะป้องกันอย่างมาก หากคุณเก็บข้อมูลอ้างอิงของอะแดปเตอร์ไว้ในกิจกรรมคุณจะปลอดภัย
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;  
}

และในกิจกรรม

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

แม้ว่ารหัสนี้จะช่วยแก้ปัญหาได้รวมถึงคำอธิบายว่าทำไมจึงแก้ปัญหานี้ได้จะช่วยปรับปรุงคุณภาพของโพสต์ของคุณได้อย่างแท้จริงและอาจส่งผลให้มีการโหวตเพิ่มขึ้น จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่แค่คนที่ถามตอนนี้ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้ จากรีวิว
double-beep
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.