ContentProvider update() doesn't work - java

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.

Related

RecyclerView not updating after creating or deleting playlists in Fragments

I am trying to update my recyclerView by notifyDataSetChanged(). But it's not working. I have to close my specific fragment and open it to see the changes.
This is MyFragment where I call recyclerView
BottomSheetFragment.java
// showing Playlist Names
recyclerPlayListViewName =
bottomView.findViewById(R.id.recycler_play_list_view_name);
playlists = new ArrayList<Playlist>();
PlayListMethodHolder.getplaylistList(getContext(), playlists);
playlistAdapter = new PlaylistAdapter(bottomView.getContext(), playlists,
"bottomsheet");
recyclerPlayListViewName.setHasFixedSize(true);
recyclerPlayListViewName.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerPlayListViewName.setAdapter(playlistAdapter);
playlistAdapter.notifyDataSetChanged();
This is AdapterClass where I call to delete the playlist method.
PlaylistAdapter.java
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
long plistID = playlists.get(position).getId();
switch (item.getItemId()) {
case R.id.pPlay:
break;
case R.id.pRename:
String dpType = "playlistRename";
PlayListPopDialog popDialog = new PlayListPopDialog(mContext,
dpType, plistID, playlists);
popDialog.show();
break;
case R.id.pDelete:
PlayListMethodHolder.deletePlaylist(mContext, plistID);
break;
And This is another DialogView where I call Create PlayList
PlayListPopDialog.java
findViewById(R.id.btn_playlist_save).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
EditText edtCreateNamePlaylist = findViewById(R.id.edt_create_name_playlist);
String playlistName = edtCreateNamePlaylist.getText().toString().trim();
if (!(playlistName.isEmpty())) {
boolean state = PlayListMethodHolder
.doPlaylistExists(getContext(), playlistName);
if (!state) {
PlayListMethodHolder.createPlaylist(getContext(), playlistName);
dismiss();
} else {
Toast.makeText(getContext(), "This name is already exists.",
Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getContext(), "Empty name", Toast.LENGTH_SHORT).show();
}
}
});
Finally, this is a class for holding all methods of creating or deleting PlayLists
PlayListMethodHolder.java
public class PlayListMethodHolder {
public static void createPlaylist(Context context, String playlistName) {
String[] projectionName = new String [] {
MediaStore.Audio.Playlists._ID,
MediaStore.Audio.Playlists.NAME,
MediaStore.Audio.Playlists.DATA,
};
ContentValues nameValues = new ContentValues();
nameValues.put(MediaStore.Audio.Playlists.NAME, playlistName);
nameValues.put(MediaStore.Audio.Playlists.DATE_ADDED,
System.currentTimeMillis());
nameValues.put(MediaStore.Audio.Playlists.DATE_MODIFIED,
System.currentTimeMillis());
Uri uri = context.getApplicationContext().getContentResolver()
.insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, nameValues);
if (uri != null) {
context.getApplicationContext().getContentResolver()
.query(uri, projectionName, null, null, null);
context.getApplicationContext().getContentResolver().notifyChange(uri, null);
}
}
// Delete single playlist from list
public static void deletePlaylist (#NonNull final Context context, long playlistId){
String playlistid = String.valueOf(playlistId);
ContentResolver resolver = context.getContentResolver();
String where = MediaStore.Audio.Playlists._ID + "=?";
String[] whereVal = {playlistid};
resolver.delete(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, where,
whereVal);
return ;
}
// get Playlist names
public static void getplaylistList(Context context, ArrayList<Playlist> plist) {
Cursor playlistCursor = context.getContentResolver().query(
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
null,
null,
null,
null);
if (playlistCursor != null && playlistCursor.moveToFirst()) {
//get columns
int idColumn = playlistCursor.getColumnIndex
(MediaStore.Audio.Playlists._ID);
int titleColumn = playlistCursor.getColumnIndex
(MediaStore.Audio.Playlists.NAME);
do {
long thisId = playlistCursor.getLong(idColumn);
String thisTitle = playlistCursor.getString(titleColumn);
plist.add(new Playlist(thisId, thisTitle));
} while (playlistCursor.moveToNext());
}
}
Tap to see PlayList Design View

How would I also be able to get the phone number from the contact the user picked?

I am able to get the contact name that the user chose but not the phonenumber
In the onclick :
Intent intent = new Intent(Intent.ACTION_PICK,
ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent,PICK_CONTACT);
PICK_CONTACT is just an int value that equals one its my requestcode
then:
#Override
protected void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
if (reqCode == PICK_CONTACT) {
if (resultCode == AppCompatActivity.RESULT_OK) {
Uri contactData = data.getData();
Cursor c = getContentResolver().query(contactData, null, null, null, null);
if (c.moveToFirst()) {
String name = c.getString(c.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
contactadder.setText(name);
c.close();
}
Here is a little snippet of my work which perhaps might help you to get the right direction. Android database interaction is poorly documented and hard to find the right way/values. Just reply if you need more help to understand. I removed some business relevant data out, so it will not compile this way. Just for easy post!
public static final String[] PROJECTION ={
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.DATA1,
ContactsContract.Data.DATA2,
ContactsContract.Data.DATA3,
ContactsContract.Data.DATA4,
ContactsContract.Data.DATA5,
ContactsContract.Data.DATA6,
ContactsContract.Data.DATA7,
ContactsContract.Data.DATA8,
ContactsContract.Data.DATA9,
ContactsContract.Data.DATA10,
ContactsContract.Data.DATA11,
ContactsContract.Data.DATA12,
ContactsContract.Data.DATA13,
ContactsContract.Data.DATA14,
ContactsContract.Data.DATA15
};
private static final int MIMETYPE_COLUMN=0;
private static final int DATA_COLUMN=1;
private static final int DATATYPE_COLUMN=2;
private static final String SELECTION = ContactsContract.Data.CONTACT_ID + " = ?";
public static ContactWrapper localContact(long contactId){
Cursor cursor = getContentResolver().query(ContactsContract.Data.CONTENT_URI,PROJECTION, SELECTION, new String[]{String.valueOf(contactId)}, null);
ContactWrapper wrapper = new ContactWrapper(contact);
if(cursor==null){
return wrapper;
}
while(cursor.moveToNext()){
String mime=cursor.getString(MIMETYPE_COLUMN);
if (mime.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)) {
contact.setU8sDisplayName(cursor.getString(DATA_COLUMN));
} else if (mime.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
putPhoneNumber(contact, cursor);
} else if (mime.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
putEmail(contact, cursor);
} else if (mime.equals(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)) {
putAddress(contact, cursor);
}else if (mime.equals(ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)) {
contact.setU8sSIPAddress(cursor.getString(DATA_COLUMN));
}else if (mime.equals(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)) {
wrapper.setImageBinaryString(getContactPhotoBase64(contactId));
}
}
cursor.close();
return wrapper;
}
private static void putPhoneNumber(ContactWrapper contact,Cursor data){
switch (data.getInt(DATATYPE_COLUMN)){
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
contact.setU8sPhoneHome(data.getString(DATA_COLUMN));
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
contact.setU8sPhoneMobile(data.getString(DATA_COLUMN));
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
contact.setU8sPhoneBusiness(data.getString(DATA_COLUMN));
break;
}
}

ContentProvider mHelper stays null

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.

ExpandableListView and SimpleCursorTreeAdapter with an SQLiteCursorLoader, getChildrenCursor not called

I'll start by saying i've researched this specific solution to death and am aware of the solutions "this has been solved HERE" and HERE, but I am unable to get these working. Other info: I'm using the compatibility library and also actionbarsherlock, which both have been working great, no issues there i dont think.
I haven an SQLite database that i want to fill my entries into expandable list grouped by date. I know that my database is correctly populated and here are the columns I have verified to contain proper data:
ID (1, 2, 3, 4, etc)
TITLE (some text)
URL (url as string)
DATE (ddMMyyyy)
where the date column data is like this: 22Dec2012 or 23Dec2012 etc.
There are many entries per date, i want to group those as children with the date as group. I see the database is filled with the correct info. I have a few problems, the main is that my getChildrenCursor never gets called, only the constructor gets called. Second is that per the linked examples, I cannot get the getSherlockActivity context into my adapter (nor does getActivity() work either, just for testing purposes). I'll explain the error with logcat below.
My Fragment
public class MyFragment extends SherlockFragment implements LoaderManager.LoaderCallbacks, OnItemClickListener {
public static MyFragment newInstance(String symbol) {
MyFragment f = new MyFragment();
Bundle args = new Bundle();
args.putString(Consts.INFO, info);
f.setArguments(args);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View myView = inflater.inflate(R.layout.fragment_layout3, container, false);
mListView = (ExpandableListView)myView.findViewById(R.id.expandableListView);
mListView.setOnItemClickListener(this);
return myView;
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onResume() {
super.onResume();
refresh();
}
public void refresh() {
Log.v(TAG, "refresh");
populateExpandableList();
loader = getLoaderManager().getLoader(-1);
if (loader != null && !loader.isReset()) {
getLoaderManager().restartLoader(-1, null, this);
} else {
getLoaderManager().initLoader(-1, null, this);
}
if (getLoaderManager().getLoader(0x9999) == null) {
getLoaderManager().initLoader(0x9999, null, this);
//getLoaderManager().initLoader(-1, null, this);
}
else {
getLoaderManager().restartLoader(0x9999, null, this);
//getLoaderManager().restartLoader(-1, null, this);
}
getLoaderManager().getLoader(0x9999).forceLoad();
//getLoaderManager().getLoader(1).forceLoad();
}
private void populateExpandableList() {
// Set up our adapter
Log.v(TAG, "Endtering setup adapter");
mDbHelper = new DBHelper(getSherlockActivity(), DBConstants.DATABASE_NAME, null, DBConstants.DATABASE_VERSION);
mAdapter = new MyExpandableAdapter(getSherlockActivity(), this,
R.layout.news_list_group,
R.layout.news_list_child,
new String[] { DBConstants.DATE_GROUP_NAME }, // Name for group layouts
new int[] { R.id.group_title },
new String[] { DBConstants.TITLE_NAME, DBConstants.URL_NAME }, // Name for child layouts
new int[] { R.id.item_title, R.id.item_value });
mListView.setAdapter(mAdapter);
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
}
#Override
public Loader onCreateLoader(int loaderId, Bundle args) {
topics = new ArrayList<String>();
if (loaderId == 0x9999) {
return new MyLoader(getSherlockActivity(), mHandler, topics.toArray(new String[topics.size()]));
}
if (loaderId != -1 && loaderId != 0x9999) {
Log.v(TAG, "CreateLoader child cursor: loader ID: "+loaderId);
// child cursor
mCursorLoader = new SQLiteCursorLoader(getSherlockActivity(), mDbHelper, "SELECT _ID, "+DBConstants.TITLE+", " +DBConstants.URL + ", " + DBConstants.TIME + ", " + DBConstants.STATUS + " FROM "+DBConstants.TABLE+" WHERE "+ DBConstants.KEY_ID+"="+String.valueOf(loaderId)+" ORDER BY "+DBConstants.TIME+" DESC", null);
return mCursorLoader;
}
else if (loaderId != 0x9999) {
Log.v(TAG, "CreateLoader group cursor: loader ID: "+loaderId);
// group cursor
mCursorLoader = new SQLiteCursorLoader(getSherlockActivity(), mDbHelper, "SELECT date, "+DBConstants.TITLE+", "+DBConstants.URL+" FROM "+DBConstants.TABLE, null);
return mCursorLoader;
}
return null;
}
#Override
public void onLoadFinished(Loader loader, Object result) {
Log.v(TAG, "onLoadFinished");
if(result != null /*&& result.length > 0*/) {
if (loader.getId() == 0x9999) {
getLoaderManager().restartLoader(-1, null, this);
getLoaderManager().getLoader(-1).forceLoad();
}
if (loader.getId() != -1 && loader.getId() != 0x9999) {
Log.v(TAG, "LoadFinished second loader: loaderID: "+loader.getId());
if (!((Cursor) result).isClosed()) {
Log.v(TAG, "data.getCount() " + ((Cursor) result).getCount());
HashMap<Integer,Integer> groupMap = mAdapter.getGroupMap();
try {
int groupPos = groupMap.get(loader.getId());
Log.v(TAG, "onLoadFinished() for groupPos " + groupPos);
mAdapter.setChildrenCursor(groupPos, (Cursor) result);
} catch (NullPointerException e) {
Log.w("DEBUG","Adapter expired, try again on the next query: "
+ e.getMessage());
}
}
else {
mAdapter.setGroupCursor((Cursor) result);
}
}
else {
}
}
}
#Override
public void onLoaderReset(Loader loader) {
int id = loader.getId();
Log.v(TAG, "onLoaderReset() for loader_id " + id);
if (id != -1) {
// child cursor
try {
mAdapter.setChildrenCursor(id, null);
} catch (NullPointerException e) {
Log.w("TAG", "Adapter expired, try again on the next query: "
+ e.getMessage());
}
} else {
mAdapter.setGroupCursor(null);
}
}
public class MyExpandableAdapter extends SimpleCursorTreeAdapter {
private final String TAG = getClass().getSimpleName().toString();
private MyFragment mFragment;
protected HashMap<Integer, Integer> mGroupMap = null;
public NewsFeedExpandableAdapter(Context context, MyFragment mf, int groupLayout, int childLayout, String[] groupFrom,
int[] groupTo, String[] childrenFrom, int[] childrenTo) {
super(context, null, groupLayout, groupFrom, groupTo, childLayout, childrenFrom, childrenTo);
mFragment = mf;
mGroupMap = new HashMap<Integer, Integer>();
Log.v(TAG, "Adapter constructor");
}
#Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
// Given the group, we return a cursor for all the children within that group
Log.v(TAG, "getChildrenCursor");
int groupPos = groupCursor.getPosition();
int groupId = groupCursor.getInt(groupCursor.getColumnIndex(DBConstants.TIME_GROUP_NAME));
Log.v(TAG, "getChildrenCursor() for groupPos " + groupPos);
Log.v(TAG, "getChildrenCursor() for groupId " + groupId);
mGroupMap.put(groupId, groupPos);
Loader loader = mFragment.getLoaderManager().getLoader(groupId);
if ( loader != null && !loader.isReset() ) {
mFragment.getLoaderManager().restartLoader(groupId, null, mFragment);
} else {
mFragment.getLoaderManager().initLoader(groupId, null, mFragment);
}
return null;
}
//Accessor method
public HashMap<Integer, Integer> getGroupMap() {
return mGroupMap;
}
}
}
Now in my adapter above, you see i'm using :
Loader loader = mFragment.getLoaderManager().getLoader(groupId);
if ( loader != null && !loader.isReset() ) {
mFragment.getLoaderManager().restartLoader(groupId, null, mFragment);
} else {
mFragment.getLoaderManager().initLoader(groupId, null, mFragment);
}
rather than this:
Loader loader = getSherlockActivity().getLoaderManager().getLoader(groupId);
if ( loader != null && !loader.isReset() ) {
getSherlockActivity().getLoaderManager().restartLoader(groupId, null, mFragment);
} else {
getSherlockActivity().getLoaderManager().initLoader(groupId, null, mFragment);
}
Because when i use getActivity or getSherlockActivity, the code gives an error on the first line above saying:
"Type mismatch, cannot convert from Loader<Object> to Loader"
and on the third and fifth line errors:
"The method restartLoader(int, Bundle, LoaderManager.LoaderCallbacks<D>) in the type LoaderManager is not applicable for the arguments (int, null, MyFragment)"
Does anyone possibly know why i cannot use getActivity here? It's driving me completely bonkers. So i attempt to use mFragment.getLoaderManager instead using the fragment i passed in to the adapter, but i dont know if this is even correct.
I placed breakpoints in the code and it shows that the adapter constructor is called, and that's it, getChildrenCursor never gets called ever. in the fragment breakpoints, it reaches "Create Group Loader id=-1" and thats it. in onLoadFinished only the first "onLoadFinished" tag get's shown in the log. It never makes it into the IF statements within onLoadFinished. When i check that the loadFinished result is not null in logcat, it shows as a cursor object being passed in to onLoadFinished, but something just isnt working right.
prior to trying expandable list, i was using these identical SQLiteCursorLoader's setup, just retrieving all columns, and they worked fine. I am absolutely admitting that maybe both my SELECT statements are not correct. but i've tried a ton of different select queries, and everytime i get same result, nothing. Can anyone PLEASE help me I'm desperate and going bonkers. Thanks.

Android - Dynamically ListView using SimpleCursorAdapter

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.

Categories