Так в чем же разница между 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
классе.
Надеюсь, это поможет!