Accessing items in CardView after it has been crea

2019-08-15 23:40发布

问题:

i'm trying to figure out how to modify a certain ImageView or TextView widget in a CardView after i created it and passed it to the main RecyclerView.

So my code is as follows :

First the class that holds the items :

 public class MovieDetails {
    protected static String title;
    protected static Bitmap imageViewPoster;
    protected static Bitmap imageViewFanart;}

Now i have the RecyclerView Adapter that also holds the ViewHolder inner class like this :

public class MovieDetailsAdapter extends RecyclerView.Adapter<MovieDetailsAdapter.MovieViewHolder> {

       private List<MovieDetails> movieList;

public MovieDetailsAdapter(List<MovieDetails> movietList) {

    this.movieList = movietList;
}

@Override
public int getItemCount() {

    return movieList.size();
}

@Override
public MovieViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View itemView = LayoutInflater.
            from(viewGroup.getContext()).
            inflate(R.layout.card_layout_movies, viewGroup, false);

    return new MovieViewHolder(itemView);
}

@Override
public void onBindViewHolder(MovieViewHolder movieViewHolder, int i) {

    MovieDetails md = movieList.get(i);

    movieViewHolder.vTitle.setText(md.title);      
    movieViewHolder.vPoster.setImageBitmap(md.imageViewPoster);
    movieViewHolder.vFanart.setImageBitmap(md.imageViewFanart);

}


public static class MovieViewHolder extends RecyclerView.ViewHolder {

    protected TextView vTitle;
    protected ImageView vPoster;
    protected ImageView vFanart;

    public MovieViewHolder(View v)
    {
        super(v);
        vTitle = (TextView)v.findViewById(R.id.title);
        vPoster = (ImageView) v.findViewById(R.id.imageViewPoster);
        vFanart = (ImageView) v.findViewById(R.id.imageViewFanart);

    }
}} 

And now my main Activity class, where i am setting the layout and view and creating the MovieList array of objects.

public class MoviesListActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_movies_list);
    RecyclerView recList = (RecyclerView) findViewById(R.id.cardList);
    recList.setHasFixedSize(true);
    LinearLayoutManager llm = new LinearLayoutManager(this);
    llm.setOrientation(LinearLayoutManager.VERTICAL);
    recList.setLayoutManager(llm);

    MovieDetailsAdapter ca = new MovieDetailsAdapter(createList(5));
    recList.setAdapter(ca);

}

private List<MovieDetails> createList(int size){

    List<MovieDetails> moviedetailsList =  new ArrayList<MovieDetails>();

    for (int i=1; i <= size; i++) {
        MovieDetails moviedetails = new MovieDetails();
        moviedetails.title= "Name" +i;

        Bitmap bit = resizeBitmap(getResources(), R.drawable.poster_example, 640, 955);
        moviedetails.imageViewPoster = bit;

        Bitmap bit2 = resizeBitmap(getResources(), R.drawable.fanart_example, 800, 450);
        moviedetails.imageViewFanart = bit2;

        moviedetailsList.add(moviedetails);
    }
    return  moviedetailsList;
}

resizeBitmap is another function i use for resizing the images, irrelevant to the question, i edited it out.

Now, one i've created this CardView list, is there any way to modify the ImageView and TextViews inside it from the main Activity class ? I want to to this since i`m using AsyncTask to retrieve the new images i want to replace, so i first have to initialize the Bitmaps with some "default" images, and then later one modify them from the results of the AsyncTask used to retrieve them from the server.

Searched around google, found dozens of tutorials around CardViews but nothing regarding this, any help is appreciated, thanks.

回答1:

The CardView does not care. It is just like a LinearLayout. It does not need any different treatment than a standard RecyclerView.

First, you need to have and modify only one List<MovieDetails> and only one MovieDetailsAdapter for this to work. (You can keep your work in a temporary one if you need).

So, you should make the List public static in the code of the adapter.

Then in the Activity, instead of

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    MovieDetailsAdapter ca = new MovieDetailsAdapter(createList(5));
    ...
}

do

private MovieDetailsAdapter ca;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    ca = new MovieDetailsAdapter(createList(5));
    ...
}

Move the createList's generic MovieDetails (using the size) to another method (I'll call it makeGenericMovieDetails()). (In the createList, just replace this in the for loop.)

private MovieDetails makeGenericMovieDetails() {
    MovieDetails moviedetails = new MovieDetails();
    // The size of the list, but add one.
    moviedetails.title= "Name" + (adapter.getSize() + 1);

    Bitmap bit = resizeBitmap(getResources(), R.drawable.poster_example, 640, 955);
    moviedetails.imageViewPoster = bit;

    Bitmap bit2 = resizeBitmap(getResources(), R.drawable.fanart_example, 800, 450);
   moviedetails.imageViewFanart = bit2; 
return moviedetails;
}

Now when you want to change it, do this (once you resized it):

private void setMovieDetails(@Nullable Bitmap poster, @Nullable Bitmap fanart, @Nullable String title, int id) { 
    MovieDetails details;
    boolean isAlreadyThere = true;
    try {
        details = ca.movieList.get(id);
    } catch (IndexOutOfBoundsException e) {
        isAlreadyThere = false;
        // If we come with a bad ID we crash. No fun.
        details = makeGenericMovieDetails();
    }
    if (poster != null)
        details.imageViewPoster = poster;
    if (fanart != null)
        details.imageViewFanart = fanart;
    if (title != null)
        details.Title = title;
    ca.movieList.set(id, details);

    if (isAlreadyThere) {
        ca.notifyItemChanged(id);
    } else {
        ca.notifyItemInserted(id);
    }
}

The key line here is

ca.notifyItemChanged(id);

which tells the adapter to update that item.

I hope this works, I am doing this from StackExchange's app off hand and it keeps losing the draft, so test first.

Now, when you want to change the pic, just call setMovieDetails(poster, fanart, title, id); and pass null for a value you do not want to change. (Except id).

BTW try to make variables start with a lowercase letter. So instead of Title do something like title or mTitle. It looks better and makes it easier to distinguish.