Что такое RecyclerView.Adapter а чем он отличается от RecyclerView.Adapter в Android? - PullRequest
0 голосов
/ 26 января 2020

Я изучаю RecyclerView и на сайте разработчика класс Адаптер расширяет RecyclerView.Adapter<MyAdapter.MyViewHolder>. Реализация показывает:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private String[] mDataset;


public static class MyViewHolder extends RecyclerView.ViewHolder {

    public TextView textView;
    public MyViewHolder(TextView v) {
        super(v);
        textView = v;
    }
}

public MyAdapter(String[] myDataset) {
    mDataset = myDataset;
}

@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                               int viewType) {

    TextView v = (TextView) LayoutInflater.from(parent.getContext())
            .inflate(R.layout.my_text_view, parent, false);

    MyViewHolder vh = new MyViewHolder(v);
    return vh;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {

    holder.textView.setText(mDataset[position]);

}

@Override
public int getItemCount() {
    return mDataset.length;
}
}

И в этом учебнике класс адаптера расширяется RecyclerView.Adapter. Реализация:

public class SimpleAdapter extends RecyclerView.Adapter {

private List<SimpleViewModel> models = new ArrayList<>();


public SimpleAdapter(final List<SimpleViewModel> viewModels) {
    if (viewModels != null) {
        this.models.addAll(viewModels);
    }
}


@Override
public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
    return new SimpleViewHolder(view);
}


@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
    ((SimpleViewHolder) holder).bindData(models.get(position));
}


@Override
public int getItemCount() {
    return models.size();
}


@Override
public int getItemViewType(final int position) {
    return R.layout.item_simple_itemview;
}
}

Так в чем же разница между RecyclerView.Adapter<MyAdapter.MyViewHolder> и RecyclerView.Adapter и что означает синтаксис <> в RecyclerView.Adapter<MyAdapter.MyViewHolder> в этом случае? Я знаю, что это обозначает дженерики. Когда я должен использовать это?

1 Ответ

1 голос
/ 26 января 2020

Так в чем же разница между RecyclerView.Adapter и RecyclerView.Adapter и что означает синтаксис <> в RecyclerView.Adapter в этом случае? Я знаю, что это обозначает дженерики. Когда я должен использовать это?

Сначала давайте рассмотрим определение класса Adapter. Он определен в RecyclerView следующим образом:

public abstract static class Adapter<VH extends ViewHolder>

Так что же означает часть «дженерики»? Это означает, что класс Adapter работает с некоторым типом класса (VH), который должен быть потомком класса ViewHolder. Это известно как Ограниченный тип и гарантирует, что тип класса, с которым работает адаптер, гарантированно будет иметь тип ViewHolder.

. Вы видите в примере на сайте разработчика, который вы разместили, когда вы создаете свой собственный адаптер, который задает тип ViewHolder как MyViewHolder, то методы, которые вы должны переопределить в адаптере, явно объявляют этот тип в своих сигнатурах. Например, тип возвращаемого значения для onCreateViewHolder явно установлен на MyViewHolder.

@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                               int viewType) {

    TextView v = (TextView) LayoutInflater.from(parent.getContext())
            .inflate(R.layout.my_text_view, parent, false);

    MyViewHolder vh = new MyViewHolder(v);
    return vh;
}

В качестве альтернативы, учебник, который вы опубликовали, не указывает тип.

public class SimpleAdapter extends RecyclerView.Adapter

Когда вы расширяете класс, который ожидает обобщенный тип c и не указывает его, компилятор по умолчанию использует наименьший общий знаменатель - то есть тип класса с наименьшим значением в иерархии наследования, который гарантирует, что класс может использоваться по назначению. Поскольку тип generic c Адаптера определен как VH extends ViewHolder, компилятор знает, что тип класса должен быть не менее a ViewHolder, и по умолчанию используется этот тип. Следовательно, тот же метод, переопределенный для этого примера, возвращает RecyclerView.ViewHolder вместо MyViewHolder:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
    return new SimpleViewHolder(view);
}

Если RecyclerView.Adapter был определен как Adapter<VH> (без ограниченного типа), и вы расширили его без указания тип, тип по умолчанию будет Object (root класс всех Java классов):

@Override
public Object onCreateViewHolder(final ViewGroup parent, final int viewType) {
    final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
    return new SimpleViewHolder(view);
}

Итак, наконец, зачем использовать одно вместо другого? Вообще говоря: вы всегда должны указывать тип для обобщенного c класса . Это гарантирует вам безопасность типов. В учебном примере вы можете вернуть неправильный тип держателя вида, который скомпилируется, но будет иметь sh во время выполнения:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);

    // Returning wrong view holder, but because it still extends ViewHolder and
    // that is all this method requires, this compiles
    return new SomeOtherViewHolder(view);
}


@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
    // Above we created a SomeOtherViewHolder but here we're expecting a SimpleViewHolder
    // This will crash trying to cast to the wrong type
    ((SimpleViewHolder) holder).bindData(models.get(position));
}

Невозможно сделать эту ошибку в первом примере, потому что ViewHolder тип объявлен явно:

@Override
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                               int viewType) {

    TextView v = (TextView) LayoutInflater.from(parent.getContext())
            .inflate(R.layout.my_text_view, parent, false);

    // Trying to return SomeOtherViewHolder when method expects MyViewHolder
    // Compiler's like (*waves finger*) "nuh-uh, not on my watch" and fails
    // to compile
    SomeOtherViewHolder vh = new SomeOtherViewHolder(v);
    return vh;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    // Notice here that holder is explicitly of MyViewHolder type and casting
    // is not necessary! That's TYPE SAFETY y'all.
    holder.textView.setText(mDataset[position]);
}

Поскольку вы указываете ожидаемый тип явный , конкретный , вы не можете случайно вернуть неправильный тип, вам не нужно приведение, и вы можете использовать все методы publi c, определенные в вашем пользовательском ViewHolder классе.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...