в моем коде у меня есть свой собственный класс ContentProvider, который можно увидеть здесь:ContentProvider mHelper остается нулевой
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" />
Спасибо всем заранее для чтения и для понимания.
'new MaiMobileProvider();' это не то, как мы используем 'ContentProviders' ... даже если ... как вы думаете, что' onCreate' будет называться автоматически? ... вам нужно использовать 'ContentResolver.query' – Selvin
, я бы так подумал, да, черт возьми, я буду называть' onCreate' вручную и видеть. Спасибо. – diomonogatari
NOOOOOOOOOOOOOO !!!! вам нужно использовать 'ContentResolver.query' вместо прямого вызова' MaiMobileProvider.query' ... тогда ОС Android создаст экземпляр вашего 'MaiMobileProvider' (если власти совпадут) и вызовет' onCreate', и все будет просто отлично – Selvin