in my code I have a my custom ContentProvider class that can be seen here:
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();
}
}
This provider is used on requesting a method that I use to make my map markers and eventually add them to the ClusterManager, which can be seen here:
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
}
and this BaseMapFragment is extended on SecurityMapFragment class:
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
}
The MainActivity calls the SecurityMapFragment, then on the fragment it is called the methods to use the data from the Database that was created on my service.
The problem comes now, for some reason on doing mHelper.getReadableDatabase().query(...); it gives me a NullPointerException on that method call, this happens on the MaiMobileProvider on the .query() method, which is the method that BaseMapFragment uses to fetch Database data.
I know that the mHelper is null, what I don't know is why. The inicialization of mHelper is made on the onCreate of the Provider.
NOTE: yes my provider is being declared on the manifest inside the <application>
<provider
android:name=".data.database.MaiMobileProvider"
android:authorities="pt.gov.mai.mobile.android"
android:exported="false" />
Thank you all in advance for reading and for your insight.
Just like Selvin said I should use the ContentResolver.query() because the application is already in charge of instantiating the Provider that is in the manifest.
So as part of "what has changed":
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
}
And then after we get our ContentResolver from our context we can use it to query our provider, the same way it was done.
Also have to refer on Selvin that commented my question and pointed that a Resolver should be used.
And also Android documentation on ContentProvider and ContentResolver.
Related
I have trying to insert values into database as well as in content provider but getting null sqlite exception.Before using content provider class my data are added to database without any problem.after trying content provider im getting exception. Also I doesn't know whether values are inserted for content provider.....
And in SpecificActivity class I need to use drawable which is returned by LoadImageAsyncTask class but Im getting null value there...
Help me to solve those issues..
public class FeedReaderContract {
public static class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String _ID = BaseColumns._ID;
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_CONTENT = "content";
public static final String COLUMN_NAME_IMAGE = "image";
public static final String COLUMN_NAME_CHANNEL = "channel";
}
}
public class FeedReaderDbHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "FeedReader.db";
Context context;
public Context getContext() {
return context;
}
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE " + FeedReaderContract.FeedEntry.TABLE_NAME + " (" +
FeedReaderContract.FeedEntry._ID + " INTEGER PRIMARY KEY, " +
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + " TEXT, " +
FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT + " TEXT, " +
FeedReaderContract.FeedEntry.COLUMN_NAME_CHANNEL + " TEXT, " +
FeedReaderContract.FeedEntry.COLUMN_NAME_IMAGE + " TEXT); ";
private static final String SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + FeedReaderContract.FeedEntry.TABLE_NAME;
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
public void onCreate(SQLiteDatabase db) {
NewsFeedProvider.db = db;
db.execSQL(SQL_CREATE_ENTRIES);
Log.e("sql db", "created");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + FeedReaderContract.FeedEntry.TABLE_NAME);
onCreate(db);
}
public void getData(long id) {
try {
Log.e("entered", "getdata");
SQLiteDatabase db = getReadableDatabase();
Cursor cursor = db.query(FeedReaderContract.FeedEntry.TABLE_NAME, new String[] {
FeedReaderContract.FeedEntry._ID, FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, FeedReaderContract.FeedEntry.COLUMN_NAME_CHANNEL, FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, FeedReaderContract.FeedEntry.COLUMN_NAME_IMAGE
}, FeedReaderContract.FeedEntry._ID + "=?", new String[] {
String.valueOf(id)
}, null, null, null, null);
ArrayList < NewsReport > newsReports = new ArrayList < > ();
List itemIds = new ArrayList < > ();
while (cursor.moveToNext()) {
newsReports.add(new NewsReport(cursor.getString(cursor.getColumnIndex(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE)),
cursor.getString(cursor.getColumnIndex(FeedReaderContract.FeedEntry.COLUMN_NAME_CHANNEL)),
cursor.getString(cursor.getColumnIndex(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT)),
cursor.getString(cursor.getColumnIndex(FeedReaderContract.FeedEntry.COLUMN_NAME_IMAGE))));
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID));
itemIds.add(itemId);
Log.e("id", "" + itemId);
}
cursor.close();
Log.e("newsreportsize", "dbhelper" + newsReports.size());
if (newsReports.size() != 0) {
for (int i = 0; i < newsReports.size(); i++) {
Log.e("news pic", "" + newsReports.get(i).getPic());
Log.e("news title", "" + newsReports.get(i).getTitle());
Log.e("news content", "" + newsReports.get(i).getContent());
Log.e("news chanel", "" + newsReports.get(i).getNewsChannel());
}
}
} catch (Exception ex) {
Log.e("exception req data", "" + ex);
}
}
}
public class LoadImageAsyncTask extends AsyncTask < String, Void, Drawable > {
private Drawable drawable;
String imageUrl;
private Drawable image;
#Override
protected Drawable doInBackground(String...strings) {
try {
InputStream is = (InputStream) new URL(imageUrl).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
Log.e("drwable", "" + d);
} catch (Exception e) {
Log.e("Specific Activity", "Converting drawable" + e);
}
return drawable;
}
#Override
protected void onPostExecute(Drawable drawableImage) {
super.onPostExecute(drawableImage);
setImage(drawableImage);
}
public void setImage(Drawable drawable) {
new SpecificNewsReportActivity().drawable = drawable;
Log.e("set image", "" + drawable);
this.drawable = drawable;
}
public Drawable getImage() {
Log.e("get image", "" + drawable);
return drawable;
}
}
public class NewsFeedProvider extends ContentProvider {
static final String PROVIDER_NAME = "com.example.newsreport";
static final String URL = "content://" + PROVIDER_NAME + "/newsfeed";
static final Uri CONTENT_URL = Uri.parse(URL);
static final int uriCode = 1;
static String newsTitle;
static String newsContent;
static String newsImage;
static String newsChannel;
static final UriMatcher uriMatcher;
private FeedReaderDbHelper dbHelper;
private static HashMap < String, String > values;
public static SQLiteDatabase db;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "newsfeed", uriCode);
}
#Override
public boolean onCreate() {
dbHelper = new FeedReaderDbHelper(getContext());
return true;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(FeedReaderContract.FeedEntry.TABLE_NAME);
switch (uriMatcher.match(uri)) {
case uriCode:
queryBuilder.setProjectionMap(values);
break;
default:
throw new IllegalArgumentException("Unknown URI" + uri);
}
//Cursor cursor=queryBuilder.query(dbHelper.getReadableDatabase(),projection,selection,selectionArgs,null,null,sortOrder);
Cursor cursor = dbHelper.getReadableDatabase().query(FeedReaderContract.FeedEntry.TABLE_NAME, projection, FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + "= ?", selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case uriCode:
return "vnd.android.cursor.dir/newsfeed";
default:
throw new IllegalArgumentException("Unsupported URI" + uri);
}
}
#Override
public Uri insert(Uri uri, ContentValues contentValues) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
long rowId = db.insert(FeedReaderContract.FeedEntry.TABLE_NAME, null, contentValues);
if (rowId > 0) {
Uri _uri = ContentUris.withAppendedId(CONTENT_URL, rowId);
getContext().getContentResolver().notifyChange(_uri, null);
Log.e("insert", "feedreader" + contentValues);
return _uri;
} else {
Toast.makeText(getContext(), "Row insert failed", Toast.LENGTH_SHORT).show();
return null;
}
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int rowsDeleted = 0;
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case uriCode:
rowsDeleted = db.delete(FeedReaderContract.FeedEntry.TABLE_NAME, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI" + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
int rowsUpdated = 0;
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case uriCode:
rowsUpdated = db.delete(FeedReaderContract.FeedEntry.TABLE_NAME, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI" + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
}
public class NewsReportActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks < ArrayList < NewsReport >> {
ProgressBar progressBar;
FeedReaderDbHelper dbHelper;
SQLiteDatabase db;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_view);
dbHelper = new FeedReaderDbHelper(this);
db = dbHelper.getWritableDatabase();
Log.e("application", "" + dbHelper);
Intent intent = getIntent();
if (intent.hasExtra("exception")) {
TextView connectionTextView = (TextView) findViewById(R.id.no_connection_text_view);
connectionTextView.setText("There is no internet connection!!!");
} else {
Log.e("no exception", "entered else");
}
getSupportLoaderManager().initLoader(0, null, this);
}
#NonNull
#Override
public Loader < ArrayList < NewsReport >> onCreateLoader(int id, #Nullable Bundle args) {
NewsReportLoader newsReportLoader = new NewsReportLoader(this);
newsReportLoader.forceLoad();
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setVisibility(View.VISIBLE);
return newsReportLoader;
}
#Override
public void onLoadFinished(#NonNull Loader < ArrayList < NewsReport >> loader, ArrayList < NewsReport > data) {
try {
Log.e("data", "" + data.size());
NewsReportAdapter adapter = new NewsReportAdapter(this, data);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
progressBar.setVisibility(View.INVISIBLE);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
new LinearLayoutManager(this).getOrientation());
recyclerView.addItemDecoration(mDividerItemDecoration);
if (dbHelper != null) {
Log.e("dbhelper", "notnull");
db = dbHelper.getWritableDatabase();
if (db != null) {
Log.e("db", "notnull");
for (int i = 0; i < data.size(); i++) {
ContentValues values = new ContentValues();
NewsReport newsReport = data.get(i);
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, newsReport.getTitle());
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, newsReport.getContent());
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CHANNEL, newsReport.getNewsChannel());
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_IMAGE, newsReport.getPic());
values.put(NewsFeedProvider.newsTitle, newsReport.getTitle());
values.put(NewsFeedProvider.newsContent, newsReport.getContent());
values.put(NewsFeedProvider.newsChannel, newsReport.getNewsChannel());
values.put(NewsFeedProvider.newsImage, newsReport.getPic());
try {
Uri uri = getApplicationContext().getContentResolver().insert(NewsFeedProvider.CONTENT_URL, values);
} catch (Exception ex) {
Log.e("exception in resolver" + getContentResolver(), "" + ex);
}
long newRowId = db.insert(FeedReaderContract.FeedEntry.TABLE_NAME, null, values);
Log.e("new row id", "" + newRowId);
dbHelper.getData(newRowId);
}
} else
Log.e("db", "null");
} else {
Log.e("dbhelper", "null");
}
// db.execSQL("delete from "+ FeedReaderContract.FeedEntry.TABLE_NAME);
} catch (Exception ex) {
Log.e("newsactivity", "" + FeedReaderContract.FeedEntry.TABLE_NAME.length());
Log.e("onloadfinished", "" + ex);
Log.e("datahelper", "" + dbHelper.getReadableDatabase().rawQuery("SELECT * FROM " + FeedReaderContract.FeedEntry.TABLE_NAME, null));
}
}
#Override
public void onLoaderReset(#NonNull Loader < ArrayList < NewsReport >> loader) {
}
}
public class SpecificNewsReportActivity extends AppCompatActivity {
private TextView contentTextView, titleTextView;
public ImageView imageView;
private Intent intent;
public Drawable drawable;
private String imageUrl;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_specific_news_report);
ActionBar actionBar = this.getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
intent = getIntent();
LoadImageAsyncTask task = new LoadImageAsyncTask();
AsyncTask < String, Void, Drawable > d = task.execute();
try {
drawable = d.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
imageUrl = getIntent().getStringExtra("image");
Log.e("drawable specific", "" + drawable);
drawable = new LoadImageAsyncTask().getImage();
contentTextView = (TextView) findViewById(R.id.specific_news_report_content_text_view);
titleTextView = (TextView) findViewById(R.id.specific_news_report_title_text_view);
imageView = (ImageView) findViewById(R.id.specific_news_report_image_view);
contentTextView.setText(intent.getStringExtra("content"));
titleTextView.setText(intent.getStringExtra("title"));
try {
if (drawable != null) {
imageView.setImageDrawable(drawable);
} else {
Log.e("returned drawable", "null");
}
} catch (Exception ex) {
Log.e("enna exception", "" + ex);
}
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
Intent intent = NavUtils.getParentActivityIntent(this);
NavUtils.navigateUpTo(this, intent);
}
return super.onOptionsItemSelected(item);
}
}
stacktrace
2019-07-29 13:57:20.172 24098-24098/com.example.newsreport E/SQLiteLog: (1) near "null": syntax error
2019-07-29 13:57:20.177 24098-24098/com.example.newsreport E/SQLiteDatabase: Error inserting channel=News18.com null=https://images.news18.com/ibnlive/uploads/2019/07/yediyurappa-1.jpg image=https://images.news18.com/ibnlive/uploads/2019/07/yediyurappa-1.jpg title=Karnataka Assembly Trust Vote LIVE: Yediyurappa Wins Floor Test, Speaker Ramesh Kumar Resigns - News18 content=Eleven Congress MLAs and three JDS lawmakers faced the axe from the Speaker in addition to the three disqualified earlier, bringing down the majority mark to 104, one less than the current strength of 105 of the BJP, which also enjoys the support of an Indepe… [+3489 chars]
android.database.sqlite.SQLiteException: near "null": syntax error (code 1 SQLITE_ERROR): , while compiling: INSERT INTO entry(channel,null,image,title,content) VALUES (?,?,?,?,?)
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1562)
at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1433)
at com.example.newsreport.NewsFeedProvider.insert(NewsFeedProvider.java:78)
at android.content.ContentProvider$Transport.insert(ContentProvider.java:265)
at android.content.ContentResolver.insert(ContentResolver.java:1587)
at com.example.newsreport.NewsReportActivity.onLoadFinished(NewsReportActivity.java:96)
at com.example.newsreport.NewsReportActivity.onLoadFinished(NewsReportActivity.java:29)
at androidx.loader.app.LoaderManagerImpl$LoaderObserver.onChanged(LoaderManagerImpl.java:250)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:113)
at androidx.lifecycle.LiveData.dispatchingValue(LiveData.java:131)
at androidx.lifecycle.LiveData.setValue(LiveData.java:289)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at androidx.loader.app.LoaderManagerImpl$LoaderInfo.setValue(LoaderManagerImpl.java:189)
at androidx.loader.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManagerImpl.java:174)
at androidx.loader.content.Loader.deliverResult(Loader.java:132)
at androidx.loader.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:258)
at androidx.loader.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:83)
at androidx.loader.content.ModernAsyncTask.finish(ModernAsyncTask.java:490)
at androidx.loader.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:507)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-07-29 13:57:20.218 24098-24098/com.example.newsreport E/SQLiteLog: (1) near "null": syntax error
2019-07-29 13:57:20.220 24098-24098/com.example.newsreport E/SQLiteDatabase: Error inserting channel=News18.com null=https://images.news18.com/ibnlive/uploads/2019/07/yediyurappa-1.jpg image=https://images.news18.com/ibnlive/uploads/2019/07/yediyurappa-1.jpg title=Karnataka Assembly Trust Vote LIVE: Yediyurappa Wins Floor Test, Speaker Ramesh Kumar Resigns - News18 content=Eleven Congress MLAs and three JDS lawmakers faced the axe from the Speaker in addition to the three disqualified earlier, bringing down the majority mark to 104, one less than the current strength of 105 of the BJP, which also enjoys the support of an Indepe… [+3489 chars]
android.database.sqlite.SQLiteException: near "null": syntax error (code 1 SQLITE_ERROR): , while compiling: INSERT INTO entry(channel,null,image,title,content) VALUES (?,?,?,?,?)
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:903)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:514)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1562)
at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1433)
at com.example.newsreport.NewsReportActivity.onLoadFinished(NewsReportActivity.java:102)
at com.example.newsreport.NewsReportActivity.onLoadFinished(NewsReportActivity.java:29)
at androidx.loader.app.LoaderManagerImpl$LoaderObserver.onChanged(LoaderManagerImpl.java:250)
at androidx.lifecycle.LiveData.considerNotify(LiveData.java:113)
I need to use drawable which is returned from loadimageasynctask
I need to store all data in database as well as for content provider
In the table there are 4 columns and the primary key.
When you insert a new row you supply values for the ContentValues object but you do it twice for each column:
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, newsReport.getTitle());
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, newsReport.getContent());
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CHANNEL, newsReport.getNewsChannel());
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_IMAGE, newsReport.getPic());
values.put(NewsFeedProvider.newsTitle, newsReport.getTitle());
values.put(NewsFeedProvider.newsContent, newsReport.getContent());
values.put(NewsFeedProvider.newsChannel, newsReport.getNewsChannel());
values.put(NewsFeedProvider.newsImage, newsReport.getPic());
Why?
I suspect that one of:
NewsFeedProvider.newsTitle
NewsFeedProvider.newsContent
NewsFeedProvider.newsChannel
NewsFeedProvider.newsImage
returns null.
So delete these lines:
values.put(NewsFeedProvider.newsTitle, newsReport.getTitle());
values.put(NewsFeedProvider.newsContent, newsReport.getContent());
values.put(NewsFeedProvider.newsChannel, newsReport.getNewsChannel());
values.put(NewsFeedProvider.newsImage, newsReport.getPic());
They are not needed.
The values for the columns are set by the previous 4 lines.
Something's probably wrong with the implementation of update() method but I'm not sure what is:
#Override
public int update(#NonNull Uri uri, #Nullable ContentValues contentValues, #Nullable String s, #Nullable String[] strings) {
int count = 0;
switch (uriMatcher.match(uri)) {
case uriCode:
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
Here's how I call the method:
Random r1 = new Random();
long insertValue1 = r1.nextInt(5);
updatedValues.put(Provider.adPoints, insertValue1);
int value = getContentResolver().update(Provider.CONTENT_URI, updatedValues, null, null); //insert(Provider.CONTENT_URI, values);
I also want to make use of count and return the number of row updated in update(). What seems to be wrong here?
There is no update code in Switch . I think you missed it
In order to get the rows updates with a Content Provider then you have to do this:
First make sure that you have a reference of your DatabaseHelper class in the ContentProvider:
private YourDatabaseSQLLiteHelper mDbHelper;
#Override
public boolean onCreate() {
mDbHelper = new YourDatabaseSQLLiteHelper(getContext());
return true;
}
Then override the update() method on your content provider:
#Override
public int update(#NonNull Uri uri, #Nullable ContentValues cv, #Nullable String selection, #Nullable String[] selectionArgs) {
int rowsUpdated;
switch (sUriMatcher.match(uri)) {
case YOUR_TABLE_CODE:
// This is what you need.
rowsUpdated = mDbHelper.getWritableDatabase().update(
YourTableContract.YourTableEntry.TABLE_NAME,
cv,
selection,
selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (rowsUpdated != 0)
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
Then when you call the method, it must return how many rows were updated.
int rowsUpdatedCount = getContentResolver().update(...);
Please let me know if this works for you.
I'm trying to make an app that involves a database. I'm using a ContentProvider and it's crashing in the query method when it tries to getWritableDatabase.
It returns a NullPointerException. I know for a fact that the Context isn't null, since that seems to be the main cause of this kind of problem.
Here's the ContentProvider code:
package com.corvus.corvusenterprises.digimonapp;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
import java.util.HashSet;
import static com.corvus.corvusenterprises.digimonapp.DBHelper.presentDigimon;
/**
* Created by Jack on 01/05/2017.
*/
public class DigimonContentProvider extends ContentProvider {
private static DigimonContentProvider instance;
private DBHelper dbHelper;
private SQLiteDatabase db;
private static final int DIGIMON = 10;
private static final int DIGIMON_ID = 20;
private static final int ATTACKS = 30;
private static final int ATTACKS_ID = 40;
private static final int EVOLUTIONS = 50;
private static final int EVOLUTIONS_ID = 60;
private static final String AUTHORITY = "com.corvus.corvusenterprises.digimonapp";
private static final String BASE_PATH_DIGIMON = "digimon";
private static final String BASE_PATH_ATTACKS = "attacks";
private static final String BASE_PATH_EVOLUTIONS = "evolutions";
public static final Uri CONTENT_URI_DIGIMON = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH_DIGIMON);
public static final Uri CONTENT_URI_ATTACKS = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH_ATTACKS);
public static final Uri CONTENT_URI_EVOLUTIONS = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH_EVOLUTIONS);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/digimon";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/digimon";
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, BASE_PATH_DIGIMON, DIGIMON);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_DIGIMON + "/#", DIGIMON_ID);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_ATTACKS, ATTACKS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_ATTACKS + "/#", ATTACKS_ID);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_EVOLUTIONS, EVOLUTIONS);
sURIMatcher.addURI(AUTHORITY, BASE_PATH_EVOLUTIONS + "/#", EVOLUTIONS_ID);
}
private DigimonContentProvider()
{
}
public static DigimonContentProvider getInstance() {
if (instance == null)
instance = new DigimonContentProvider();
return instance;
}
#Override
public boolean onCreate() {
Context ctx = MyApp.getContext();
dbHelper = DBHelper.getInstance(ctx);
dbHelper.insertDigimon("Guilmon", "Guilmon", "Child/Rookie", "Virus", "Dinosaur", "TRUE","R.mipmap.guilmon.jpg");
dbHelper.insertDigimon("Growmon", "Growlmon", "Adult/Champion", "Virus", "Bigger Dinosaur", "FALSE","R.mipmap.growmon.jpg");
dbHelper.insertDigimon("Terriermon", "terriermon", "Child/Rookie", "Vaccine", "Dogbunny", "FALSE","R.mipmap.terriermon.jpg");
dbHelper.insertDigimon("Galgomon", "Gargomon", "Adult/Champion", "Vaccine", "Gunbunny", "FALSE","R.mipmap.galgomon.jpg");
dbHelper.insertDigimon("Kyubimon", "Kyubimon", "Adult/Champion", "Data", "9-Tailed Fox", "FALSE","R.mipmap.kyubimon.jpg");
dbHelper.insertDigimon("Taomon", "Taomon", "Perfect/Ultimate", "Data", "Kitsune Miko", "FALSE","R.mipmap.taomon.jpg");
dbHelper.insertDigimon("Impmon", "Impmon", "Child/Rookie", "Virus", "Kid in a purple onesie", "FALSE","R.mipmap.impmon.jpg");
dbHelper.insertDigimon("Beelzebumon", "Beelzemon", "Ultimate/Mega", "Virus", "Demon Lord of Gluttony", "FALSE","R.mipmap.beelzebumon.jpg");
presentDigimon[460] = true; presentDigimon[454] = true;
presentDigimon[1019] = true; presentDigimon[374] = true;
presentDigimon[572] = true; presentDigimon[1013] = true;
presentDigimon[507] = true; presentDigimon[100] = true;
dbHelper.insertEvolution("Guilmon", "Growmon", "");
dbHelper.insertEvolution("Terriermon", "Galgomon","");
dbHelper.insertEvolution("Kyubimon", "Taomon","");
dbHelper.insertEvolution("Impmon", "Beelzebumon", "(Warp Evolution)");
dbHelper.insertAttack("Fireball", "Pyro Sphere", "Guilmon", "Explosive Fireball");
dbHelper.insertAttack("Rock Breaker", "Rock Breaker", "Guilmon", "Claw Swipe");
dbHelper.insertAttack("Exhaust Flame", "Pyro Blaster", "Growmon", "Fire Laser");
dbHelper.insertAttack("Plasma Blade", "Dragon Slash", "Growmon", "Forearm Blades");
dbHelper.insertAttack("Blazing Fire", "Bunny Blast", "Terriermon", "Energy Blast");
dbHelper.insertAttack("Petit Twister", "Terrier Tornado", "Terriermon", "Throws Tornado");
dbHelper.insertAttack("Gatling Arm", "Gargo Laser", "Galgomon", "Fires Guns");
dbHelper.insertAttack("Dum Dum Upper", "Bunny Pummel", "Galgomon", "Fires Guns While Punching");
dbHelper.insertAttack("Koenryu", "Dragon Wheel", "Kyubimon", "Fire Dragon");
dbHelper.insertAttack("Onibidama", "Fox-Tail Inferno", "Kyubimon", "Fireballs from the tails");
dbHelper.insertAttack("Bonhitsusen", "Talisman of Light", "Taomon", "Energy Seal Laser");
dbHelper.insertAttack("Oṃ", "Talisman Spell", "Taomon", "Makes a dome shield");
dbHelper.insertAttack("Night of Fire", "Badaboom", "Impmon", "Mini-Fireballs");
dbHelper.insertAttack("Pillar of Fire", "", "Impmon", "Wall of Flames");
dbHelper.insertAttack("Double Impact", "Double Impact", "Beelzebumon", "Fires two bullets");
dbHelper.insertAttack("Darkness Claw", "", "Beelzebumon", "Kills Leomon");
db = dbHelper.getWritableDatabase();
return false;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
Uri _uri = null;
switch (sURIMatcher.match(uri)) {
case DIGIMON:
long _ID1 = db.insert(DigimonTable.DIGIMON_TABLE_NAME, "", values);
if (_ID1 > 0) {
_uri = ContentUris.withAppendedId(CONTENT_URI_DIGIMON, _ID1);
MyApp.getContext().getContentResolver().notifyChange(_uri, null);
}
break;
case ATTACKS:
long _ID2 = db.insert(AttacksTable.ATTACKS_TABLE_NAME, "", values);
if (_ID2 > 0) {
_uri = ContentUris.withAppendedId(CONTENT_URI_ATTACKS, _ID2);
MyApp.getContext().getContentResolver().notifyChange(_uri, null);
}
break;
case EVOLUTIONS:
long _ID3 = db.insert(EvolutionsTable.EVOLUTIONS_TABLE_NAME, "", values);
if (_ID3 > 0) {
_uri = ContentUris.withAppendedId(CONTENT_URI_EVOLUTIONS, _ID3);
MyApp.getContext().getContentResolver().notifyChange(_uri, null);
}
break;
default:
throw new SQLException("Failed to insert row into " + uri);
}
MyApp.getContext().getContentResolver().notifyChange(uri, null);
return _uri;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
int uriType = sURIMatcher.match(uri);
checkColumns(projection, uriType);
queryBuilder.setTables(DigimonTable.DIGIMON_TABLE_NAME + ", " + EvolutionsTable.EVOLUTIONS_TABLE_NAME + ", " + AttacksTable.ATTACKS_TABLE_NAME);
switch (uriType) {
case DIGIMON:
break;
case DIGIMON_ID:
queryBuilder.appendWhere(DigimonTable.DIGIMON_COLUMN_ID+"="+uri.getLastPathSegment());
case ATTACKS:
break;
case ATTACKS_ID:
queryBuilder.appendWhere(AttacksTable.ATTACKS_COLUMN_ID+"="+uri.getLastPathSegment());
case EVOLUTIONS:
break;
case EVOLUTIONS_ID:
queryBuilder.appendWhere(EvolutionsTable.EVOLUTIONS_COLUMN_ID+"="+uri.getLastPathSegment());
default:
throw new IllegalArgumentException("Unknown URI: "+ uri);
}
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(MyApp.getContext().getContentResolver(), uri);
return cursor;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
int rowsDeleted = 0;
switch (uriType) {
case DIGIMON:
rowsDeleted = db.delete(DigimonTable.DIGIMON_TABLE_NAME, selection, selectionArgs);
break;
case DIGIMON_ID:
String id1 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(
DigimonTable.DIGIMON_TABLE_NAME,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1,
null);
} else {
rowsDeleted = db.delete(
DigimonTable.DIGIMON_TABLE_NAME,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1
+ " and " + selection,
selectionArgs);
}
break;
case ATTACKS:
rowsDeleted = db.delete(AttacksTable.ATTACKS_TABLE_NAME, selection, selectionArgs);
break;
case ATTACKS_ID:
String id2 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(
AttacksTable.ATTACKS_TABLE_NAME,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2,
null);
} else {
rowsDeleted = db.delete(
AttacksTable.ATTACKS_TABLE_NAME,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2
+ " and " + selection,
selectionArgs);
}
break;
case EVOLUTIONS:
rowsDeleted = db.delete(EvolutionsTable.EVOLUTIONS_TABLE_NAME, selection, selectionArgs);
break;
case EVOLUTIONS_ID:
String id3 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = db.delete(
EvolutionsTable.EVOLUTIONS_TABLE_NAME,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3,
null);
} else {
rowsDeleted = db.delete(
EvolutionsTable.EVOLUTIONS_TABLE_NAME,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3
+ " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
MyApp.getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
int rowsUpdated = 0;
switch (uriType) {
case DIGIMON:
rowsUpdated = db.update(DigimonTable.DIGIMON_TABLE_NAME,
values,
selection,
selectionArgs);
break;
case DIGIMON_ID:
String id1 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = db.update(DigimonTable.DIGIMON_TABLE_NAME,
values,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1,
null);
} else {
rowsUpdated = db.update(DigimonTable.DIGIMON_TABLE_NAME,
values,
DigimonTable.DIGIMON_COLUMN_ID + "=" + id1
+ " and "
+ selection,
selectionArgs);
}
break;
case ATTACKS:
rowsUpdated = db.update(AttacksTable.ATTACKS_TABLE_NAME,
values,
selection,
selectionArgs);
break;
case ATTACKS_ID:
String id2 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = db.update(AttacksTable.ATTACKS_TABLE_NAME,
values,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2,
null);
} else {
rowsUpdated = db.update(AttacksTable.ATTACKS_TABLE_NAME,
values,
AttacksTable.ATTACKS_COLUMN_ID + "=" + id2
+ " and "
+ selection,
selectionArgs);
}
break;
case EVOLUTIONS:
rowsUpdated = db.update(EvolutionsTable.EVOLUTIONS_TABLE_NAME,
values,
selection,
selectionArgs);
break;
case EVOLUTIONS_ID:
String id3 = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = db.update(EvolutionsTable.EVOLUTIONS_TABLE_NAME,
values,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3,
null);
} else {
rowsUpdated = db.update(EvolutionsTable.EVOLUTIONS_TABLE_NAME,
values,
EvolutionsTable.EVOLUTIONS_COLUMN_ID + "=" + id3
+ " and "
+ selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
MyApp.getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection, int uri) {
HashSet<String> availableColumns;
String[] availableDigimon = { DigimonTable.DIGIMON_COLUMN_ID,
DigimonTable.DIGIMON_COLUMN_NAME, DigimonTable.DIGIMON_COLUMN_DUB_NAME,
DigimonTable.DIGIMON_COLUMN_LEVEL, DigimonTable.DIGIMON_COLUMN_ATTRIBUTE,
DigimonTable.DIGIMON_COLUMN_DESCRIPTION, DigimonTable.DIGIMON_COLUMN_FAVOURITE,
DigimonTable.DIGIMON_COLUMN_PATH};
String[] availableAttacks = {AttacksTable.ATTACKS_COLUMN_ID, AttacksTable.ATTACKS_COLUMN_NAME,
AttacksTable.ATTACKS_COLUMN_DUB_NAME, AttacksTable.ATTACKS_COLUMN_DIGIMON,
AttacksTable.ATTACKS_COLUMN_DESCRIPTION};
String[] availableEvolutions = {EvolutionsTable.EVOLUTIONS_COLUMN_ID,EvolutionsTable.EVOLUTIONS_COLUMN_FROM,
EvolutionsTable.EVOLUTIONS_COLUMN_TO, EvolutionsTable.EVOLUTIONS_COLUMN_CONDITIONS};
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(
Arrays.asList(projection));
switch(uri){
case DIGIMON:
case DIGIMON_ID: availableColumns = new HashSet<String>(Arrays.asList(availableDigimon));
break;
case ATTACKS:
case ATTACKS_ID: availableColumns = new HashSet<String>(Arrays.asList(availableAttacks));
break;
case EVOLUTIONS:
case EVOLUTIONS_ID: availableColumns = new HashSet<String>(Arrays.asList(availableEvolutions));
break;
default: availableColumns = new HashSet<String>(Arrays.asList(availableDigimon));
}
// check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException(
"Unknown columns in projection");
}
}
}
public Cursor defaultMainMenu()
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON, new String[]{DigimonTable.DIGIMON_COLUMN_NAME, DigimonTable.DIGIMON_COLUMN_FAVOURITE}, null, null, DigimonTable.DIGIMON_COLUMN_NAME + " ASC");
int dummy = cursor.getCount();
return cursor;
}
public Cursor searchMenuQuery(String search)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON,new String[] {DigimonTable.DIGIMON_COLUMN_NAME,DigimonTable.DIGIMON_COLUMN_FAVOURITE},DigimonTable.DIGIMON_COLUMN_NAME+" = '?'",new String[]{search},DigimonTable.DIGIMON_COLUMN_NAME+" ASC");
int dummy = cursor.getCount();
return cursor;
}
public Cursor favouritesMenuQuery()
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON,new String[] {DigimonTable.DIGIMON_COLUMN_NAME},DigimonTable.DIGIMON_COLUMN_FAVOURITE+" = true",null,DigimonTable.DIGIMON_COLUMN_NAME+" ASC");
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonProfileQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_DIGIMON,null,DigimonTable.DIGIMON_COLUMN_NAME+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonAttacksQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_ATTACKS,null,AttacksTable.ATTACKS_COLUMN_DIGIMON+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonEvolutionFromQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_EVOLUTIONS,null,EvolutionsTable.EVOLUTIONS_COLUMN_FROM+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
public Cursor digimonEvolutionToQuery(String name)
{
Cursor cursor = MyApp.getContext().getContentResolver().query(CONTENT_URI_EVOLUTIONS,null,EvolutionsTable.EVOLUTIONS_COLUMN_TO+" = '?'",new String[]{name},null);
int dummy = cursor.getCount();
return cursor;
}
}
And here's the Logcat results:
Process: com.corvus.corvusenterprises.digimonapp, PID: 12198
java.lang.RuntimeException: Unable to get provider com.corvus.corvusenterprises.digimonapp.DigimonContentProvider: java.lang.NullPointerException
at android.app.ActivityThread.installProvider(ActivityThread.java:5084)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4673)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4613)
at android.app.ActivityThread.access$1800(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1298)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:895)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:711)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
at com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.onCreate(DigimonContentProvider.java:62)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1616)
at android.content.ContentProvider.attachInfo(ContentProvider.java:1587)
at android.app.ActivityThread.installProvider(ActivityThread.java:5081)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:4673)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4613)
at android.app.ActivityThread.access$1800(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1298)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:895)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:711)
at dalvik.system.NativeStart.main(Native Method)
Here's the DBHelper code, in case it helps:
package com.corvus.corvusenterprises.digimonapp;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import static com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.CONTENT_URI_ATTACKS;
import static com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.CONTENT_URI_DIGIMON;
import static com.corvus.corvusenterprises.digimonapp.DigimonContentProvider.CONTENT_URI_EVOLUTIONS;
/**
* Created by Jack on 01/05/2017.
*/
public class DBHelper extends SQLiteOpenHelper {
public static final String[]digimonArray = {
"Gigantic array of names"};
private static final String DATABASE_NAME = "DigimonDatabase.db";
private static final int version = 1;
private static DBHelper instance;
public static boolean[]presentDigimon = new boolean[digimonArray.length];
private DBHelper(Context context) {
super(context, DATABASE_NAME, null, version);
}
public static DBHelper getInstance(Context ctx) {
if (instance == null)
instance = new DBHelper(ctx);
return instance;
}
#Override
public void onCreate(SQLiteDatabase db) {
DigimonTable.onCreate(db);
AttacksTable.onCreate(db);
EvolutionsTable.onCreate(db);
}
public void onUpgrade(SQLiteDatabase db, int oldver, int newVer)
{
DigimonTable.onUpgrade(db,oldver,newVer);
AttacksTable.onUpgrade(db,oldver,newVer);
EvolutionsTable.onUpgrade(db,oldver,newVer);
}
public void insertDigimon(String name, String dub_name, String level, String attribute, String description, String favourite, String path)
{
DigimonContentProvider dcp = DigimonContentProvider.getInstance();
ContentValues values = new ContentValues();
values.put(DigimonTable.DIGIMON_COLUMN_NAME,name);
values.put(DigimonTable.DIGIMON_COLUMN_DUB_NAME,dub_name);
values.put(DigimonTable.DIGIMON_COLUMN_LEVEL,level);
values.put(DigimonTable.DIGIMON_COLUMN_ATTRIBUTE,attribute);
values.put(DigimonTable.DIGIMON_COLUMN_DESCRIPTION,description);
values.put(DigimonTable.DIGIMON_COLUMN_FAVOURITE, favourite);
values.put(DigimonTable.DIGIMON_COLUMN_PATH,path);
dcp.insert(CONTENT_URI_DIGIMON, values);
}
public void insertAttack(String name, String dub_name, String digimon, String description)
{
DigimonContentProvider dcp = DigimonContentProvider.getInstance();
ContentValues values = new ContentValues();
values.put(AttacksTable.ATTACKS_COLUMN_NAME, name);
values.put(AttacksTable.ATTACKS_COLUMN_DUB_NAME,dub_name);
values.put(AttacksTable.ATTACKS_COLUMN_DIGIMON, digimon);
values.put(AttacksTable.ATTACKS_COLUMN_DESCRIPTION, description);
dcp.insert(CONTENT_URI_ATTACKS, values);
}
public void insertEvolution(String from, String to, String conditions)
{
DigimonContentProvider dcp = DigimonContentProvider.getInstance();
ContentValues values = new ContentValues();
values.put(EvolutionsTable.EVOLUTIONS_COLUMN_TO,to);
values.put(EvolutionsTable.EVOLUTIONS_COLUMN_FROM,from);
values.put(EvolutionsTable.EVOLUTIONS_COLUMN_CONDITIONS,conditions);
dcp.insert(CONTENT_URI_EVOLUTIONS, values);
}
}
Any and all help appreciated. If you need more information, just let me know.
(EDITED): New version being worked on. Code updated.
(EDITED 2): Fixed a possible issue with recursive calls.
I know for a fact that the Context isn't null
How do you know that? MyApp.getContext() looks strange to me.
Try giving the Context to the ContentProvider
private Context mContext;
private DigimonContentProvider(Context context)
{
this.mContext = context;
}
private DigimonContentProvider() { }
public static DigimonContentProvider getInstance(Context context) {
if (instance == null)
instance = new DigimonContentProvider(context);
return instance;
}
#Override
public boolean onCreate() {
dbHelper = DBHelper.getInstance(this.mContext);
However, you don't need a ContentProvider to have a database, so try getting the database working without it.
It is throwing a NullPointerException because you are trying to access your ContentProvider methods directly instead of using a ContentResolver for the same.
You can abstract the code you have written in the ContentProvider to access it in an another class. And this time use a ContentResolver instance for the same.
Edit:
Maybe your problem is that your dbHelper is not singleton and you are creating an another instances of it through dbHelper.getInstance(getContext) in insert() method.
Try getting a new instance of dbHelper only in onCreate() method and not in other methods.
You can use this example: MoviesContentProvider.java
I began to study the mechanism ContentProvider I decided to write a simple example, when one application uses the data of another. My goal is to implement update, delete, and insert requests to the database.
I wrote the provider and the provider's client, insert is working, but update and delete requests applies to the entire table, rather than to a specific record.
I can't understand, what am I doing wrong?
Here is my provider:
public class MyProvider extends ContentProvider {
final String LOG_TAG = "myLogs";
static final String DB_NAME = "mydb";
static final int DB_VERSION = 1;
static final String CONTACT_TABLE = "_id";
static final String CONTACT_id = "_id";
static final String CONTACT_NAME = "name";
static final String CONTACT_EMAIL = "email";
static final String DB_CREATE = "create table "+CONTACT_TABLE+"("+
CONTACT_id+" integer primary key autoincrement,"+
CONTACT_NAME+ " text,"+
CONTACT_EMAIL+" text);";
static final String AUTHORITY = "com.dandewine.user.contentprovider.AddressBook";
static final String CONTACT_PATH = "contacts";
public static final Uri CONTACT_CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+CONTACT_PATH);
static final String CONTACT_CONTENT_TYPE = "vnd.android.cursor.item/vnd."+AUTHORITY+"."+CONTACT_PATH;
static final int URI_CONTACT = 1;
static final int URI_CONTACT_ID = 2;
private static final UriMatcher uriMatcher;
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, CONTACT_PATH, URI_CONTACT);
uriMatcher.addURI(AUTHORITY, CONTACT_PATH + "/#", URI_CONTACT);
}
DBHelper helper;
SQLiteDatabase db;
#Override
public boolean onCreate(){
Log.d(LOG_TAG,"onCreate");
helper = new DBHelper(getContext());
return true;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.d(LOG_TAG,"query, "+uri.toString());
switch (uriMatcher.match(uri)){
case URI_CONTACT:
Log.d(LOG_TAG,"URI_CONTACTS");
if(TextUtils.isEmpty(sortOrder))
sortOrder=CONTACT_NAME+" ASC";
break;
case URI_CONTACT_ID:
String id = uri.getLastPathSegment();
Log.d(LOG_TAG,"URI_CONTACTS_ID,"+id);
if(TextUtils.isEmpty(selection))
selection=CONTACT_id+" = "+id;
else
selection=selection+" AND "+CONTACT_id+" = "+id;
break;
default:throw new IllegalArgumentException("Wrong URI: "+uri);
}
db = helper.getWritableDatabase();
Cursor cursor = db.query(CONTACT_TABLE,projection,selection,selectionArgs,null,null,sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(),CONTACT_CONTENT_URI);
return cursor;
}
#Override
public String getType(Uri uri) {
Log.d(LOG_TAG, "getType, " + uri.toString());
switch (uriMatcher.match(uri)) {
case URI_CONTACT:
return CONTACT_CONTENT_TYPE;
case URI_CONTACT_ID:
return CONTACT_CONTENT_TYPE;
}
return null;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
Log.d(LOG_TAG,"insert, "+uri.toString());
if(uriMatcher.match(uri)!=URI_CONTACT)
throw new IllegalArgumentException("Wrong URI: "+uri);
db = helper.getWritableDatabase();
long rowID = db.insert(CONTACT_TABLE,null,values);
Uri resultURI = ContentUris.withAppendedId(CONTACT_CONTENT_URI,rowID);
getContext().getContentResolver().notifyChange(resultURI,null);
return resultURI;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.d(LOG_TAG,"delete, "+uri.toString());
switch(uriMatcher.match(uri)){
case URI_CONTACT:
Log.d(LOG_TAG,"URI_CONTACT");
break;
case URI_CONTACT_ID:
String id = uri.getLastPathSegment();
Log.d(LOG_TAG,"URI_CONTACTS_ID, "+id);
if(TextUtils.isEmpty(selection))
selection=CONTACT_id+" = "+id;
else
selection = selection + " AND "+CONTACT_id+" = "+id;
break;
default:throw new IllegalArgumentException("Wrong URI: "+uri);
}
db = helper.getWritableDatabase();
int cnt = db.delete(CONTACT_TABLE,selection,selectionArgs);
getContext().getContentResolver().notifyChange(uri,null);
return cnt;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.d(LOG_TAG, "update, " + uri.toString());
switch (uriMatcher.match(uri)) {
case URI_CONTACT:
Log.d(LOG_TAG, "URI_CONTACTS");
break;
case URI_CONTACT_ID:
String id = uri.getLastPathSegment();
Log.d(LOG_TAG, "URI_CONTACTS_ID, " + id);
if (TextUtils.isEmpty(selection)) {
selection = CONTACT_id + " = " + id;
} else {
selection = selection + " AND " + CONTACT_id + " = " + id;
}
break;
default:
throw new IllegalArgumentException("Wrong URI: " + uri);
}
db = helper.getWritableDatabase();
int cnt = db.update(CONTACT_TABLE, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return cnt;
}
private class DBHelper extends SQLiteOpenHelper{
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_CREATE);
ContentValues cv = new ContentValues();
for (int i = 0; i <=3 ; i++) {
cv.put(CONTACT_NAME,"name "+i);
cv.put(CONTACT_EMAIL,"email "+i);
db.insert(CONTACT_TABLE,null,cv);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
Here is client app:
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>,
View.OnClickListener {
final String LOG_TAG = "myLogs";
static final Uri CONTACT_URI = Uri.parse("content://com.dandewine.user.contentprovider.AddressBook/contacts");
SimpleCursorAdapter adapter;
final String CONTACT_NAME = "name";
final String CONTACT_EMAIL = "email";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String from[] = {"name","email"};
int to[] = {android.R.id.text1,android.R.id.text2};
adapter =new SimpleCursorAdapter(this,android.R.layout.simple_list_item_2,null,from,to,0);
ListView lvContact = (ListView)findViewById(R.id.lvContact);
lvContact.setAdapter(adapter);
getSupportLoaderManager().initLoader(0,null,this);
}
#Override
public void onClick(View v) {
Log.d(LOG_TAG,"onClick");
ContentValues cv = new ContentValues();
Uri uri;
int count;
switch (v.getId()){
case R.id.btnInsert:
cv.put(CONTACT_EMAIL,"email 4");
cv.put(CONTACT_NAME,"name 4");
uri = getContentResolver().insert(CONTACT_URI,cv);
Log.d(LOG_TAG,"insert, result Uri: "+uri.toString());
Toast.makeText(this,"Insert",Toast.LENGTH_SHORT).show();
break;
case R.id.btnDelete:
uri = ContentUris.withAppendedId(CONTACT_URI,3);
count = getContentResolver().delete(uri,null,null);
Log.d(LOG_TAG,"delete, count = "+count);
Toast.makeText(this,"Delete",Toast.LENGTH_SHORT).show();
break;
case R.id.btnUpdate:
cv.put(CONTACT_NAME,"name 5");
cv.put(CONTACT_EMAIL,"email 5");
uri = ContentUris.withAppendedId(CONTACT_URI,2);
count = getContentResolver().update(uri,cv,null,null);
Log.d(LOG_TAG,"update, count ="+count);
Toast.makeText(this,"Update",Toast.LENGTH_SHORT).show();
break;
case R.id.btnError:
Toast.makeText(this,"Error",Toast.LENGTH_SHORT).show();
uri = Uri.parse("content://com.dandewine.user.contentprovider.AddressBook/phones");
try{
Cursor cursor = getContentResolver().query(uri,null,null,null,null);
}catch (Exception ex){
Log.d(LOG_TAG, "Error: " + ex.getClass() + ", " + ex.getMessage());
}
break;
}
getSupportLoaderManager().getLoader(0).forceLoad();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new MyLoader(this,CONTACT_URI);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
private static class MyLoader extends android.support.v4.content.CursorLoader{
Uri uri;
public MyLoader(Context context,Uri uri) {
super(context,uri,null, null, null, null);
this.uri=uri;
}
#Override
public Cursor loadInBackground() {
return getContext().getContentResolver().query(uri,null,null,null,null);
}
}
}
I am populating a ListView using a SimpleCursorAdapter
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] projection = new String[] { BlogTable.TITLE_PLAIN, BlogTable.DATE_MODIFIED, BlogTable.EXCERPT, BlogTable.ID };
CursorLoader loader = new CursorLoader(parent, BlogContentProvider.CONTENT_URI, projection, null, null, BlogTable.DATE_MODIFIED + " DESC LIMIT " + BlogContentProvider.QUERY_LIMIT);
return loader;
}
private void fillData(){
//_id is expected from this method that is why we used it earlier
String[] from = new String[] { BlogTable.TITLE_PLAIN, BlogTable.DATE_MODIFIED, BlogTable.EXCERPT};
int[] to = new int[] { R.id.text_news_title, R.id.text_news_date, R.id.text_news_excerpt};
//initialize loader to call this class with a callback
getLoaderManager().initLoader(0, null, this);
//We create adapter to fill list with data, but we don't provide any data as it will be done by loader
adapter = new SimpleCursorAdapter(parent, R.layout.news_list_view, null, from, to, 0);
setListAdapter(adapter);
}
I want to load only 10 items at a time and then at the end of the list call a method addData() and get 10 more rows and so on. I know there is the CWAC EndlessAdapter for this, however I do not know what call to make to add another 10 rows to the current ListView and at the same time keep position.
I know this may sound like a stupid question but I am relatively new to Android development and still learning. Can anyone help?
EDIT:
This is the ContentProvider I am using, maybe it can be of help
package com.brndwgn.database;
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 BlogContentProvider extends ContentProvider {
private DbHelper dbh;
//identifiers for URI types
public static final int BLOG_LIST = 1;
public static final int BLOG_ITEM = 2;
//elements of our URI to identify our COntentProvider
public static final String AUTHORITY = "com.brndwgn.database";
public static final String BASE_PATH = "blog";
//URI to query from this Content provider
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
//MIME data types we offer
public static final String BLOG_LIST_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/bloglist";
public static final String BLOG_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/blogitem";
public static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
//patterns for our provider
static {
matcher.addURI(AUTHORITY, BASE_PATH, BLOG_LIST);
matcher.addURI(AUTHORITY, BASE_PATH + "/#", BLOG_ITEM);
}
public static final int QUERY_LIMIT = 2;
#Override
public boolean onCreate() {
dbh = new DbHelper(getContext());
return true;
}
#Override
public String getType(Uri uri) {
int uriId = matcher.match(uri);
//we check id of URI and return correct MIME type, we defined all of them before
switch(uriId) {
case BLOG_ITEM: return BLOG_ITEM_TYPE;
case BLOG_LIST: return BLOG_LIST_TYPE;
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
int uriId = matcher.match(uri);
//we create object of SQL query builder so we don't need to use plain SQL
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
//Set a name for the table to query
builder.setTables(BlogTable.TABLE_NAME);
switch(uriId) {
case BLOG_ITEM:
//set where condition to get just one row
builder.appendWhere(BlogTable.ID + "=" + uri.getLastPathSegment());
break;
case BLOG_LIST:
//we don't need to do anything here
break;
default:
new IllegalArgumentException("Unknown uri: " + uri);
}
//get instance of database
SQLiteDatabase db = dbh.getReadableDatabase();
//execute query
Cursor cursor = builder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
//set notifications for this URI
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriId = matcher.match(uri);
int deleted=0;
SQLiteDatabase db = dbh.getWritableDatabase();
switch(uriId) {
case BLOG_LIST:
deleted = db.delete(BlogTable.TABLE_NAME, selection, selectionArgs);
break;
case BLOG_ITEM:
if(TextUtils.isEmpty(selection)) {
deleted = db.delete(BlogTable.TABLE_NAME, BlogTable.ID + "=" + uri.getLastPathSegment(), selectionArgs);
}
else {
deleted = db.delete(BlogTable.TABLE_NAME, selection + " and " + BlogTable.ID + "=" + uri.getLastPathSegment(), selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknow uri: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return deleted;
}
#Override
public Uri insert(Uri uri, ContentValues values) {
int uriId = matcher.match(uri);
//Variable for ID of new record
long newId;
switch(uriId) {
case BLOG_LIST:
//get instance of Database
SQLiteDatabase db = dbh.getWritableDatabase();
//execute query
newId = db.replace(BlogTable.TABLE_NAME, null, values);
//newId = db.insertWithOnConflict(BlogTable.TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_IGNORE);
//create URI for new added record
Uri newuri = Uri.parse(CONTENT_URI + "/" + newId);
//notify change for list URI
getContext().getContentResolver().notifyChange(uri, null);
return newuri;
default:
throw new IllegalArgumentException("Unknown uri: " + uri);
}
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriId = matcher.match(uri);
int updated=0;
SQLiteDatabase db = dbh.getWritableDatabase();
switch(uriId) {
case BLOG_LIST:
updated = db.update(BlogTable.TABLE_NAME, values, selection, selectionArgs);
break;
case BLOG_ITEM:
if(TextUtils.isEmpty(selection)) {
updated = db.update(BlogTable.TABLE_NAME, values, BlogTable.ID + "=" + uri.getLastPathSegment(), null);
}
else {
updated = db.update(BlogTable.TABLE_NAME, values, selection + " and " + BlogTable.ID + "=" + uri.getLastPathSegment(), selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return updated;
}
}
Use
adapter.notifyDataSetChanged();
where adapter is your SimpleCursorAdapter for the listview
Edit:
before that you should add data to your adapter. To achieve this, add a method for your adapter to query from the database.