Search code examples
mysqlsqliteandroid-contentproviderandroid-loadermanager

cursor throwing nullpointer when called from content provider


Im trying to query data from two different tables using a LoaderManager in a ListFragment. My tables definetely have data, i checked, but for some reason my query/cursor is returning null. I suspect its a syntax issue but im not entirely sure. I ran the same query in MySql Workbench, and it worked. Iv tried running the query like this:

cursor = db.query("Customer, Appointment", new String[]{"fullname", "physicalAddress", "date","time"}, "Customer.ID IN(?)", new String[]{"select customerID from Appointment"},null,null,null);

and this:

cursor = db.rawQuery("select fullName, physicalAddress, date, time from Customer, Appointment where Customer.ID IN(select customerID from Appointment);", null);

But everytime this line of code runs:

cursor.setNotificationUri(getContext().getContentResolver(), uri);

i get a nullpointer. In case this means anything, im not using a FrameLayout and dynamically adding my ListFragment. Iv defined it in the Activities xml file. Any help is appreciated. Please let me know if iv left anything out.

DatabaseContentProvider:

package com.venon.nakomangsp;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.Nullable;

@SuppressWarnings("ConstantConditions")
public class DatabaseContentProvider extends ContentProvider {

DatabaseHelper dbHelper;
private static final String PROVIDER_NAME = "com.venon.nakomangsp.databasecontentprovider";
private static final UriMatcher uriMatcher;
public static final Uri CUSTOMER_URI = Uri.parse("content://"+ PROVIDER_NAME+"/Customer");
private static final int CUSTOMER_CODE = 1;
public static final Uri APPOINTMENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/Appointment");
private static final int APPOINTMENT_CODE = 2;
public static final Uri APPOINTMENT_VIEW_URI = Uri.parse("content://" + PROVIDER_NAME + "/AppointmentView");
private static final int APPOINTMENT_VIEW_CODE = 3;

static{
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(PROVIDER_NAME,"Customer", CUSTOMER_CODE);
    uriMatcher.addURI(PROVIDER_NAME, "Appointment", APPOINTMENT_CODE);
}


@Override
public boolean onCreate() {
    dbHelper = new DatabaseHelper(getContext());
    return true;
}

@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {

    SQLiteDatabase db = dbHelper.getWritableDatabase();
    Cursor cursor = null;

    switch(uriMatcher.match(uri)){

        case CUSTOMER_CODE:
            cursor = db.query("Customer", projection, selection, selectionArgs, null, null, sortOrder);
            break;

        case APPOINTMENT_CODE:
            cursor = db.query("Appointment", projection, selection, selectionArgs, null, null, sortOrder);
            break;

        case APPOINTMENT_VIEW_CODE://this is the case triggered
            //cursor = db.rawQuery("select fullName, physicalAddress, date, time from Customer, Appointment where Customer.ID IN(select customerID from Appointment);", null);

            cursor = db.query("Customer, Appointment", new String[]{"fullname", "physicalAddress", "date","time"}, "Customer.ID IN(?)", new String[]{"select customerID from Appointment"},null,null,null);

        default:
            break;

    }

    cursor.setNotificationUri(getContext().getContentResolver(), uri);

    return cursor;
}

@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {

    SQLiteDatabase db = dbHelper.getWritableDatabase();

    switch(uriMatcher.match(uri)){

        case CUSTOMER_CODE:
            db.insertOrThrow("Customer", null, values);
            break;

        case APPOINTMENT_CODE:
            db.insertOrThrow("Appointment", null, values);
            break;

        default:
            break;

    }

    getContext().getContentResolver().notifyChange(uri, null, false);//set to true when syncadapter hooked up
    return null;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {

    SQLiteDatabase db = dbHelper.getWritableDatabase();

    switch(uriMatcher.match(uri)){

        case CUSTOMER_CODE:
            db.delete("Customer", selection, selectionArgs);
            break;

        case APPOINTMENT_CODE:
            db.delete("Appointment", selection, selectionArgs);
            break;

        default:
            break;

    }

    getContext().getContentResolver().notifyChange(uri, null, false);//keep as false when hooking up syncadapter
    return 0;
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {

    SQLiteDatabase db = dbHelper.getWritableDatabase();

    switch(uriMatcher.match(uri)){

        case CUSTOMER_CODE:
            db.update("Customer", values, selection, selectionArgs);
            break;

        case APPOINTMENT_CODE:
            db.update("Appointment", values, selection, selectionArgs);
            break;

        default:
            break;

    }
    getContext().getContentResolver().notifyChange(uri, null, false);
    return 0;
}

@Nullable
@Override
public String getType(Uri uri) {
    return null;
}
}

Calling Code:

package com.venon.nakomangsp;


import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;


public class AppointmentListFragment extends ListFragment implements     LoaderManager.LoaderCallbacks<Cursor> {
SimpleCursorAdapter adapter;

public static AppointmentListFragment newInstance() {
    AppointmentListFragment fragment = new AppointmentListFragment();

    return fragment;
}

public AppointmentListFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
       // mParam1 = getArguments().getString(ARG_PARAM1);
       // mParam2 = getArguments().getString(ARG_PARAM2);
    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_appointment_list, container, false);

    String[] from = {"fullName", "physicalAddress", "date", "time"};
    int[] to = {R.id.customerName_lv, R.id.physicalAddress_lv, R.id.date_lv, R.id.time_lv};
    adapter = new SimpleCursorAdapter(getContext(), R.layout.appointment_list, null, from, to, 0);
    setListAdapter(adapter);

    getActivity().getSupportLoaderManager().initLoader(0, null, AppointmentListFragment.this);

    return view;
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);

    getActivity().startActivity(new Intent(getContext(), AppointmentViewActivity.class));
}

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    //this is the calling line
    return new CursorLoader(getContext(), DatabaseContentProvider.APPOINTMENT_VIEW_URI, null, null, null, null);
}

@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {

    adapter.swapCursor(cursor);
}

@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
    adapter.swapCursor(null);
}


}

Solution

  • if your uri does not match one of the three case elements, Cursor will be null and you get a NPE:

    switch(uriMatcher.match(uri)){
    
        case CUSTOMER_CODE:
            cursor = db.query("Customer", projection, selection, selectionArgs, null, null, sortOrder);
            break;
    
        case APPOINTMENT_CODE:
            cursor = db.query("Appointment", projection, selection, selectionArgs, null, null, sortOrder);
            break;
    
        case APPOINTMENT_VIEW_CODE://this is the case triggered
            //cursor = db.rawQuery("select fullName, physicalAddress, date, time from Customer, Appointment where Customer.ID IN(select customerID from Appointment);", null);
    
            cursor = db.query("Customer, Appointment", new String[]{"fullname", "physicalAddress", "date","time"}, "Customer.ID IN(?)", new String[]{"select customerID from Appointment"},null,null,null);
    
        default:
            break;
    
    }
    
    cursor.setNotificationUri(getContext().getContentResolver(), uri);
    

    The best way is to throw an IllegalArgument exception in default.

        default:
            throw new IllegalArgumentException("unknown uri");