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)
Related
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.
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")
I was wanted to customize my textviews in SimpleCursorAdapter can someone help me to do that in a easiest way where too many code changes is not required...
Below is my working code where i am fetching strings from a class and inserting in SimpleCursorAdapter
code :
public class MyListActivity extends ListActivity {
/** Called when the activity is first created. */
private Cursor mCursor = null;
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.weeklysettings);
getListView().addHeaderView(buildHeader(), null , false);
Cursor mCursor = getCursorDetails();
startManagingCursor(mCursor);
ListAdapter adapter = new SimpleCursorAdapter(this, // Context.
R.layout.listview, // Specify the row template
// to use (here, three
// columns bound to the
// two retrieved cursor
// rows).
mCursor, // Pass in the cursor to bind to.
// Array of cursor columns to bind to.
new String[] { MyClass.EVENT,
MyClass.CHANNEL_NAME,
MyClass.PROGRAM_TITLE,
MyClass.EVENTTIME },
new int[] { R.id.event, R.id.channelname, R.id.programtitle, R.id.timestamp});
// Bind to our new adapter.
setListAdapter(adapter);
//setListAdapter(new ArrayAdapter<String>(this, R.layout.listview, ynetList));
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
stopManagingCursor(mCursor);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
startManagingCursor(mCursor);
}
private ViewGroup buildHeader() {
LayoutInflater infalter = getLayoutInflater();
ViewGroup header = (ViewGroup) infalter.inflate(R.layout.listitem_header, getListView(), false);
header.setEnabled(false);
return(header);
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
Intent intent = new Intent(this, SettingsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
finish();
super.onBackPressed();
}
private Cursor getCursorDetails() {
String sortOrder = DataExchangeFacility.TIMESTAMP
+ " COLLATE LOCALIZED DESC";
mCursor = getApplicationContext().getContentResolver().query(
DataExchangeFacility.CONTENT_URI_GRACE, null, null, null, sortOrder);
return mCursor;
}
}
Give this a shot:
ListAdapter adapter = new SimpleCursorAdapter(this, // Context.
R.layout.listview, // Specify the row template
// to use (here, three
// columns bound to the
// two retrieved cursor
// rows).
mCursor, // Pass in the cursor to bind to.
// Array of cursor columns to bind to.
new String[] { MyClass.EVENT,
MyClass.CHANNEL_NAME,
MyClass.PROGRAM_TITLE,
MyClass.EVENTTIME },
new int[] { R.id.event, R.id.channelname, R.id.programtitle, R.id.timestamp}) {
#Override
public void setViewText(TextView v, String text) {
// v is your TextView
v.setTextColor(Color.RED);
super.setViewText(v, text);
}
};
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.
My ListView currently is able to display only one column data. I want it to display two column data.
Here is the code for my ListView:
public class ProjectExplorer extends ListActivity {
private projectdatabase database;
protected Cursor cursor;
protected ListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
database = new projectdatabase(ProjectExplorer.this);
getinfo();
}
private void getinfo() {
database.open();
cursor = database.getDataforDisplay();
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, new String[] {"project_name"}, new int[] { android.R.id.text1 }, 0);
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView parent, View view, int position, long id) {
super.onListItemClick(parent, view, position, id);
Cursor c = ((SimpleCursorAdapter)parent.getAdapter()).getCursor();
c.moveToPosition(position);
// get project name here
String str_projectname= c.getString(c.getColumnIndex("project_name"));
Toast.makeText(this, str_projectname, Toast.LENGTH_LONG).show();
}
Here is the method in database class which return the cursor:
public Cursor getDataforDisplay () {
String[] columns = new String[] {KEY_ROWID, PROJECT_NAME, PROJECT_FINISH_DATE, PROJECT_DIFFICULTY, PROJECT_STATUS};
Cursor c = projectDatabase.query(DATABASE_TABLE, columns, null, null, null, null, null);
projectDatabase.query(DATABASE_TABLE, columns, null, null, null, null, null);
c.moveToFirst();
return c;
}
I also want to display KEY_ROWID which is defined as _id
You can use android.R.layout.simple_list_item_2 specifying column no.2 from table from where data can be retrieved and specifies location with help of it can be displayed on Activity - android.R.id.text2
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor, new String[] {"project_name","column_no2"}, new int[] { android.R.id.text1, andriod.R.id.text2 }, 0);
You can also create your on custom Adapter specifying your own Listview and creating it from scratch and customized everything.
The best way to achieve this at least in my opinion is to create custom Adapter for your ListView in that case you can set your own design how single listview element should look like . Just populate some arrays using your Cursor and set them to your custom adapter.