CursorLoader change cursor() doesn't refresh listview - android

I use approach resuest to server - listView - content provider in many projects and it works well. However I faced with really strange issue - notifyChange(uri, null) doesn't refresh data in listview automatically if I insert or delete data as well.
{
ListView listView = (ListView) findViewById(R.id.list);
View header = View.inflate(this, R.layout.header, null);
listView.addHeaderView(header);
adapter = new Adapter(this, R.layout.item, null, true);
listView.setAdapter(adapter);
getSupportLoaderManager().restartLoader(0, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
return new CursorLoader(this, Statuses.URI, null , null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
adapter.changeCursor(arg1);
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
adapter.changeCursor(null);
}
// inset method of content provider
long id = db.getWritableDatabase().insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_REPLACE);
Uri newUri = Uri.withAppendedPath(uri, Long.toString(id));
cr.notifyChange(newUri, null);
return newUri;
//delete method of contetn provider
int count = db.getWritableDatabase().delete(table, selection, selectionArgs);
cr.notifyChange(uri, null);
return count;
Do you any issues with this code?

Resolved. Forgot to add Uri before cursor has returned.

Related

retriveing data from exisint sqlite database

I wish to store it in arraylist and then display it out in listView. Is there any solution to it ? how do I set the adapter? how can I link this two up and display it into a listview using arrayList?
DBhelper.java
public ArrayList<String> getDataarray(){
SQLiteQueryBuilder querybuilder=new SQLiteQueryBuilder();
querybuilder.setTables(DATABASE_TABLES);
String [] columns= new String[]{ KEY_ROWID,KEY_USERNAME,KEY_AGE,KEY_ClINIC,KEY_PHONE,KEY_EMAIL,KEY_DATESIGNUP
,KEY_CONDITIONID,KEY_DOCTORID,KEY_LOGINID,KEY_ACTIVITYNAME,KEY_NOTIFICATIONNAME,KEY_GROUPNAME,KEY_APPROVED
};
Cursor c= ourdatabase.query(DATABASE_TABLES, columns, null,null, null, null, null);
String result="";
ArrayList<String> resultarray = new ArrayList<String>();
int iRow=c.getColumnIndex(KEY_ROWID);
int iUserName=c.getColumnIndex(KEY_USERNAME);
int iAge=c.getColumnIndex(KEY_AGE);
int iClinic=c.getColumnIndex(KEY_ClINIC);
int iPhone=c.getColumnIndex(KEY_PHONE);
int iEmail=c.getColumnIndex(KEY_EMAIL);
int iDateSignup=c.getColumnIndex(KEY_DATESIGNUP);
int iConditionID=c.getColumnIndex(KEY_CONDITIONID);
int iDoctorID=c.getColumnIndex(KEY_DOCTORID);
int iLoginID=c.getColumnIndex(KEY_LOGINID);
int iActivityName=c.getColumnIndex(KEY_ACTIVITYNAME);
int iNotificationName=c.getColumnIndex(KEY_NOTIFICATIONNAME);
int iGroupName=c.getColumnIndex(KEY_GROUPNAME);
int iApproved=c.getColumnIndex(KEY_APPROVED);
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT value FROM " + DATABASE_TABLES, null);
if(cursor.moveToFirst()) {
do {
resultarray.add(cursor.getString(cursor.getColumnIndex("value")));
}while(cursor.moveToNext());
}
cursor.close();
db.close();
return resultarray;
}
ProfileFragment.java this is the page where i want to retrieve out at the listView how can i retrieve it from the database instead of array
public View getView( int position ,View convertView,ViewGroup parent){
LayoutInflater inflater= (LayoutInflater) context.getSystemService(android.content.Context.LAYOUT_INFLATER_SERVICE);
View row =inflater.inflate(R.layout.profile_list,parent,false);
TextView myProfile=(TextView)row.findViewById(R.id.Profile);
TextView myCondition=(TextView)row.findViewById(R.id.condition);
myProfile.setText(ProfileArray[position]);
myCondition.setText(resultarray[position]);
return row;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.user,container,false);
Resources res=getResources();
Profile=res.getStringArray(R.array.Profile);
//how can i change the line below to let it get the data from the database array? or is there any other method?
condition=res.getStringArray(R.array.Profile_values);
list.setAdapter(adapter);
list=(ListView)rootview.findViewById(R.id.listView1);
return rootview;
}
Do you want to display all of data?
Think about using CursorLoader with SimpleCursorAdapter. It will load your data once activity is created in background. And in your activity class just implement interface LoaderManager.LoaderCallback, and in onCreate you simply initialize Loader with getSupportLoaderManager().initLoader(LOADER_ID, null, this)
Here is the link with good example http://www.androiddesignpatterns.com/2012/07/understanding-loadermanager.html
EDIT:
This code use in onCreate
// init DB
db = new DB(this);
db.open();
// forming columns from DB to views
String[] from = new String[] { KEY_ROWID, KEY_USERNAME, KEY_AGE...}; //array of columns from DB
int[] to = new int[] { R.id.textviewId, R.id.textviewUserName, R.id.textviewAge }; //Array of of view components
// create adapter
scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);
ListView lvData = (ListView) findViewById(R.id.lvData); // listview where you want to display data
lvData.setAdapter(scAdapter);
//init loader
getSupportLoaderManager().initLoader(0, null, this);
//implement these mothods with interface `LoaderManager.LoaderCallback<Cursor>`
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle bndl) {
return new MyCursorLoader(this, db);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
scAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
This code must works for you.
EDIT2
static class MyCursorLoader extends CursorLoader {
DB db;
public MyCursorLoader(Context context, DB db) {
super(context);
this.db = db;
}
#Override
public Cursor loadInBackground() {
return db.getAllData();
}
}
One detail added. This is a class where you download your data from db and return filled cursor.

Deleting items from list view bug

So i have a problem with my listview when i delete data from my database.
The problem is that some other items in my list view get mest up
i have noted that when i delete the second from the bottom the problem occurs
Database
//getRowRevers
public Cursor getAllRowre(){
String where=null;
String orderBy = ID_KEY + " DESC";
Cursor cursor=db.query(true, DATABASE_TABLE, ALL_KEY, where, null, null, null,ID_KEY + " DESC", null);
if(cursor!=null){
cursor.moveToFirst();
}
return cursor;
}
//delete
public boolean deleatRow(String idRow){
String where=ID_KEY+"="+idRow;
return db.delete(DATABASE_TABLE, where, null) != 0;
}
public void deleatAll(){
Cursor cursor=getAllRowre();
long idRow=cursor.getColumnIndexOrThrow(ID_KEY);
if(cursor.moveToFirst()){
do{
deleatRow(cursor.getString((int) idRow));
}while(cursor.moveToNext());
}
}
So here is how i managed to get the list view working i think this method is not the best and maybe this is the reason and i don't know how to do it in a different way
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
int mySuperInt=dbJ.countCases()+ 1 -position-2;
Intent myIntent = new Intent(getActivity(), JornalListViewClick.class);
myIntent.putExtra("intVariableName",mySuperInt);
startActivity(myIntent);
}
});
PS the list view is always changing when the user pass data

Listview showing sorted data instead of how it is stored in database

I am populating my ListView from a Database according to the code shown below in a Fragment which implements CursorLoader. Earlier I was using SimpleCursorAdapter for the same purpose but I had to change to ArrayAdapter for some reasons.
The Database have only two columns:
_id(integer primary key autoincrement) and message(string not null)
The ListView is working fine but the problem is that the strings shown in the listview are automatically sorted alphabetically and not in the order they were stored. Whereas I did not face this problem while using SimpleCursorAdapter.
Could anyone please tell what I'm doing wrong this time and how to correct it.
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
String[] projection = {KEY_ROWID, KEY_MESSAGE};
CursorLoader cursorLoader = new CursorLoader(getActivity(),
CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if(cursor != null){
msgList = new ArrayList<String>();
cursor.moveToFirst();
while(cursor.isAfterLast() == false){
msgList.add(cursor.getString(1).toString());
cursor.moveToNext();
}
}
mAdapter = new ArrayAdapter<String>(getActivity(), R.layout.msg_list, R.id.list_textView, msgList);
listview.setAdapter(mAdapter);
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
if (mAdapter != null)
listview.setAdapter(null);
}
Thanks
The data from a DB is always fetched in an unpredictable order.
You have to specify the column/s against which you want the data to be sorted and the order direction for each column (default: ASC).
Try using CursorLoader(..., KEY_ROWID + " DESC")

Android ListView: how to avoid database query in bindView()? Need to fetch one to many relationship data

I have a list view to display albums. In each album list item, I need to display some information from each photo in this album. Here is how my cursor loader looks like:
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(this, AlbumsColumns.CONTENT_URI, null, null, null, null);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
long albumId = cursor.getLong(cursor.getColumnIndex(AlbumsColumns._ID));
Cursor photoCursor = getContentResolver().query(PhotosColumns.CONTENT_URI, null, PhotosColumns.ALBUM_ID + " = ?",
new String[]{Long.toString(albumId)}, null);
if (photoCursor.moveToFirst()){
do{
// Here I collect the information from each photo in the album
}while(photoCursor.moveToNext());
}
photoCursor.close();
}
Basically, I let the cursor loader manage the album query, and each time in the bindView I query the photos from the passed in album cursor. I feel this can be a performance issue. Is there a better way doing this?
Just got an idea: use another cursor loader inside the list item. So this will be like two level cursor loader. I'll post my results later.
Edit:
The proposed idea should be the right way handling the issue. So my code is refactored like this:
// In the list view activity:
#Override
public void bindView(View view, Context context, Cursor cursor) {
AlbumListItem albumListItem = (AlbumListItem)view;
albumListItem.prepareView(getLoaderManager(), cursor);
}
// AlbumListItem is a class that has a cursor loader to query photos:
public class AlbumListItem extends RelativeLayout implements LoaderManager.LoaderCallbacks<Cursor>{
public void prepareView(LoaderManager loaderManager, Cursor albumCursor){
albumId = albumCursor.getLong(albumCursor.getColumnIndex(AlbumsColumns._ID));
// Other init stuff
loaderManager.initLoader(UNIQUE_LOADER_ID, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// Here is the async query part.
return new CursorLoader(context, PhotosColumns.CONTENT_URI, null, PhotosColumns.ALBUM_ID + " = ?", new String[]{Long.toString(albumId)}, null);
}
}

Multiple Loaders with LoaderManager, not getting right Loader

I have two loaders, one to populate bind returned data to 2 TextViews and another to populate a ListView. How do I make sure the correct loader loads for each situation? I am getting an error in the where first loader (WR_VIEW case) doesn't seem to be created or loading so in the onLoadFinished() it returns a "No such column found error" because it is accessing the second loader which doesn't call that column.
Here in my onCreate method I set up the adapter for the list view:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.workouts_options);
String[] uiBindFrom = { ExerciseTable.COLUMN_NAME };
int[] uiBindTo = { R.id.text1 };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
getApplicationContext(),
R.layout.exercises_row,
null,
uiBindFrom,
uiBindTo,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
final ListView lv = (ListView) findViewById(android.R.id.list);
lv.setAdapter(adapter);
lv.setEmptyView(findViewById(android.R.id.empty));
lv.setClickable(true);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long id) {
}
});
getSupportLoaderManager().initLoader(WR_VIEW, null, this);
getSupportLoaderManager().initLoader(EXERCISE_VIEW, null, this);
}
Create my 2 different CursorLoaders:
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch(id) {
case WR_VIEW:
String[] projection = { WorkoutRoutineTable.COLUMN_ID, WorkoutRoutineTable.COLUMN_NAME, WorkoutRoutineTable.COLUMN_DESCRIPTION };
return new CursorLoader(this, Workouts.buildWorkoutIdUri(""+mRowId), projection, null, null, null);
default:
String[] columns = {ExercisesColumns.NAME, WRExercisesColumns.COLUMN_ID };
return new CursorLoader(this, Workouts.buildWorkoutIdExerciseUri(""+mRowId), columns, null, null, null);
}
}
Bind data to my TextViews here and swapCursor for the ListView:
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
int id = loader.getId();
switch(id) {
case WR_VIEW:
if (cursor != null && cursor.moveToFirst()) {
mNameText.setText(cursor.getString(cursor.getColumnIndexOrThrow(WorkoutRoutineTable.COLUMN_NAME)));
mDescriptionText.setText(cursor.getString(cursor.getColumnIndexOrThrow(WorkoutRoutineTable.COLUMN_DESCRIPTION)));
getSupportActionBar().setTitle(mNameText.getText());
if (!TextUtils.isEmpty(mDescriptionText.getText())) {
getSupportActionBar().setSubtitle(mDescriptionText.getText());
}
cursor.close();
}
default:
adapter.swapCursor(cursor);
}
}
Resetting the Loader:
public void onLoaderReset(Loader<Cursor> loader) {
int id = loader.getId();
switch(id) {
case WR_VIEW:
break;
default:
adapter.swapCursor(null);
break;
}
}
In your onLoadFinished() you don't have a break after WR_VIEW case, so the default clause is getting run as well, passing the wrong cursor to your adapter. (onCreateLoader seems to have a similar issue as well)

Categories

Resources