Loader不返回数据或空光标

时间:2013-08-24 03:00:24

标签: android sqlite android-contentprovider android-cursorloader

我有两个加载器,每个加载器都从不同的内容提供商加载数据。

向片段提供来自第一内容提供者的药物ID,并且第一个加载器加载与该药物相关的所有信息。第二个加载器应该向第二个内容提供者查询与该药物相关的所有警报。

第一个加载器工作得很好,并返回所有正确的数据。但是,第二个加载器似乎返回一个空游标,即使我知道表中有大量数据应该是相关的。我说“看起来”是因为对onLoadFinished中的第二个加载器上的数据使用getCount()会导致我的应用程序崩溃,我认为这种情况发生的唯一原因是游标是否为空。

无论如何,这是我的加载器的代码。如果您需要,我可以为您提供其他任何您想要的代码。

/**
 * Initializes the loaders.
 */
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
    CursorLoader loader = null;
    long id = getArguments().getLong(ARG_MED_ID);
    switch(loaderId) {
    case 0: // MedList Loader
        Log.d("MedManager", "Loading med data");
        Uri singleUri = ContentUris.withAppendedId(MedProvider.CONTENT_URI, id);
        String[] projection = { MedTable.MED_ID,
                MedTable.MED_NAME,
                MedTable.MED_DOSAGE,
                MedTable.MED_DATE_FILLED,
                MedTable.MED_DURATION };

        loader = new CursorLoader(getActivity(), singleUri,
                projection, null, null,
                MedTable.MED_NAME + " COLLATE LOCALIZED ASC");
        break;
    case 1: // AlarmList Loader
        Log.d("MedManager", "Theoretically loading alarm list");
        Uri baseUri = AlarmProvider.CONTENT_URI;

        // Create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        String[] alarmProjection = { DailyAlarmTable.ALARM_ID,
                DailyAlarmTable.ALARM_MEDNUM,
                DailyAlarmTable.ALARM_TIME };
        String select = "((" + DailyAlarmTable.ALARM_MEDNUM + " NOTNULL) AND ("
                + DailyAlarmTable.ALARM_MEDNUM + " = " + id + "))";
        loader = new CursorLoader(getActivity(), baseUri,
                alarmProjection, select, null,
                DailyAlarmTable.ALARM_TIMESTAMP + " ASC");
        break;
    }
    return loader;
}

/**
 * Customizes the various TextViews in the layout to match
 * the values pulled from the MedTable, or swaps the alarm cursor
 * into the adapter.
 */
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    switch(loader.getId()) {
    case 0:
        setUpMedDetails(data);
        break;
    case 1:
        Log.d("MedManager", "Alarm finished loading");
        /*
         * these lines are commented out because their presence causes
         * the app to crash.
         */
        /*
        boolean isEmpty = data.getCount() < 1;
        if(isEmpty) {
            Log.d("MedManager", "No results");
        }
        */
        mAdapter.swapCursor(data);
        break;

    }
}

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    // TODO Auto-generated method stub
    if(arg0.getId() == 1) {
        mAdapter.swapCursor(null);
    }
}
编辑:为了完整性,并且因为总是存在这样的可能性,我只是一个忽视明显事物的大笨蛋,这里是我在表格中添加警报的代码:

/**
 * This function will turn the hour and day into an "HH:mm AM/PM" string,
 * calculate the timestamp, and then inserts them into the table.
 */
@Override
public void onTimePicked(int hourOfDay, int minute) {
    Log.d("MedManager", "onTimePicked triggered");
    // Convert the hour and minute into a string
    String alarmString = formatAlarmString(hourOfDay, minute);

    // Convert the hour and minute into a timestamp
    long alarmTimestamp = getAlarmTimestamp(hourOfDay, minute);

    // Define the URI to receive the results of the insertion
    Uri newUri = null;

    // Define a contentValues object to contain the new Values
    ContentValues mValues = new ContentValues();

    // Add medId;
    long medId = getIntent().getLongExtra(MedDetailFragment.ARG_MED_ID, 0);
    mValues.put(DailyAlarmTable.ALARM_MEDNUM, medId);

    // Add the timestamp
    mValues.put(DailyAlarmTable.ALARM_TIMESTAMP, alarmTimestamp);

    // Add the time string
    mValues.put(DailyAlarmTable.ALARM_TIME, alarmString);

    // Insert the new alarm
    Toast.makeText(getApplicationContext(), "medNum = " + medId, Toast.LENGTH_SHORT).show();
    Toast.makeText(getApplicationContext(), "time = " + alarmString, Toast.LENGTH_SHORT).show();
    newUri = getContentResolver().insert(AlarmProvider.CONTENT_URI, mValues);
    String uriStr = newUri.toString();
    Toast.makeText(getApplicationContext(), "Uri = " + uriStr, Toast.LENGTH_SHORT).show();

}

根据要求,这是我的AlarmProvider类。

package com.gmail.jfeingold35.medicationmanager.alarmprovider;

import java.util.Arrays;
import java.util.HashSet;

import com.gmail.jfeingold35.medicationmanager.database.AlarmDatabaseHelper;
import com.gmail.jfeingold35.medicationmanager.database.DailyAlarmTable;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

public class AlarmProvider extends ContentProvider {
// Database
private AlarmDatabaseHelper database;

// Used for the UriMatcher
private static final int ALARMS = 10;
private static final int ALARM_ID = 20;

private static final String AUTHORITY = "com.gmail.jfeingold35.medicationmanager.alarmprovider";

private static final String BASE_PATH = "medicationmanager";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY 
        + "/" + BASE_PATH);

public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE
        + "/alarms";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE
        + "/alarm";

private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
    sUriMatcher.addURI(AUTHORITY, BASE_PATH, ALARMS);
    sUriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", ALARM_ID);
}

@Override
public boolean onCreate() {
    database = new AlarmDatabaseHelper(getContext());
    return false;
}

/**
 * Perform a query from the alarm database
 */
@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {
    // Using SQLiteQueryBuilder instead of the query() method
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

    // Check if the caller requested a column which doesn't exist
    checkColumns(projection);

    // Set the table
    queryBuilder.setTables(DailyAlarmTable.TABLE_ALARM);

    int uriType = sUriMatcher.match(uri);
    switch(uriType) {
    case ALARMS:
        break;
    case ALARM_ID:
        // Adding the ID to the original query
        queryBuilder.appendWhere(DailyAlarmTable.ALARM_ID + "="
                + uri.getLastPathSegment());
        break;
    default:
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    SQLiteDatabase db = database.getWritableDatabase();
    Cursor cursor = queryBuilder.query(db, projection, selection,
            selectionArgs, null, null, sortOrder);
    // Make sure that potential listeners are getting notified
    cursor.setNotificationUri(getContext().getContentResolver(), uri);
    return null;
}

/**
 * Delete from the alarm database
 */
public int delete(Uri uri, String selection, String[] selectionArgs) {
    int uriType = sUriMatcher.match(uri);
    SQLiteDatabase db = database.getWritableDatabase();
    int rowsDeleted = 0;
    switch(uriType) {
    case ALARMS:
        rowsDeleted = db.delete(DailyAlarmTable.TABLE_ALARM, selection,
                selectionArgs);
        break;
    case ALARM_ID:
        String id = uri.getLastPathSegment();
        if(TextUtils.isEmpty(selection)) {
            rowsDeleted = db.delete(DailyAlarmTable.TABLE_ALARM, 
                    DailyAlarmTable.ALARM_ID + "=" + id, null);
        } else {
            rowsDeleted = db.delete(DailyAlarmTable.TABLE_ALARM, 
                    DailyAlarmTable.ALARM_ID + "=" + id + " and " + selection,
                    selectionArgs);
        }
        break;
    default:
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return rowsDeleted;
}

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

@Override
public Uri insert(Uri uri, ContentValues values) {
    int uriType = sUriMatcher.match(uri);
    SQLiteDatabase db = database.getWritableDatabase();
    long id = 0;
    switch(uriType) {
    case ALARMS:
        id = db.insert(DailyAlarmTable.TABLE_ALARM, null, values);
        break;
    default:
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return Uri.parse(BASE_PATH + "/" + id);
}

@Override
public int update(Uri uri, ContentValues values, String selection,
        String[] selectionArgs) {
    int uriType = sUriMatcher.match(uri);
    SQLiteDatabase db = database.getWritableDatabase();
    int rowsUpdated = 0;
    switch(uriType) {
    case ALARMS:
        rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
                values,
                selection,
                selectionArgs);
        break;
    case ALARM_ID:
        String id = uri.getLastPathSegment();
        if(TextUtils.isEmpty(selection)) {
            rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
                    values,
                    DailyAlarmTable.ALARM_ID + "=" + id,
                    null);
        } else {
            rowsUpdated = db.update(DailyAlarmTable.TABLE_ALARM,
                    values,
                    DailyAlarmTable.ALARM_ID + "=" + id + " and " + selection,
                    selectionArgs);
        }
        break;
    default:
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return rowsUpdated;
}

/**
 * Confirms that the columns the user requested exist.
 * @param projection
 */
public void checkColumns(String[] projection) {
    String[] available = { DailyAlarmTable.ALARM_ID,
            DailyAlarmTable.ALARM_MEDNUM,
            DailyAlarmTable.ALARM_TIMESTAMP,
            DailyAlarmTable.ALARM_TIME };
    if(projection != null) {
        HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
        HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
        // Check if all columns which are requested are available
        if(!availableColumns.containsAll(requestedColumns)) {
            throw new IllegalArgumentException("Unknown columsn in projection");
        }
    }
}

}

2 个答案:

答案 0 :(得分:4)

哦,好吧,我发现你在null AlarmProvider类的方法:)中返回query。让我们为此

返回光标

答案 1 :(得分:1)

如果onLoadFinished()方法通过null光标,则表示ContentProvider的{​​{1}}方法已返回query()。您需要修复null方法,以便在这种情况下不会返回query()