上下文空引用问题

时间:2018-07-13 13:55:23

标签: java android nullpointerexception adaptor

一个很难解释的东西。

这是我在报告中遇到的错误:

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);

我认为这可能与我们将上下文插入适配器,然后在页面完成之前更改页面的方式有关,但是事实证明这没有定论。

带有适配器的粘贴容器:Adaptor

enter image description here

4 个答案:

答案 0 :(得分:1)

Fragment#getContext()可为空。当您的片段与活动分离时,此方法返回null。该应用程序崩溃是因为您在未附加片段的情况下创建了适配器,从而导致null传递给了构造函数。

仅在将片段附加到活动时才应调用方法showShipments。有回调onAttach()onDetach()可以帮助您检测状态。此外,isAdded()还向您返回一个布尔值,说明是否附加了该片段。选择最方便的方式。

祝你好运!

答案 1 :(得分:0)

请按照以下说明尝试使用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;
    }
}

答案 2 :(得分:0)

您可以在适配器设置过程中检查是否为空以避免这种情况。在一个片段中,getActivity可以sometimes return nullFragment lifecycle的不同点上。例如,在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(),如果该值为假,则可以从getActivity()中获取空值。

另外,请考虑将呼叫fetchShipments()onCreateView转移到onActivityCreated

答案 3 :(得分:0)

好像您在返回片段布局视图(myView)之前正在调用fetchShipments();,因此在实例化适配器时它为null。

尝试:

从onCreateView()中移动fetchShipments();并将其放在onResume()中,或覆盖onStart()并从那里调用它