在我的代码中,我有一个自定义的ContentProvider类,可以在这里看到:
public class MaiMobileProvider extends ContentProvider {
protected MaiMobileDbHelper mHelper;
protected UriMatcher mMatcher = buildUriMatcher();
//region code return on UriMatcher
public static final int GNR_CODE = 1;
public static final int PSP_CODE = 2;
public static final int SERVICES_CODE = 3;
public static final int HIGHLIGHT_CODE = 4;
//endregion
static UriMatcher buildUriMatcher() {
// 1) The code passed into the constructor represents the code to return for the root
// URI. It's common to use NO_MATCH as the code for this case. Add the constructor below.
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = MaiMobileContract.CONTENT_AUTHORITY;
// 2) Use the addURI function to match each of the types. Use the constants from
// WeatherContract to help define the types to the UriMatcher.
matcher.addURI(authority, MaiMobileContract.PATH_GNR, GNR_CODE);
matcher.addURI(authority, MaiMobileContract.PATH_PSP, PSP_CODE);
matcher.addURI(authority, MaiMobileContract.PATH_SERVICES, SERVICES_CODE);
matcher.addURI(authority, MaiMobileContract.PATH_SERVICES, HIGHLIGHT_CODE);
// 3) Return the new matcher!
return matcher;
}
//region Selections
//services.isHighlighted = 1
private static final String sServicesIsHighlightedSelection =
MaiMobileContract.ServicesEntry.TABLE_NAME +
"." + MaiMobileContract.ServicesEntry.COLUMN_IS_HIGHLIGHTED + " = 1 ";
//endregion
//region custom cursors
protected Cursor getHighlightedServices(Uri uri, String[] projection, String sortOrder) {
boolean isHighlighted = MaiMobileContract.ServicesEntry.isServiceHighlighted(uri);
String selection = null;
if (isHighlighted)
selection = sServicesIsHighlightedSelection;
return mHelper.getReadableDatabase().query(
MaiMobileContract.ServicesEntry.TABLE_NAME,
projection,
selection,
null,
null,
null,
sortOrder);
}
//endregion
@Override
public boolean onCreate() {
mHelper = new MaiMobileDbHelper(getContext());
return (mHelper == null) ? false : true;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor mCursor;
switch (mMatcher.match(uri)) {
case GNR_CODE:
mCursor = mHelper.getReadableDatabase().query(
MaiMobileContract.GnrEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
case PSP_CODE:
mCursor = mHelper.getReadableDatabase().query(
MaiMobileContract.PspEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
case SERVICES_CODE:
mCursor = mHelper.getReadableDatabase().query(
MaiMobileContract.ServicesEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
case HIGHLIGHT_CODE:
mCursor = getHighlightedServices(uri, projection, sortOrder);
break;
default:
throw new UnsupportedOperationException("Unknow uri: " + uri);
}
mCursor.setNotificationUri(getContext().getContentResolver(), uri);
return mCursor;
}
@Nullable
@Override
public String getType(Uri uri) {
final int match = mMatcher.match(uri);
switch (match) {
case GNR_CODE:
return MaiMobileContract.GnrEntry.CONTENT_TYPE;
case PSP_CODE:
return MaiMobileContract.PspEntry.CONTENT_TYPE;
case SERVICES_CODE:
return MaiMobileContract.ServicesEntry.CONTENT_TYPE;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mHelper.getWritableDatabase();
final int match = mMatcher.match(uri);
Uri returnedUri;
switch (match) {
case GNR_CODE: {
long id = db.insert(MaiMobileContract.GnrEntry.TABLE_NAME, null, values);
if (id > 0)
returnedUri = MaiMobileContract.GnrEntry.buildGnrUri(id);
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
}
case PSP_CODE: {
long id = db.insert(MaiMobileContract.PspEntry.TABLE_NAME, null, values);
if (id > 0)
returnedUri = MaiMobileContract.PspEntry.buildPspUri(id);
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
}
case SERVICES_CODE: {
long id = db.insert(MaiMobileContract.ServicesEntry.TABLE_NAME, null, values);
if (id > 0)
returnedUri = MaiMobileContract.ServicesEntry.buildServicesUri(id);
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
}
case HIGHLIGHT_CODE: {
long id = db.insert(MaiMobileContract.ServicesEntry.TABLE_NAME, null, values);
if (id > 0)
returnedUri = MaiMobileContract.ServicesEntry.buildServicesUri(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 returnedUri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mHelper.getWritableDatabase();
// Student: Use the uriMatcher to match the WEATHER and LOCATION URI's we are going to
final int match = mMatcher.match(uri);
int rowsDeleted;
// handle. If it doesn't match these, throw an UnsupportedOperationException.
if (null == selection)
selection = "1";
switch (match) {
case GNR_CODE:
rowsDeleted = db.delete(MaiMobileContract.GnrEntry.TABLE_NAME, selection,
selectionArgs);
break;
case PSP_CODE:
rowsDeleted = db.delete(MaiMobileContract.PspEntry.TABLE_NAME, selection,
selectionArgs);
break;
case SERVICES_CODE:
rowsDeleted = db.delete(MaiMobileContract.ServicesEntry.TABLE_NAME, selection,
selectionArgs);
break;
case HIGHLIGHT_CODE:
rowsDeleted = db.delete(MaiMobileContract.ServicesEntry.TABLE_NAME, selection,
selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (rowsDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return rowsDeleted;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mHelper.getWritableDatabase();
final int match = mMatcher.match(uri);
int updatedRows;
switch (match) {
case GNR_CODE:
updatedRows = db.update(MaiMobileContract.GnrEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
case PSP_CODE:
updatedRows = db.update(MaiMobileContract.PspEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
case SERVICES_CODE:
updatedRows = db.update(MaiMobileContract.ServicesEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
case HIGHLIGHT_CODE:
updatedRows = db.update(MaiMobileContract.ServicesEntry.TABLE_NAME, values, selection,
selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (updatedRows != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return updatedRows;
}
@Override
@TargetApi(11)
public void shutdown() {
mHelper.close();
super.shutdown();
}
}
此提供程序用于请求我用于制作地图标记的方法,并最终将它们添加到ClusterManager中,可以在此处看到:
public class BaseMapFragment extends SupportMapFragment {
//region Parameters
private final String LOG_TAG = "BaseMapFragment";
public static int layout;
protected FetchDataInterface mApiGson;
protected GoogleMap gMap;
protected SecurityMapFragment mapFragment;
protected MaiMobileProvider mProvider;
protected List<MaiClusterItem> pspItems = new ArrayList<>();
protected List<MaiClusterItem> gnrItems = new ArrayList<>();
protected ClusterManager<MaiClusterItem> mClusterManager;
//endregion
//region Methods
protected void addMapMarkers(MaiMobileProvider provider, String markerGroup) {
switch (markerGroup) {//between a switch and a if statement, I adopted the switch for future implementations
case "psp":{
Cursor cursor = provider.query(MaiMobileContract.PspEntry.CONTENT_URI,null,null,null,MaiMobileContract.PspEntry.COLUMN_DISTANCE +" ASC");
cursor.moveToFirst();
Log.v("Cursor psp: ", cursor.toString());
Log.v("Cursor psp ", "has: " + cursor.getCount());
while(cursor.moveToNext()){
//cyclic add items to each MaiClusterItem List
LatLng coco = new LatLng(
cursor.getDouble(ColumnIndexes.PspIndexes.COLUMN_COORD_LAT),
cursor.getDouble(ColumnIndexes.PspIndexes.COLUMN_COORD_LONG));
pspItems.add(new MaiClusterItem(coco,
BitmapDescriptorFactory.fromResource(R.mipmap.psp),
cursor.getString(ColumnIndexes.PspIndexes.COLUMN_NAME),
cursor.getString(ColumnIndexes.PspIndexes.COLUMN_DESCRIPTION)));
Log.v("pspItems ", "has: " + pspItems.size());
}
cursor.close();
break;
}
case "gnr": {
Cursor cursor = provider.query(MaiMobileContract.GnrEntry.CONTENT_URI, null, null, null, MaiMobileContract.GnrEntry.COLUMN_DISTANCE + " ASC");
cursor.moveToFirst();
Log.v("Cursor gnr: ", cursor.toString());
while(cursor.moveToNext()){
LatLng coco = new LatLng(
cursor.getDouble(ColumnIndexes.GnrIndexes.COLUMN_COORD_LAT),
cursor.getDouble(ColumnIndexes.GnrIndexes.COLUMN_COORD_LONG));
gnrItems.add(new MaiClusterItem(
coco,
BitmapDescriptorFactory.fromResource(R.mipmap.gnr_green),
cursor.getString(ColumnIndexes.GnrIndexes.COLUMN_NAME),
""));
Log.v("gnrItems ", "has: " + gnrItems.size());
}
cursor.close();
break;
}
default:
throw new UnsupportedOperationException("Unknown error adding markers: " + getContext() + " at " + LOG_TAG);
}
}
//region PspData Call
protected void makePspMarkers() {
addMapMarkers(mProvider, "psp");
mClusterManager.addItems(pspItems);
mClusterManager.setRenderer(new MaiClusterItem.ClusterItemRenderer(getActivity(), gMap, mClusterManager));
}
//endregion
//region GnrData Call
protected void makeGnrMarkers() {
addMapMarkers(mProvider, "gnr");
mClusterManager.addItems(gnrItems);
mClusterManager.setRenderer(new MaiClusterItem.ClusterItemRenderer(getActivity(), gMap, mClusterManager));
}
//endregion
//endregion
}
并且此BaseMapFragment在SecurityMapFragment类上进行了扩展:
public class SecurityMapFragment extends BaseMapFragment implements
OnMapReadyCallback {
//region Properties
public CameraPosition userCameraPosition;
//endregion
//region Methods
//region MapReady
@Override
public void onMapReady(GoogleMap googleMap) {
gMap = googleMap;
//region map design
gMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
gMap.getUiSettings().setZoomControlsEnabled(false);
gMap.setMyLocationEnabled(true);
gMap.getUiSettings().setMyLocationButtonEnabled(false);
//endregion
//region camera+clustering
userCameraPosition =
new CameraPosition.Builder()
.target(MainActivity.userCoords)
.zoom(9f)
.bearing(-10f)
.build();
gMap.moveCamera(CameraUpdateFactory.newCameraPosition(userCameraPosition));//set camera on user position (static for now)
mClusterManager = new ClusterManager<>(getContext(), gMap);
gMap.setOnCameraChangeListener(mClusterManager);//cluster call
//endregion
}
//endregion
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mProvider = new MaiMobileProvider();
//generate map
mapFragment = (SecurityMapFragment) this.getFragmentManager().findFragmentById(R.id.security_map_view);
getMapAsync(this);
//interface api instance for Gson
mApiGson = RetrofitUtils.createGsonRetrofitInterface();
makePspGnrMarkers();//this will be called on created and also on filter selection
}
//region Add markers methods
private void makePspGnrMarkers() {
//Todo mClusterManager.clearItems();
makePspMarkers();
makeGnrMarkers();
}
//endregion
//endregion
}
MainActivity调用SecurityMapFragment,然后在片段上调用它来使用在我的服务上创建的数据库中的数据的方法。
现在出现了问题,由于某些原因,在执行mHelper.getReadableDatabase().query(...);
时,它在该方法调用上给了NullPointerException
,这发生在MaiMobileProvider
方法的.query()
上,这是BaseMapFragment
用于获取数据库数据的方法。
我知道mHelper
是null
,我不知道是为什么。 mHelper的内部化是在提供者的onCreate
上进行的。
注意:是的,我的提供者正在<application>
<provider
android:name=".data.database.MaiMobileProvider"
android:authorities="pt.gov.mai.mobile.android"
android:exported="false" />
提前感谢大家的阅读和见解。
答案 0 :(得分:0)
就像Selvin说我应该使用ContentResolver.query()
因为应用程序已经负责实例化清单中的Provider。
因此,作为“改变了什么”的一部分:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mResolver = getContext().getContentResolver();//From a Provider to a ContentResolver
//generate map
mapFragment = (SecurityMapFragment) this.getFragmentManager().findFragmentById(R.id.security_map_view);
getMapAsync(this);
//interface api instance for Gson
mApiGson = RetrofitUtils.createGsonRetrofitInterface();
makePspGnrMarkers();//this will be called on created and also on filter selection
}
然后我们从我们的上下文中获取ContentResolver
之后,我们可以使用它来查询我们的提供程序,就像它完成一样。
还必须参考Selvin,评论我的问题并指出应该使用Resolver
。
还有Android documentation on ContentProvider and ContentResolver。