Проблема с контекстной нулевой ссылкой

Очень сложно объяснить.

Это ошибка, которую я получаю в своем отчете:

Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference

Кажется, что это происходит периодически, когда вы входите в фрагмент и выходите из него. Похоже, ошибка произошла в адаптере.

Вот где это называется:

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        getActivity().setTitle("Shipments");

        myView = inflater.inflate(R.layout.shipments_out_layout, container, false);

        listView = myView.findViewById(R.id.listView);

        fetchShipments();

        return myView;
    }

    /**
     * Fetch shipments
     */
    public void fetchShipments()
    {
        shipmentsService.fetchFromServer(getActivity());
    }

    /**
     * Show shipments
     */
    public void showShipments(){
        RealmResults<Shipment> savedShipments = shipmentsService.all();

        ShipmentsAdaptor adaptor = new ShipmentsAdaptor(savedShipments, this.getContext());

        listView.setAdapter(adaptor);
    }

И вот тут ошибка в адаптере:

public class ShipmentsAdaptor extends ArrayAdapter<Shipment> {

private RealmResults<Shipment> dataSet;
Context mContext;

// View lookup cache
private static class ViewHolder {
    TextView stockItemId;
    TextView technicianName;
    TextView shipmentDate;
}

public ShipmentsAdaptor(RealmResults<Shipment> data, Context context){
    super(context, R.layout.shipments_out_row_item, data);
    this.dataSet = data;
    this.mContext = context;
}

Это конкретно эта строка: super(context, R.layout.shipments_out_row_item, data);

Я подумал, что это может быть связано с тем, как мы вставляем контекст в адаптер, а затем меняем страницу до ее завершения, но это оказалось безрезультатным.

Корзина для вставки с адаптером: Адаптер

Проблема с контекстной нулевой ссылкой

Не имеет отношения к проблеме, но ... это должен быть адаптер, а не адаптер :)

Gennadii Saprykin 13.07.2018 16:05

Выложите все ошибки журнала. Пожалуйста!

Abner Escócio 13.07.2018 16:20

Добавлена ​​полная ошибка

Lewis Smith 13.07.2018 16:24

Спасибо. Но ставьте и свой полноценный адаптер. Пожалуйста!

Abner Escócio 13.07.2018 16:31

Добавил пастебин с переходником

Lewis Smith 13.07.2018 16:34

Спасибо! Я добавил новый ответ

Abner Escócio 13.07.2018 16:45
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
252
4

Ответы 4

Fragment#getContext() допускает значение NULL. Этот метод возвращает null, когда ваш фрагмент отключается от активности. Приложение вылетает из-за того, что вы создаете адаптер, а фрагмент не прикреплен, в результате чего в конструктор передается null.

Метод showShipments следует вызывать только тогда, когда фрагмент прикреплен к активности. Есть обратные вызовы onAttach() и onDetach(), которые помогут вам определить состояние. Также isAdded() возвращает логическое выражение, прикреплен ли фрагмент или нет. Выбирайте то, что вам удобно.

Удачи!

Спасибо, имеет смысл, я буду использовать приведенный выше код, чтобы узнать, работает ли это.

Lewis Smith 13.07.2018 16:13

onAttach не похоже на метод, который можно переопределить во фрагменте, я делаю это не в том месте

Lewis Smith 13.07.2018 16:19
developer.android.com/reference/android/app/…
Gennadii Saprykin 13.07.2018 16:21

Это никак не меняет мой ответ :) Но спасибо за дополнительную информацию. Решение простое - просто убедитесь, что контекст, который вы передаете адаптеру, никогда не равен нулю.

Gennadii Saprykin 13.07.2018 16:37

Могу ли я получить доступ к контексту напрямую из адаптера, чтобы избавиться от необходимости передавать его через

Lewis Smith 13.07.2018 16:45

Нет. Адаптер - это простой класс, который выполняет сопоставление данных и представлений. И ему нужен контекст, чтобы раздуть эти представления, иначе он не сможет ничего отобразить. Вам нужно получить контекст активности и передать его адаптеру. К контексту действия может получить доступ ваш фрагмент после того, как он будет прикреплен.

Gennadii Saprykin 13.07.2018 16:47

Попробуйте выполнить рефакторинг вашего адаптера с помощью BaseAdapter, как показано ниже.

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ShipmentsAdaptor extends BaseAdapter {

    private RealmResults<Shipment> dataSet;
    private Context mContext;

    // View lookup cache
    private static class ViewHolder {
        TextView stockItemId;
        TextView technicianName;
        TextView shipmentDate;
    }

    public ShipmentsAdaptor(RealmResults<Shipment> dataSet, Context context) {
        this.dataSet = dataSet;
        this.mContext = context;
    }

    @Override
    public int getCount() {
        return dataSet.size();
    }

    @Override
    public Object getItem(int position) {
        return dataSet.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Get the data item for this position
        Shipment shipment = (Shipment) getItem(position);
        // Check if an existing view is being reused, otherwise inflate the view
        ViewHolder viewHolder; // view lookup cache stored in tag

        final View result;

        if (convertView == null) {

            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.shipments_out_row_item, parent, false);
            viewHolder.stockItemId = convertView.findViewById(R.id.stockItemId);
            viewHolder.technicianName = convertView.findViewById(R.id.technicianName);
            viewHolder.shipmentDate = convertView.findViewById(R.id.shipmentDate);

            result = convertView;

            convertView.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) convertView.getTag();
            result=convertView;
        }

        lastPosition = position; //use getItemId() instead

        if (shipment != null){
            viewHolder.stockItemId.setText(String.valueOf(shipment.id));
            if (shipment.technician != null){
                viewHolder.technicianName.setText(shipment.technician.name);
            }
            viewHolder.shipmentDate.setText(shipment.shippingDate);
        }

        // Return the completed view to render on screen
        return convertView;
    }
}

Спасибо, попробуем через мгновение

Lewis Smith 13.07.2018 16:46

Вы можете проверить значение null во время настройки адаптера, чтобы избежать этого. Во фрагменте getActivity может иногда возвращает ноль в разных точках во время Жизненный цикл фрагмента. Например, в showShipments

Activity a = getActivity();
if ( a == null || a.isFinishing() ) {
    // Not in a valid state to show things anyway, so just stop and exit
    return;
}
ShipmentsAdaptor adaptor = new ShipmentsAdaptor(savedShipments, a);

Вы также можете проверить isAdded(), и если это неверно, вы можете получить null от getActivity().

Также рассмотрите возможность переноса вызова на fetchShipments() с onCreateView на onActivityCreated.

Похоже, вы вызываете fetchShipments(); до того, как будет возвращено представление макета фрагмента (myView), поэтому при создании экземпляра адаптера он имеет значение null.

Пытаться:

Переместите fetchShipments(); из onCreateView () и поместите его в onResume () или переопределите onStart () и вызовите его оттуда

Другие вопросы по теме