【问题标题】:Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference [duplicate]尝试在空对象引用上调用接口方法“int android.database.Cursor.getCount()”[重复]
【发布时间】:2017-02-19 04:06:47
【问题描述】:

我确实有一个让我头疼的问题。我通过自定义内容提供程序将我所在城市的一些图像存储在 sqlite 数据库中。但是,当我运行我的应用程序时,我得到一个空光标。

Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference
                                                 at theo.testing.androidcustomloaders.fragments.MainActivityFragment.onActivityCreated(MainActivityFragment.java:74)
                                                 at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:2089)
                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1133)
                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1290)
                                                 at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)
                                                 at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1677)
                                                 at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388)
                                                 at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:604)
                                                 at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
                                                 at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1220)
                                                 at android.app.Activity.performStart(Activity.java:5992)
                                                 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2261)
                                                 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2358) 
                                                 at android.app.ActivityThread.access$800(ActivityThread.java:144) 
                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278) 
                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                 at android.os.Looper.loop(Looper.java:135) 
                                                 at android.app.ActivityThread.main(ActivityThread.java:5219) 
                                                 at java.lang.reflect.Method.invoke(Native Method) 
                                                 at java.lang.reflect.Method.invoke(Method.java:372) 
                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898) 
                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693) 

这意味着信息存储不正确,或者我的提供商的 Uri 存在某种错误。所以。

MyCityContract

public class MyCityContract {

public static final String CONTENT_AUTHORITY = "theo.testing.customloaders";

public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);

public static final class MyCityEntry implements BaseColumns{
    //table name
    public static final String TABLE_MY_CITY = "my_city";
    //columns
    public static final String _ID = "_id";
    public static final String COLUMN_NAME = "name";
    public static final String COLUMN_ICON = "icon";

    // create content uri
    public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
            .appendPath(TABLE_MY_CITY).build();
    // create cursor of base type directory for multiple entries
    public static final String CONTENT_DIR_TYPE =
            ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + TABLE_MY_CITY;
    // create cursor of base type item for single entry
    public static final String CONTENT_ITEM_TYPE =
            ContentResolver.CURSOR_ITEM_BASE_TYPE +"/" + CONTENT_AUTHORITY + "/" + TABLE_MY_CITY;

    // for building URIs on insertion
    public static Uri buildFlavorsUri(long id){
        return ContentUris.withAppendedId(CONTENT_URI, id);
    }

  }
}

MyCityDbHelper

public class MyCityDbHelper  extends SQLiteOpenHelper{
public static final String LOG_TAG = MyCityDbHelper.class.getSimpleName();
//name & version
public static final String DATABASE_NAME = "city.db";
public static final int DATABASE_VERSION = 4;
// Create the database
public MyCityDbHelper(Context context) {
    super(context, DATABASE_NAME,null,DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
    final String SQL_CREATE_MY_CITY_TABLE = "CREATE TABLE " +
            MyCityContract.MyCityEntry.TABLE_MY_CITY + "(" + MyCityContract.MyCityEntry._ID +
            " INTEGER PRIMARY KEY AUTOINCREMENT, " +
            MyCityContract.MyCityEntry.COLUMN_NAME + " TEXT NOT NULL, " +
            MyCityContract.MyCityEntry.COLUMN_ICON + " INTEGER NOT NULL);";


    sqLiteDatabase.execSQL(SQL_CREATE_MY_CITY_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
    Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " +
            newVersion + ". OLD DATA WILL BE DESTROYED");
    // Drop the table
    sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + MyCityContract.MyCityEntry.TABLE_MY_CITY);
    sqLiteDatabase.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
            MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");

    // re-create database
    onCreate(sqLiteDatabase);
   }
}

MyCityProvider

public class MyCityProvider extends ContentProvider {
private static final String LOG_TAG = MyCityProvider.class.getSimpleName();
private static final UriMatcher sUriMatcher = buildUriMatcher();
private MyCityDbHelper myCityDbHelper;

//Codes for UriMatcher
private static final int MY_CITY = 100;
private static final int MY_CITY_WITH_ID = 200;


private static UriMatcher buildUriMatcher(){
    // Build a UriMatcher by adding a specific code to return based on a match
    // It's common to use NO_MATCH as the code for this case.
    final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    final String authority = MyCityContract.CONTENT_AUTHORITY;

    //add code for each URI


 matcher.addURI(authority,MyCityContract.MyCityEntry.TABLE_MY_CITY,MY_CITY);
    matcher.addURI(authority,MyCityContract.MyCityEntry.TABLE_MY_CITY + "/#",MY_CITY_WITH_ID);

    return matcher;

}
@Override
public boolean onCreate() {
    myCityDbHelper = new MyCityDbHelper(getContext());

    return true;
}

@Override
public String getType(Uri uri) {
    final int match = sUriMatcher.match(uri);

    switch (match){
        case MY_CITY: {
            return MyCityContract.MyCityEntry.CONTENT_DIR_TYPE;
        }
        case MY_CITY_WITH_ID:{
            return MyCityContract.MyCityEntry.CONTENT_ITEM_TYPE;

        }
        default:{
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){
    Cursor retCursor;
    switch(sUriMatcher.match(uri)){
        // All Flavors selected
        case MY_CITY:{
            retCursor = myCityDbHelper.getReadableDatabase().query(
                    MyCityContract.MyCityEntry.TABLE_MY_CITY,
                    projection,
                    selection,
                    selectionArgs,
                    null,
                    null,
                    sortOrder);
            return retCursor;
        }
        // Individual flavor based on Id selected
        case MY_CITY_WITH_ID:{
            retCursor = myCityDbHelper.getReadableDatabase().query(
                    MyCityContract.MyCityEntry.TABLE_MY_CITY,
                    projection,
                    MyCityContract.MyCityEntry._ID + " = ?",
                    new String[] {String.valueOf(ContentUris.parseId(uri))},
                    null,
                    null,
                    sortOrder);
            return retCursor;
        }
        default:{
            // By default, we assume a bad URI
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }
}




@Override
public Uri insert(Uri uri, ContentValues contentValues) {
    final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();

    Uri returnUri;

    switch (sUriMatcher.match(uri)){
        case MY_CITY:

            long _id = db.insert(MyCityContract.MyCityEntry.TABLE_MY_CITY,null,contentValues);
            Log.d("id",String.valueOf(_id));
            // insert unless it is already contained in the database
            if(_id>0){
                returnUri = MyCityContract.MyCityEntry.buildFlavorsUri(_id);
            }else {
                throw new android.database.SQLException("Failed to insert row into: " + uri);
            }
            break;
        default: {
            throw  new UnsupportedOperationException("Unknown uri: " + uri );
        }
    }

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

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
    final int match = sUriMatcher.match(uri);
    int numDeleted;
    switch(match){
        case MY_CITY:
            numDeleted = db.delete(
                    MyCityContract.MyCityEntry.TABLE_MY_CITY, selection, selectionArgs);
            // reset _ID
            db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
                    MyCityContract.MyCityEntry.TABLE_MY_CITY + "'");
            break;
        case MY_CITY_WITH_ID:
            numDeleted = db.delete(MyCityContract.MyCityEntry.TABLE_MY_CITY,
                    MyCityContract.MyCityEntry._ID + " = ?",
                    new String[]{String.valueOf(ContentUris.parseId(uri))});
            // reset _ID
            db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
                    MyCityContract.MyCityEntry.TABLE_MY_CITY  + "'");

            break;
        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }

    return numDeleted;
}
@Override
public int bulkInsert(Uri uri, ContentValues[] values){
    final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
    final int match = sUriMatcher.match(uri);
    switch(match){
        case MY_CITY:
            // allows for multiple transactions
            db.beginTransaction();

            // keep track of successful inserts
            int numInserted = 0;
            try{
                for(ContentValues value : values){
                    if (value == null){
                        throw new IllegalArgumentException("Cannot have null content values");
                    }
                    long _id = -1;
                    try{
                        _id = db.insertOrThrow(MyCityContract.MyCityEntry.TABLE_MY_CITY,
                                null, value);
                    }catch(SQLiteConstraintException e) {
                        Log.w(LOG_TAG, "Attempting to insert " +
                                value.getAsString(
                                        MyCityContract.MyCityEntry.COLUMN_NAME)
                                + " but value is already in database.");
                    }
                    if (_id != -1){
                        numInserted++;
                    }
                }
                if(numInserted > 0){
                    // If no errors, declare a successful transaction.
                    // database will not populate if this is not called
                    db.setTransactionSuccessful();
                }
            } finally {
                // all transactions occur at once
                db.endTransaction();
            }
            if (numInserted > 0){
                // if there was successful insertion, notify the content resolver that there
                // was a change
                getContext().getContentResolver().notifyChange(uri, null);
            }
            return numInserted;
        default:
            return super.bulkInsert(uri, values);
    }
}
@Override
public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs){
    final SQLiteDatabase db = myCityDbHelper.getWritableDatabase();
    int numUpdated = 0;

    if (contentValues == null){
        throw new IllegalArgumentException("Cannot have null content values");
    }

    switch(sUriMatcher.match(uri)){
        case MY_CITY:{
            numUpdated = db.update(MyCityContract.MyCityEntry.TABLE_MY_CITY,
                    contentValues,
                    selection,
                    selectionArgs);
            break;
        }
        case MY_CITY_WITH_ID: {
            numUpdated = db.update(MyCityContract.MyCityEntry.TABLE_MY_CITY,
                    contentValues,
                    MyCityContract.MyCityEntry._ID + " = ?",
                    new String[] {String.valueOf(ContentUris.parseId(uri))});
            break;
        }
        default:{
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
    }

    if (numUpdated > 0){
        getContext().getContentResolver().notifyChange(uri, null);
    }

    return numUpdated;
  }
}

MainActivityFragment

public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
private static final String LOG_TAG = MainActivityFragment.class.getSimpleName();
private MyCityAdpapter myCityAdpapter;
private static final int CURSOR_LOADER_ID = 0;
private GridView mGridView;


MyCity[] mMyCity = {
        new MyCity("Ancient Theatre - Larisa", R.drawable.larissa1),

        new MyCity("Ancient Theatre - Larisa", R.drawable.larissa2),
        new MyCity("Municipality park", R.drawable.larissa3),
        new MyCity("Municipality park", R.drawable.larissa4),
        new MyCity("Old trains",R.drawable.larissa5),
        new MyCity("Old trains",R.drawable.larissa6),
        new MyCity("Church",
                R.drawable.larissa7),
        new MyCity("Church",
                R.drawable.larissa8),
        new MyCity("Alcazar park",
                R.drawable.larissa9),
        new MyCity("Alcazar park",
                R.drawable.larissa10),
        new MyCity("AEL FC Arena",
                R.drawable.larissa11),
        new MyCity("AEL FC Arena",
                R.drawable.larissa12),
        new MyCity("Larissa Fair",
                R.drawable.larissa13),
        new MyCity("Larissa Fair",
                R.drawable.larissa14),
        new MyCity("Larissa Fair",
                R.drawable.larissa15),
        new MyCity("Larissa Fair",
                R.drawable.larissa16)

};
public MainActivityFragment() {
    // Required empty public constructor
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    Cursor c =
            getActivity().getContentResolver().query(MyCityContract.MyCityEntry.CONTENT_URI,
                    new String[]{MyCityContract.MyCityEntry._ID},
                    null,
                    null,
                    null);
    if (c.getCount() == 0){
        insertData();
    }
    // initialize loader
    getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
    super.onActivityCreated(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    // inflate fragment_main layout
    final View rootView = inflater.inflate(R.layout.fragment_main_activity, container, false);


    // initialize our FlavorAdapter
    myCityAdpapter = new MyCityAdpapter(getActivity(), null, 0, CURSOR_LOADER_ID);
    // initialize mGridView to the GridView in fragment_main.xml
    mGridView = (GridView) rootView.findViewById(R.id.flavors_grid);
    // set mGridView adapter to our CursorAdapter
    mGridView.setAdapter(myCityAdpapter);

    return rootView;

}

// insert data into database
public void insertData(){
    ContentValues[] cityValuesArr = new ContentValues[mMyCity.length];
    // Loop through static array of MyCity, add each to an instance of ContentValues
    // in the array of ContentValues
    for(int i = 0; i < mMyCity.length; i++){
        cityValuesArr[i] = new ContentValues();
        cityValuesArr[i].put(MyCityContract.MyCityEntry.COLUMN_ICON, mMyCity[i].image);
        cityValuesArr[i].put(MyCityContract.MyCityEntry.COLUMN_NAME,
                mMyCity[i].name);

    }

    // bulkInsert our ContentValues array
    getActivity().getContentResolver().bulkInsert(MyCityContract.MyCityEntry.CONTENT_URI,
            cityValuesArr);
}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args){
    return new CursorLoader(getActivity(),
            MyCityContract.MyCityEntry.CONTENT_URI,
            null,
            null,
            null,
            null);
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    myCityAdpapter.swapCursor(data);
}

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

我在 Fragment 的 onCreateView(...) 方法中读取了光标

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    Cursor c =
            getActivity().getContentResolver().query(MyCityContract.MyCityEntry.CONTENT_URI,
                    new String[]{MyCityContract.MyCityEntry._ID},
                    null,
                    null,
                    null);
    if (c.getCount() == 0){
        insertData();
    }
    // initialize loader
    getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
    super.onActivityCreated(savedInstanceState);
}

这就是我被抛出空光标异常的地方。

有什么想法吗?

谢谢,

西奥。

编辑

我改变了这个 if 条件

 if (c.getCount() == 0){
        insertData();
    }

  if (c == null){
        insertData();
    }

我遇到了这个异常!

 Caused by: java.lang.IllegalArgumentException: Unknown URL content://theo.testing.customloaders/my_city

所以提供者有错误。嗯……

【问题讨论】:

  • 如果将onActivityCreated 上的逻辑移动到onViewCreated 会怎样?内容解析器可能尚不可用
  • 还是一样的问题:(
  • 你有没有在初始化光标cursor.moveToFirst()的时候使用??
  • 首先还要检查 cursor!=null
  • 使用 cursor!=null 应用程序不会崩溃,但我在 gridview 上看不到任何图像。

标签: android exception nullpointerexception android-contentprovider


【解决方案1】:

好的。我修好了它。我所做的只是将我的权限名称从

theo.testing.customloaders

theo.testing.customloaders.app

【讨论】:

    【解决方案2】:

    我认为您在 MainActivity 片段的 onActivityCreated 中使用 getActivity 时遇到问题 如果从 onActivityCreated 中调用 getActivity “可能”返回 null ...尤其是在配置更改期间(例如方向更改),因为活动被破坏... 将该初始化移至 onAttach ... 以下链接帮助我找出 getActivity return null in fragment onActivityCreated in some rooted device

    【讨论】:

    • 不。还是什么都没有。
    • 您的调试指针是否在查询中进入 MY_CITY 或 MY_CITY_WITH_ID 大小写?
    猜你喜欢
    • 2021-12-27
    • 2019-12-20
    • 1970-01-01
    • 2021-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多