Vernon Clive Kawonza Vernon Clive Kawonza - 5 months ago 16
MySQL Question

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


}

Answer

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