Выражение может иметь значение null, но возвращается методом, объявленным как @NotNull - PullRequest
0 голосов
/ 10 октября 2018

После создания адаптера RecyclerView возвращается предупреждение о держателе моего представления.Я прочитал этот вопрос и немного его понимаю, но не ясно, какой экземпляр viewHolder в return viewHolder; следует заменить на

Выражение можетоценивается как ноль, но возвращается методом, объявленным как @ NotNull

public class MyRVAapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private final static int TYPE_EXPANDABLE = 1, TYPE_NONEXPANDABLE = 2;
    private ArrayList callSMSFeed = new ArrayList();
    private Context context;

    public MyRVAapter(Context context){
        this.context = context;
    }

    public void setCallSMSFeed(List<Object> callSMSFeed){
        this.callSMSFeed = (ArrayList) callSMSFeed;
    }

  @Override
    public int getItemViewType(int position) {
        if (callSMSFeed.get(position) instanceof Phonecall) {
            return TYPE_EXPANDABLE;
        } else if (callSMSFeed.get(position) instanceof SMSmessage) {
            return TYPE_NONEXPANDABLE;
        }
        return -1;
    }

    @Override
    public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
        int viewType=holder.getItemViewType();
        switch (viewType){
            case TYPE_EXPANDABLE:
                Phonecall call = (Phonecall) callSMSFeed.get(position);
                ((CallViewHolder)holder).showCallDetails(call);
                break;
            case TYPE_NONEXPANDABLE:
                SMSmessage sms = (SMSmessage)callSMSFeed.get(position);
                ((SMSViewHolder)holder).showSmsDetails(sms);
                break;
        }
    }

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

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {


        int layout;

        RecyclerView.ViewHolder viewHolder;
        switch (viewType){
            case TYPE_EXPANDABLE:
                layout = R.layout.cardview_a;
                View callsView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new CallViewHolder(callsView);
                break;
            case TYPE_NONEXPANDABLE:
                layout = R.layout.cardview_b;
                View smsView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new SMSViewHolder(smsView);
                break;
            default:
                viewHolder = null;
                break;
        }
        return viewHolder;
    }
}

Ответы [ 4 ]

0 голосов
/ 10 октября 2018

Мне нравится ответ @ TheWanderer, но я хотел добавить еще один, чтобы выделить то, что, как мне кажется, облегчит вашу жизнь.

В отличие от ListView, RecyclerView не волнует, какие ценности вывозврат от getItemViewType();пока вы возвращаете различные значения из этого метода, RecyclerView счастлив.Это позволяет вам использовать идентификаторы ресурсов макета в качестве возвращаемых значений, что означает, что вам никогда не придется определять свои собственные константы!

@Override
public int getItemViewType(int position) {
    Object obj = callSMSFeed.get(position);

    if (obj instanceof Phonecall) {
        return R.layout.cardview_a;
    } else if (obj instanceof SMSmessage) {
        return R.layout.cardview_b;
    }

    throw new IllegalStateException("item at position " + position + " is not a Phonecall or SMSmessage: " + obj);
}

Здесь мы возвращаем R.layout.cardview_a вместо TYPE_EXPANDABLE;оба находятся под капотом int, но теперь мы можем позволить структуре ресурсов позаботиться о том, чтобы определить их для нас.

Мы также выдаем исключение, если когда-нибудь попадем в Object, который не являетсяPhonecall или SMSmessage, чтобы мы сразу знали, что есть дело, которое нам нужно рассмотреть.Такое исключение следует видеть только разработчикам, совершающим ошибки;приложение никогда не будет зависать от пользователя, потому что вы продолжите и исправите его, прежде чем выпустить приложение.

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

    switch (viewType) {
        case R.layout.cardview_a:
            return new CallViewHolder(itemView);

        case R.layout.cardview_b:
            return new SMSViewHolder(itemView);

        default:
            throw new IllegalArgumentException("unexpected viewType: " + viewType);
    }
}

Поскольку мы вернули идентификаторы макетов из getItemViewType(), у нас нетбеспокоиться о переводе наших собственных констант в значения R.layout;мы можем просто надуть viewType напрямую.Нам по-прежнему нужен оператор switch, чтобы знать, какой тип ViewHolder должен быть возвращен.

Опять же, мы бросили здесь исключение на случай, если нам когда-нибудь передадут viewType, которого мы не ожидаем,Этого «не произойдет», но если он когда-либо сделает , будет очень ясно, где проблема, и вам будет легко ее исправить.

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    int viewType = holder.getItemViewType();

    switch (viewType) {
        case R.layout.cardview_a:
            Phonecall call = (Phonecall) callSMSFeed.get(position);
            ((CallViewHolder) holder).showCallDetails(call);
            break;

        case R.layout.cardview_b:
            SMSmessage sms = (SMSmessage) callSMSFeed.get(position);
            ((SMSViewHolder) holder).showSmsDetails(sms);
            break;

        default:
            throw new IllegalArgumentException("unexpected viewType: " + viewType);
    }
}

Здесь единственная разницазамена ваших констант идентификаторами макета внутри switch.Ничего страшного.И, конечно, мы терпим крах, если получаем что-то, чего не ожидаем.

Обратите внимание, что я удалил ключевое слово final из параметров.Хотя компилятор с радостью позволит вам добавить их, вы не должны этого делать.Из-за таких методов, как notifyItemInserted(), позиция ViewHolder может меняться с течением времени без повторного связывания.Решение этой проблемы выходит за рамки вашего вопроса, но на это следует обратить внимание.

0 голосов
/ 10 октября 2018

У вас есть это

@NonNull

перед вашим onCreateViewHolder.В предупреждающем сообщении четко указывается, что вам необходимо убедиться, что вы возвращаете что-то, что не null.В случае default, viewHolder действительно равно null, вы можете вернуть действительное значение или вызвать исключение в этом случае.

0 голосов
/ 10 октября 2018

у вас есть это предупреждение, потому что метод

public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

не должен возвращать ноль, но в вашем случае по умолчанию вы возвращаете нуль

default:
                viewHolder = null;
                break;

При производстве случай по умолчанию приведетк аварии, и поэтому предупреждение повышается.Вы должны сгенерировать исключение времени выполнения или вернуть ненулевое представление по умолчанию.

0 голосов
/ 10 октября 2018

@ NonNull - это просто флаг IDE (используется для перекрестной совместимости Kotlin).Это не намного больше, чем просто информирование IDE о том, когда следует и не следует предупреждать вас о возможных нулевых указателях.

То, что вы объявляете это, не означает, что ваш метод будет возвращать ненулевое значение.Конечно, ваш будет только из-за того, как это работает, но IDE не настолько умна.Все, что он видит, это противоречие: вы используете параметр @NonNull, но у вас также есть случай, когда вы возвращаете нулевое значение.

Самый простой способ исправить это - просто заменить ваш * 1006.* case с тем, что находится под TYPE_EXPANDABLE или TYPE_NONEXPANDABLE и удалите лишний регистр, то есть:

EDIT: Из комментария Бена Р также было бы хорошей идеей добавить исключение в ваш onCreateViewHolderMethod() если текущий тип представления является неожиданным.

switch (viewType){
    case TYPE_EXPANDABLE:
        layout = R.layout.cardview_a;
        View callsView = LayoutInflater
                .from(parent.getContext())
                .inflate(layout, parent, false);
        viewHolder = new CallViewHolder(callsView);
        break;
    case TYPE_NONEXPANDABLE:
        layout = R.layout.cardview_b;
        View smsView = LayoutInflater
                .from(parent.getContext())
                .inflate(layout, parent, false);
        viewHolder = new SMSViewHolder(smsView);
        break;
    default:
        throw IllegalArgumentException("Invalid View type: " + viewType);
}

Это не самый элегантный, но если вы точно знаете, что getItemViewType() никогда не вернет -1, вы выиграли 'Я не могу прибегнуть к какому-либо странному поведению.

Я бы добавил к этому еще одну вещь, просто чтобы вы могли быть уверены, что получите то, что хотите.Вместо этого:

@Override
public int getItemViewType(int position) {
    if (callSMSFeed.get(position) instanceof Phonecall) {
        return TYPE_EXPANDABLE;
    } else if (callSMSFeed.get(position) instanceof SMSmessage) {
        return TYPE_NONEXPANDABLE;
    }
    return -1;
}

Попробуйте:

@Override
public int getItemViewType(int position) {
    if (callSMSFeed.get(position) instanceof Phonecall) {
        return TYPE_EXPANDABLE;
    } else if (callSMSFeed.get(position) instanceof SMSmessage) {
        return TYPE_NONEXPANDABLE;
    }
    throw new IllegalArgumentException("Item at position " + position + " is not an instance of either Phonecall or SMSmessage");
}

Примечание. Вы можете использовать любой тип исключения, который вы считаете подходящим для данного случая.Я использую IllegalArgumentException, Бен П (из комментариев) может использовать IllegalStateException ... вы можете даже просто выбросить Exception.

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