I got a SQLite database and I would like to display data in a listView, I try it with a SimpleCursorAdapter:
contactAdapter = new SimpleCursorAdapter(this, R.layout.contact_row, cursor,
new String[] { MyDb.ACCOUNT_NAME },
new int[] { R.id.contactNameTv });
On this very line I get an
IllegalArgumentException: column '_id' does not exists.
Well, thanks JVM I just don't see what the heck should I do with that, because I don't even use _id column and this statement also wrong because I exported the database and opened with sqlite database opener and I can see the column _id in the database so it does exist.
Can somebody tell me when this error should appear and what is it trying to tell me ?
E D I T:
njzk2 pointed me right, I wasn't queried the "_id" column in my cursor getting func. Thanks.
App Crashes On Startup Due To java.lang.IllegalArgumentException: column '_id' does not exist
see the above sample which has same issue like this may be it will help you
Solution
You should add "_id" field when you create your table.
//example
"CREATE TABLE TABLE_NAME (_id INTEGER PRIMARY KEY AUTOINCREMENT,field1 TEXT, field2 TEXT, etc TEXT)";
The Cursor must include a column named "_id" or this class will not work.
Additionally, using {#link android.database.MergeCursor} with this class will not work if the merged Cursors have overlapping values in their "_id"
columns.
Warning!!
SimpleCursorAdapter this constructor was deprecated in API level 11. This option is discouraged, as it results in Cursor queries being performed on the application's UI thread and thus can cause poor responsiveness or even Application Not Responding errors. As an alternative, use LoaderManager with a CursorLoader.
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
An alternative is to use CursorAdapter and CursorLoader.
CursorAdapter is very useful when you work with databases for example if you want to show a list of data in ListView, GridView or RecyclerView directly from a database.
CursorLoader runs an asynchronous query in the background!
http://developer.android.com/reference/android/content/CursorLoader.html
I hope it helps you!!
cheers.
Related
I have _id set up in the database but when debugging it says the _id does not exist at this line:
SimpleCursorAdapter sqldb_adapter = new SimpleCursorAdapter(this, Resource.Layout.Recordslayout, sqldb_cursor, from, to);
I am using the tutorial from this blog.
One thing I do not have it set up in my mainactivity but a different one. I have set the public class to the correct activity.
This occurs when you don't have the _id column present in the projection(String[] from in your case). Adapter needs this column. Crosscheck that _id column is present and add some code if you want further help.
I've got several problems and I'm starting to wonder if my path is correct...
I would like to make a list of the most often used appliactions based on time scheduled measurments of processor usage. I know how to get usage statistics and processes names, I know how to connect it with apps names and icons. What I don't know is what to do next.
My idea was to create two tables: PROCESSES AND PROCESS_STATS, store all the information in the database and provide ContentProvider linked with SimpleCursorAdapter. In my opinion it's the cleaniest solution when working with SQLiteDB on Android. Don't bother counting effects into some "real" statistics, it's not the case here.
Problems:
I can't create the table with blob in it. Code in listing 1 does not work. When i try to read from table (using the code from Listing 2) I get java.lang.IllegalArgumentException: column 'app_icon' does not exist. There are no errors in LogCat while creating the db.
Storing icons (bitmaps) in the db is not a very good design pattern. However, I like the simplicity of my solution: ContentProvider, SimpleCursorAdapter and Fragments do all the background work for me. If I'd like to store icons on SD i would have much more work, especially with the final list of apps. What are the other ways to do this painlessly?
Listing 1:
CREATE TABLE processes
(_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
app_name TEXT,
app_icon BLOB);
CREATE TABLE process_stats
(_id INTEGER PRIMARY KEY AUTOINCREMENT,
process_id INTEGER NOT NULL,
FOREIGN KEY(process_id) REFERENCES processes(_id),
value INTEGER NOT NULL,
measurment_date INTEGER NOT NULL);
Listing 2:
...
import android.support.v4.widget.SimpleCursorAdapter;
...
public class ProcessesStatsActivity extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Cursor cursor = this.managedQuery(StatsProvider.PROCESSES_CONTENT_URI, null, null, null, null);
String[] columns = new String[] { StatsCollectorDatabase._PROCESS_APP_ICON, StatsCollectorDatabase._PROCESS_APP_NAME, StatsCollectorDatabase._PROCESS_STAT_VALUE };
int[] views = new int[] { android.R.id.icon, android.R.id.text1, android.R.id.text2 };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this.getApplicationContext(), R.layout.processes_stats_list_item, cursor, columns, views, 0);
this.setListAdapter(adapter);
}
}
Perhaps you first created your table without the app_icon field and then edited your CREATE TABLE statement adding the app_icon field. In this case it is still the old table that you will be reading from and hence it has no app_icon field.
Simplest then would be uninstall your app and reinstall it again.
Or you can increase your DB version, in this case SQLitehelper.onUpgrade() will be called and you may delete or restructure all the tables in there.
As to saving images saving them on SD and keeping their filepaths in DB is good. Keeping images in DB is not so good because there's a limit on total image size I think.
For future visitors:
I ended up with solution like this:
I don't save application info in the database. I have only one table, process_stats, in which I store measurment results. When it comes to view the results, I loop manually through the coursor and count everything I wanted. Next, I load details like app icon and app name and view the list.
I can paste some sample code here. Comment this answer, if interested.
I am getting this error
IllegalArgumentException: column '_id' does not exist
When using a SimpleCursorAdapter to retrieve from my database, and the table does indeed have this _id column. Noticing this a common problem, I have tried to work around it given some of the solutions online but none of them work. This is my cursor query:
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, R.layout.quoterow, myCursor, new String[]{"_id", "quote"}, new int[]{R.id.quote});
although I should mention the original did not include the _id column, I added this recently to try and solve the problem. Has anyone got any ideas that might help solve the problem?
Your database doesn't have to have a column called '_id' but the SimpleCursorAdaptor does need to have one returned. You can do this with an alias.
An example is that I have a table with columns...
uid,name,number
To query this for a SimpleCursorAdapter, I do this with a database rawQuery...
SELECT uid as _id,name,number FROM MY_TABLE
This works fine and supplies the necessary '_id' column to SimpleCursorAdapter.
EDIT: As far as I understand it the _id field is used as a unique key to make sure the data the cursor handles can be handled correctly by adapters and adapterviews etc.
Look at the data model in the docs for Content Providers.
Using a unique key in 'databases' of whatever kind is pretty much universal practice, and as far as I can tell, the use of the column name '_id' (or '_ID') is simply a way of standardizing and simplifying things across databases, content providers, cursors, adapters etc etc
In short, in order for these various components to work correctly, they need a data column with unique values but they must also 'know' what the name of that column is. They wouldn't 'know', so to speak, that my column name 'uid' is the one they need as opposed to my 'name' and 'number' columns.
You either don't have a column "_id" in your table or you are not including it in your query. That is what is causing the exception. You need to fix the following as well:
Your last argument for the CursorAdapter constructor is missing the to column reference for _id.
The int[] argument is an array of view ids to populate with values from the cursor. The String[] argument is an array of column names from a row the cursor points to.
You have to have an equal number of values in the from array as you do the to array. Because the data from the Cursor is being grabbed FROM the Cursor and placed TO the views. If there are not an equal number of values in each array, the adapter throws an exception because it doesn't have the right amount of information to map the data to the views.
Also, according to the JavaDoc for SimpleCursorAdapter, that constructor is deprecated because it causes queries to be executed in the UI thread. Which is bad. Use this one instead:
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html#SimpleCursorAdapter%28android.content.Context,%20int,%20android.database.Cursor,%20java.lang.String[],%20int[],%20int%29
A simple fix would be to add ",0" to the end of the argument list.
If you are trying to use an existing sqlite database in your Android application then you need to do some prep work to get it to work properly. This blog post describes the process in detail.
http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/
Is the field "_id" necessary in Android SQLite?
_id is useful when you are using the enhanced Adapters which make use of a Cursor (e.g. ResourceCursorAdapter). It's used by these adapters to provide an ID which can be used to refer to the specific row in the table which relates the the item in whatever the adapter is being used for (e.g. a row in a ListView).
It's not necessary if you're not going to be using classes which need an _id column in a cursor, and you can also use "as _id" to make another column appear as though it's called _id in your cursor.
Why not make use of _ROWID_?
SQLite provides this anyway for every row, so you can just alias it to _id in your select statement.
Technically no the field _id is not required, however if you are making use of the CursorAdapter class (which you probably are, especially if you are working with the Notepad example) then yes
"The Cursor must include a column named "_id" or this class will not
work"
as explained in the documentation here. Unfortunately the code examples do not make this very clear.
It's quite convenient in many cases to have an id field. I prefer mine to be auto-incrementing (as shown below). I'm always finding new uses for the id field :)
When it comes time to attach the data to an adapter, I like to use a table name alias to query the id field as _id. Example: SELECT id _id, msg from message order by id. That way the adapter sees a field called _id and everybody's happy.
Here's a sample of how I define my tables:
CREATE TABLE message (_id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, tripID TEXT, msg TEXT);
From the official docs...
The Cursor must include a column named "_id" or this class will not work. Additionally, using MergeCursor with this class will not work if the merged Cursors have overlapping values in their "_id" columns.
And the Cursor is:
This interface provides random read-write access to the result set returned by a database query.
In other words, you need _id for Android SQLite ( which usually uses Cursor )
If you define your _id column as an autoincrementing integer it is actually an alias for the ROWID column that SQLite provides by default (https://www.sqlite.org/lang_createtable.html#rowid).
Your create statement needs take the form...
CREATE TABLE t(_id INTEGER PRIMARY KEY ASC, y, z);
To prove this works...
UPDATE t SET _id=22 WHERE _id=11;
then
SELECT ROWID, _id FROM t;
and you'll find both _id and ROWID have the same value.
Note, that if you use DESC in the CREATE a new column is created and ROWID is not aliased.
Surely not.
Its a convenience field that some widgets like ListView uses to populate data. See this good article:
http://www.casarini.org/blog/2009/android-contentprovider-on-sqlite-tables-without-the-_id-column/
Of course if you are creating your own UI widget and your own adapter, you don't have to name your primary key as "_id". It can be any name you want. But you would be responsible for managing your collections of UI widgets and binding them to the right row in your database. "_id" is only useful for ListView as Brad has pointed out.
The _id field is indeed necessary in sqlite, it will help you to select a particular data from sqlite.
SELECT name from table_name where _id = ?
And if your are creating a recyclerview/ listview and you want a detailed activity for that list item you indeed need an id for this to fetch data of that item.
if you are creating a class for constants there is a BaseColumn interface in android,
which provide _ID field to that constant class.
//from android documentation..
public static class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
}
I need to display results from a SQL join in a ListView/ListActivity.
I've created a cursor:
Cursor cursor = db.rawQuery(LIST_JOIN_SQL, null);
and if I iterate through the cursor, the results are exactly what I expect. However when I try and use a SimpleCursorAdapter to display these results in a ListView I get a runtime exception because there is no column called ' id'.
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.item, cursor, FROM, TO);
Where FROM and TO are defined as:
private static String[] FROM = { "name", };
private static int[] TO = { R.id.name, };
Now I figure I'm probably using the wrong approach here, as it seems SimpleCursorAdapters aren't meant for displaying results of joins.
What approach would you recommend here? I'm restricted to using Android 1.6 APIs.
Try selecting one of your columns as _ID alias
select col1 as _id from table
To use CursorAdapter (or any of its subclasses) you're required to have the "_id" column; it's explicitly stated in the documentation. That's because CursorAdapter uses this column heavily.
What I recommend is whatever you think (based on your project) to be the easier of these two paths:
Create an _id field in one of the tables so that when you join, you end up with an _id field.
Implement your own ListAdapter (starting from BaseAdapter) that is essentially a CursorAdapter but doesn't require an _id field.
I suspect #1 would be easier to do if you control the database, but that you'd have to do #2 if you cannot change the databases' schema.