Populate ExpandableListView with data from SQLite - android

The setup: I have a local SQLite database holding showtimes for movies. Some of the columns are "Date", "ID", "Time"...
The intention:
I want to put all of these showtimes into a ExpandableListView while the dates are going to be the parent items.
The problem: Nothing is displayed. Nothing at all. And I struggle to understand why. Does anyone have an idea?
Some code: The most important stuff is up at the top, get's less and less important as you scroll down...
This is the code I'm trying to achieve this with which is called in the onCreate() of the Activity:
String sql = "SELECT rowid _id,* FROM " + Statics.DBSHOWS + ";";
Cursor movieCursor = database.rawQuery(sql,null);
movieCursor.moveToFirst();
adapter = new ExpandableListAdapter(movieCursor, this,
android.R.layout.simple_list_item_1,
android.R.layout.simple_list_item_2,
new String[]{Statics.DBSHOWS_DATE},
new int[]{android.R.id.text1},
new String[]{Statics.DBSHOWS_TIME, Statics.DBSHOWS_ID},
new int[]{android.R.id.text1, android.R.id.text2});
movieListView.setAdapter(adapter);
This is my ExpandableListAdapter:
public class ExpandableListAdapter extends SimpleCursorTreeAdapter {
Context context;
public ExpandableListAdapter(Cursor cursor, Context context, int groupLayout,
int childLayout, String[] groupFrom, int[] groupTo, String[] childrenFrom,
int[] childrenTo) {
super(context, cursor, groupLayout, groupFrom, groupTo,
childLayout, childrenFrom, childrenTo);
this.context = context;
}
#Override
protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
super.bindChildView(view, context, cursor, isLastChild);
System.out.println("Dumping form Childview");
DatabaseUtils.dumpCurrentRow(cursor);
}
#Override
protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
super.bindGroupView(view, context, cursor, isExpanded);
if(view==null){
System.out.println("View is null!!");
}
System.out.println("Dumping form Groupview");
DatabaseUtils.dumpCurrentRow(cursor);
}
#Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
int dateInMillis = groupCursor.getInt(groupCursor.getColumnIndex(Statics.DBSHOWS_DATE));
Cursor childCursor = DataHandler.getShowsForDate(dateInMillis);
childCursor.moveToFirst();
return childCursor;
}
}
The two Override Methods bindChildView(...) and bindGroupView(...) were made for testing. As expected, the following output was printed:
Dumping form Groupview
0 {
_id=1
Id=117451
Date=15.04.2016
Time=20:15
Movie_Id=2181
Hall=0
Cards_Sold=0
}

I have a love-hate relationship with our hobby/job: You have something working, at some point, something that seems totally independent changes, and then later your something is not working again. This is what happened here, and there was no way you could have guessed it:
With my Device updating to Marshmallow it could still read the ArrayList I used before but couldn't read the database anymore... Why it could still dump the cursor...? I don't know. But as soon as I figured out that you must request permissions on the go, and implemented that, it works... More or less anyway.

Related

Limit number of items in SimpleCursorAdapter when using custom content provider

I'm trying to get used to using custom content providers. I've successfully managed to write a very simple application that on the press of a button adds a String to an sqlite database using a custom content provider. These database entries are then displayed in a ListView in the same activity.
I am trying to limit the number of items in the ListView to 5, but due to my lack in experience, I have no idea how to proceed.
This is what I'm using to fill the ListView
private void fillData() {
String[] from = new String[]{commentsTable.COLUMN_COMMENT, commentsTable.COLUMN_ID};
int[] to = new int[]{android.R.id.text1, android.R.id.text2};
getLoaderManager().initLoader(0, null, this);
adapter = new SimpleCursorAdapter(this, android.R.layout.two_line_list_item, null, from, to, 0);
setListAdapter(adapter);
}
I followed this tutorial http://www.vogella.com/tutorials/AndroidSQLite/article.html#tutorial-sqlite-custom-contentprovider-and-loader to write an app similar to the app in the tutorial.
I have tried using a Cursor instead of null but I'm getting a java.lang.NullPointerException error because of the method .getWritableDatabase().
After some research, I have managed to solve this and thought I would post an answer for anyone who stumbles across this question.
In my customContentProvider class I added the variables:
public static final String QUERY_PARAMETER_LIMIT = "limit";
public static final String QUERY_PARAMETER_OFFSET = "offset";
and then edited the query method to include:
public Cursor query(Uri uri, ...) {
String limit = uri.getQueryParameter(QUERY_PARAMETER_LIMIT);
String offset = uri.getQueryParameter(QUERY_PARAMETER_OFFSET);
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// ...
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder, limitString);
//...
return c;
}
Then when getting a cursor simply use the Uri
Uri CONTENT_URI = customContentProvider.CONTENT_URI.buildUpon()
.appendQueryParameter(customContentProvider.QUERY_PARAMETER_LIMIT,
String.valueOf(limit))
.appendQueryParameter(customContentProvider.QUERY_PARAMETER_OFFSET,
String.valueOf(offset))
.build();
Reference:
https://stackoverflow.com/a/24055457/6735035
CursorAdapter has method getCount(). You could implement it in your class like this.
public int getCount() {
int superCount = super.getCount();
return Math.min(superCount, 5);
}
So you need to inherit SimpleCursorAdapter and redefine method getCursor().
Crate this class
public class CustomCursorAdapter extends SimpleCursorAdapter {
public CustomCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
#Override
public int getCount() {
int superCount = super.getCount();
return Math.min(superCount, 5);
}
}
And in your code change SimpleCursorAdapter to CustomCursorAdapter
private void fillData() {
String[] from = new String[]{commentsTable.COLUMN_COMMENT, commentsTable.COLUMN_ID};
int[] to = new int[]{android.R.id.text1, android.R.id.text2};
getLoaderManager().initLoader(0, null, this);
adapter = new CustomCursorAdapter(this, android.R.layout.two_line_list_item, null, from, to, 0);
setListAdapter(adapter);
}

How to set background color through SimpleCursorAdapter

Here is my code:
private void fillData() {
Cursor notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor);
String[] from = new String[]{NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_COLOR};
int[] to = new int[]{R.id.text1, R.id.text2};
SimpleCursorAdapter notes = new SimpleCursorAdapter(
this, R.layout.note_row, notesCursor, from, to);
setListAdapter(notes);
}
Which produces the following ListView: http://i.stack.imgur.com/7W1xa.jpg
What I want is to take "R.id.text2" value (which is a hex color) and set it as text color of itself, for each different row of my ListView.
The result should look like this: http://i.stack.imgur.com/wrXt8.jpg
Is that possible? Thanks.
Yes, it's possible. Create your own cursor adapter MyCursorAdapter which extend SimpleCursorAdapter, then override newView or bindView method.
public class MyCursorAdapter extends SimpleCursorAdapter {
public MyCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
}
public MyCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
TextView textView = (TextView) view.findViewById(R.id.text2);
String color = cursor.getString(cursor.getColumnIndex(NotesDbAdapter.KEY_COLOR));
textView.setBackgroundColor(Color.parseColor(color));
}
}
There's no need to create a new class. See this code.
#Override
public boolean setViewValue(View view, Cursor c, int columnIndex) {
if(columnIndex == c.getColumnIndexOrThrow(NotesDbAdapter.KEY_COLOR)) {
TextView tv = (TextView)view;
tv.setColor(Color.RED);
}
}

how to split from [] value in simplecursoradapter in android

I have displaying value in list using simplecursoradapter. Nothing problem it. but how to split from [] value in simplecursoradapter in android
Means. I have in colummn this value -> John-44-2013
This value display in list. but i want to display John only.
String[] from = new String[] { column[0], column[1] };
int[] to = new int[] { R.id.colID, R.id.colDate };
TestCursorAdapter sca = new TestCursorAdapter (this,R.layout.gridrowsaveddetail, c,from, to);
public class TestCursorAdapter extends SimpleCursorAdapter {
String [] from;
int [] to;
public TestCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.from=from;
this.to=to;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView title_of_list= (TextView) view.findViewById(R.id.colDate);
String temp=cursor.getString(cursor.getColumnIndex(from[1]));
String[] parse = temp.split("-");
title_of_list.setText(parse[0].trim());
super.bindView(view, context, cursor);
}
}
But not getting this. Why something wrong with this code. thank you advance.
Remove the call to super.BindView
This call will try to set the text itself, and is thereby overruling your actions.
Or, place the call at the start of the method.

Android: adding an extra String to TextView which populates its content from Database

I have a listview which populates its content from SQLite Database.
Here's my code:
ListView listView = (ListView) findViewById(R.id.lstText);
listView.setOnItemClickListener(this);
listView.setAdapter(new MySimpleCursorAdapter(this, R.layout.listitems,
managedQuery(Uri.withAppendedPath(Provider.CONTENT_URI,
Database.Project.NAME), new String[] { BaseColumns._ID,
Database.Project.C_PROJECTTITLE,
Database.Project.C_SMALLIMAGE, Database.Project.C_PROJECTDESCRIPTION, Database.Project.C_ORGANIZATIONTITLE}, null, null, null),
new String[] { Database.Project.C_PROJECTTITLE,
Database.Project.C_SMALLIMAGE, Database.Project.C_PROJECTDESCRIPTION, Database.Project.C_ORGANIZATIONTITLE}, new int[] {
R.id.txt_title, R.id.image, R.id.txt_list_desc, R.id.txt_org}));
I want to put an extra String to some TextViews above when its displayed on the list. For example, I want to add a String with the word "from" on R.id.txt_org, before the populated String from the database which is Database.Project.C_ORGANIZATIONTITLE
Let's say the populated String is: New Organisation,
with an extra String "from" what will be displayed is: from New Organisation
Can anybody help me with that? Thank you very much.
EDITED:
FYI, this is my SimpleCursorAdapter method:
class MySimpleCursorAdapter extends SimpleCursorAdapter {
public MySimpleCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
loader = new ImageLoader(context);
this.context = context;
}
Context context=null;
ImageLoader loader = null;
public void setViewImage(ImageView v, String value) {
v.setTag(value);
loader.DisplayImage(value, context, v);
}
}
Since you're already using a custom adapter, override the adapter's bindView() and newView() methods, rather than getView(). That way you will not have to manually deal with recycling the row's view.
Within these method you can get the data from the resulting Cursor and manipulate it before binding it to your row's view.
GetView Vs. BindView in a custom CursorAdapter?
How to override CursorAdapter bindView
//Edit: some more code below. Note that this is just a rough outline and by no means complete or tested.
class MySimpleCursorAdapter extends SimpleCursorAdapter {
private ImageLoader mLoader = null;
private LayoutInflater mInflater = null;
private int mBusinessNameIndex = -1;
private int mSmallImageIndex = -1;
public MySimpleCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
mLoader = new ImageLoader(context);
mInflater = getLayoutInflater();
mBusinessNameIndex = c.getColumnIndexOrThrow(Database.Project.NAME);
mSmallImageIndex = c.getColumnIndexOrThrow(Database.Project.C_SMALLIMAGE);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mInflater.inflate(R.layout.row, null);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Get your views from 'view'
TextView someTextView = (TextView) view.findViewById(R.id.xxx);
ImageView someImageView = (ImageView) view.findViewById(R.id.yyy);
// Set the data
someTextView.setText("from " + cursor.getString(mBusinessNameIndex));
mLoader.DisplayImage(cursor.getString(mSmallImageIndex ), context, someImageView);
}
}

Android ListView (not ListActivity) connecting to SQLite DB using CustomCursorAdapter

I am trying to create Custom Cursor adapter and attach it to my listview.
Though I am not yet there to create textboxes and set values inside my adapter,
my code currently throws a runtime exception when I try to call super(ctx, c);
What could be wrong? Searched all over the web & couldn't get it. Thanks in advance!
Custom Cursor adapter:
public class CustomCursorAdaptor extends CursorAdapter {
private Context context;
private int layout;
public CustomCursorAdaptor (Context ctx, int layout, Cursor c, String[] from, int[] to) {
super(ctx, c);
this.context = ctx;
this.layout = layout;
}
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return(new View(context));
}
#Override
public void bindView(View v, Context context, Cursor c) {
}
}
and my Activity:
public class DynamicScrollView extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context ctx=getBaseContext();
RelativeLayout newLayout=new RelativeLayout(ctx);
ListView lv=new ListView(ctx);
SQLiteDatabase db;
db = ctx.openOrCreateDatabase("TShow.db", SQLiteDatabase.OPEN_READONLY, null);
db.setVersion(1);
db.setLocale(Locale.getDefault());
db.setLockingEnabled(true);
Cursor cur = db.query("control", new String[] {"id"}, "parent_id=2", null, null, null, null);
CustomCursorAdaptor adapter = new CustomCursorAdaptor(ctx, lv.getId(), cur, new String[] {"id"}, new int[] {2});
lv.setAdapter(adapter);
newLayout.addView(lv);
setContentView(newLayout);
}
}
I really don't know much about the base context, which you are passing to your CursorAdaptor here, but I understand that usually you should rather be using your Activity as the context. Activity is a subclass of Context, in case you did not know.
So, in stead of:
new CustomCursorAdaptor(ctx, lv.getId(), cur, new String[] {"id"}, new int[] {2});
... you could try:
new CustomCursorAdaptor(this, lv.getId(), cur, new String[] {"id"}, new int[] {2});
Cursor adapter expects to have a column _id which it uses as index. I added another column as _id in the select and it worked! Updated code:
Cursor cur = db.query("control", new String[] {"id as _id", "id"}, "parent_id=2", null, null, null, null);
I traced it back from the exception description which said: column '_id' does not exist
Thank you for the golden tip about the _id column which is needed for the ListView to work.
#dmg: you must not name your _id column with the (native)SQL 'AS' statement. Just add the '_id' column without changing it.

Categories

Resources