Get ID of View in GridView
What I've tried
Hello Guys, I first created a database which I've filled with 3 Collumns, RowID, imageID, text. Afterwards I created a GridView which if filled over my database. Now I have created a onItemClickListner, in which I'd like to get the imageID over the position. After that happend I serach my DB-Table after this imageID, to get the text. This stuff I nneed to save in my other Table. The problem is I think, that I don't get the imageID, and like this serach for nothin in the DB, if you take a look at the Logcat you see that it's null, so it probably didn't get the imageID or I search in my DBAdapter not like I should.
Question
IMPORTRANT: I finally get the ID of the View thx to FuzzialLogic, but there is still a problem, I can't get Row over my Cursor. Please take a look at that!
WORKS:
What do I need to change in my Code, that I can get the ID of the Image the User clicked on. Afterwards I'd like to search my DB with that Image-ID, to get the Text which I stored with the Image. This stuff afterwards goes in my other Table.
Down here you see the Code and LogCat-Log. I also added my DatabaseAdapter if someone needs it. Thx for your help in Advance!
Code
SFilterConfigActivity.class:
package de.retowaelchli.filterit;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.Toast;
import android.*;
import de.retowaelchli.filterit.database.SmileyDBAdapter;
import de.retowaelchli.filterit.database.SFilterDBAdapter;
import de.retowaelchli.filterit.stats.ImageAdapter;
public class SFilterConfigActivity extends Activity {
//Variablen deklarieren
private String name;
private String keyword;
private String smiley;
private String text;
private String source;
private Integer[] info;
private SmileyDBAdapter SmileyHelper;
private SFilterDBAdapter mDbHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sfilter_config);
SmileyHelper = new SmileyDBAdapter(this);
mDbHelper = new SFilterDBAdapter(this);
getImages();
grid();
}
public void grid(){
//Hier wird die GridView definiert und anschliesend über den ImageAdapter gefüllt
final GridView gridview = (GridView) findViewById(R.id.SmileyGrind);
gridview.setAdapter(new ImageAdapter(this, info));
//Hier wird definiert was passiert wenn auf ein Bild in der GridView geklickt wird
gridview.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Toast.makeText(SFilterConfigActivity.this, "" + position, Toast.LENGTH_SHORT).show();
// gridview.setSelection(position);
// Funktioniert noch nich Custom GridView Layout dafür erstellen siehe Stackoverflow
if(position == gridview.getSelectedItemPosition()){
v.setBackgroundColor(0xFF00FF00);
}
else{
v.setBackgroundColor(0x0000000);
}
//Hier wird herrausgefunden welche ID das Bild hat und in den jeweiligen String gespeichert
source = (new Long(id)).toString();
SmileyHelper.open();
Cursor c = SmileyHelper.getSmiley(source);
startManagingCursor(c);
if (c.moveToFirst()) {
do {
text = c.getString(c.getColumnIndex(SmileyDBAdapter.SOURCE));
smiley = c.getString(c.getColumnIndex(SmileyDBAdapter.INFO));
} while (c.moveToNext());
SmileyHelper.close();
}
}
});
}
public Integer[] getImages(){
SmileyHelper.open();
Cursor c = SmileyHelper.getAllSmileys();
ArrayList<Integer> infoList = new ArrayList<Integer>();
c.getColumnIndex(SmileyDBAdapter.INFO);
int ColumnIndex = c.getColumnIndex(SmileyDBAdapter.INFO);
if(c!=null)
{
while(c.moveToNext()){
String infoItem = c.getString( ColumnIndex );
infoList.add(Integer.parseInt(infoItem));
}
}
info = infoList.toArray(new Integer[]{});
c.close();
SmileyHelper.close();
return info;
}
public void onClickSConfigSave(View v){
EditText edtTextName = (EditText)findViewById(R.id.SFConfigName);
EditText edtTextKeyword = (EditText)findViewById(R.id.SFConfigKeyword);
name = edtTextName.getText().toString();
keyword = edtTextKeyword.getText().toString();
mDbHelper.open();
mDbHelper.createSFilter(name, keyword, smiley, text);
mDbHelper.close();
final Intent i = new Intent(this, SmileyActivity.class);
startActivity(i);
}
}
ImageAdapter.class
package de.retowaelchli.filterit.stats;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
//import de.retowaelchli.filterit.SFilterConfigActivity;
public class ImageAdapter extends BaseAdapter {
// references to our images
private Integer[] mThumbIds;
private Context mContext;
public ImageAdapter(Context c, Integer[] imageIds) {
mContext = c;
mThumbIds = imageIds;
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return mThumbIds[position];
}
public long getItemId(int position) {
return position;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(final int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
imageView.setId(mThumbIds[position]);
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
}
Like this I added the pictures with some text to the DB:
private void angry(){
int drawableID = context.getResources().getIdentifier("angry", "drawable", getPackageName());
iv.setImageResource(drawableID);
//String info = String.valueOf(drawableID);
String info = String.valueOf(drawableID);
mDbHelper.open();
mDbHelper.createSmiley("You received a angry message", info);
mDbHelper.close();
}
Log-Cat
And here's the Log:
10-12 11:32:29.632: DEBUG/Database(25130): dbopen(): path = /data/data/de.retowaelchli.filterit/databases/filterit, flag = 6
10-12 11:32:29.632: DEBUG/Database(25130): dbopen(): path = /data/data/de.retowaelchli.filterit/databases/filterit, free size = 663
10-12 11:32:30.612: DEBUG/Database(25130): dbopen(): path = /data/data/de.retowaelchli.filterit/databases/filterit, flag = 6
10-12 11:32:30.612: DEBUG/Database(25130): dbopen(): path = /data/data/de.retowaelchli.filterit/databases/filterit, free size = 663
10-12 11:32:30.632: ERROR/Database(25130): Error inserting text=null smiley=null keyword=test name=test
10-12 11:32:30.632: ERROR/Database(25130): android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
10-12 11:32:30.632: ERROR/Database(25130): at android.database.sqlite.SQLiteStatement.native_execute(Native Method)
10-12 11:32:30.632: ERROR/Database(25130): at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:61)
10-12 11:32:30.632: ERROR/Database(25130): at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1671)
10-12 11:32:30.632: ERROR/Database(25130): at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1515)
10-12 11:32:30.632: ERROR/Database(25130): at de.retowaelchli.filterit.database.SFilterDBAdapter.createSFilter(SFilterDBAdapter.java:89)
10-12 11:32:30.632: ERROR/Database(25130): at de.retowaelchli.filterit.SFilterConfigActivity.onClickSConfigSave(SFilterConfigActivity.java:143)
10-12 11:32:30.632: ERROR/Database(25130): at java.lang.reflect.Method.invokeNative(Native Method)
10-12 11:32:30.632: ERROR/Database(25130): at java.lang.reflect.Method.invoke(Method.java:507)
10-12 11:32:30.632: ERROR/Database(25130): at android.view.View$1.onClick(View.java:2186)
10-12 11:32:30.632: ERROR/Database(25130): at android.view.View.performClick(View.java:2532)
10-12 11:32:30.632: ERROR/Database(25130): at android.view.View$PerformClick.run(View.java:9277)
10-12 11:32:30.632: ERROR/Database(25130): at android.os.Handler.handleCallback(Handler.java:587)
10-12 11:32:30.632: ERROR/Database(25130): at android.os.Handler.dispatchMessage(Handler.java:92)
10-12 11:32:30.632: ERROR/Database(25130): at android.os.Looper.loop(Looper.java:143)
10-12 11:32:30.632: ERROR/Database(25130): at android.app.ActivityThread.main(ActivityThread.java:4196)
10-12 11:32:30.632: ERROR/Database(25130): at java.lang.reflect.Method.invokeNative(Native Method)
10-12 11:32:30.632: ERROR/Database(25130): at java.lang.reflect.Method.invoke(Method.java:507)
10-12 11:32:30.632: ERROR/Database(25130): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
10-12 11:32:30.632: ERROR/Database(25130): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
10-12 11:32:30.632: ERROR/Database(25130): at dalvik.system.NativeStart.main(Native Method)
Here you find the Code of my SmileyDBAdapter.
SmileyDB
package de.retowaelchli.filterit.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SmileyDBAdapter {
public static final String ROW_ID = "_id";
public static final String SOURCE = "source";
public static final String INFO = "info";
private static final String DATABASE_TABLE = "smiley";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DBAdapter.DATABASE_NAME, null, DBAdapter.DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* @param ctx
* the Context within which to work
*/
public SmileyDBAdapter(Context ctx) {
this.mCtx = ctx;
}
public SmileyDBAdapter open() throws SQLException {
this.mDbHelper = new DatabaseHelper(this.mCtx);
this.mDb = this.mDbHelper.getWritableDatabase();
return this;
}
/**
* close return type: void
*/
public void close() {
this.mDbHelper.close();
}
public long createSmiley(String source, String info ){
ContentValues initialValues = new ContentValues();
initialValues.put(SOURCE, source);
initialValues.put(INFO, info);
return this.mDb.insert(DATABASE_TABLE, null, initialValues);
}
public boolean deleteSmiley(long rowId) {
return this.mDb.delete(DATABASE_TABLE, ROW_ID + "=" + rowId, null) > 0;
}
public Cursor getAllSmileys() {
return this.mDb.query(DATABASE_TABLE, new String[] { ROW_ID,
SOURCE, INFO }, null, null, null, null, null);
}
//Es wird nach der ID des smiley gesucht.
public Cursor getSmiley(String info) throws SQLException {
Cursor mCursor =
this.mDb.query(true, DATABASE_TABLE, new String[] { ROW_ID, SOURCE,
INFO }, INFO + "=" + info, null, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
public boolean updateSmiley(long rowId, String source, String info,
String cache){
ContentValues args = new ContentValues();
args.put(SOURCE, source);
args.put(INFO, info);
return this.mDb.update(DATABASE_TABLE, args, ROW_ID + "=" + rowId, null) >0;
}
}
DBAdapter
package de.retowaelchli.filterit.database;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBAdapter {
public static final String DATABASE_NAME = "filterit";
public static final int DATABASE_VERSION = 1;
public static final String CREATE_TABLE_ADFILTER = "create table adfilter (_id integer primary key autoincrement, "
+ ADFilterDBAdapter.NAME+" not null ,"
+ ADFilterDBAdapter.KEYWORD+" not null ,"
+ ADFilterDBAdapter.CACHE + " not null );";
private static final String CREATE_TABLE_SFILTER = "create table sfilter (_id integer primary key autoincrement, "
+SFilterDBAdapter.NAME+" not null ,"
+SFilterDBAdapter.KEYWORD+" not null ,"
+SFilterDBAdapter.SMILEY+ " not null ,"
+SFilterDBAdapter.TEXT+ " not null );";
private static final String CREATE_TABLE_ADMESSAGES = "create table admessages (_id integer primary key autoincrement, "
+MessagesDBAdapter.PHONENUMBER+" not null ,"
+MessagesDBAdapter.MESSAGE+ " not null );";
private static final String CREATE_TABLE_SMILEY = " create table smiley (_id integer primary key autoincrement, "
+SmileyDBAdapter.SOURCE+" not null ,"
+SmileyDBAdapter.INFO+ " not null );";
private final Context context;
private DatabaseHelper DBHelper;
private SQLiteDatabase db;
/**
* Constructor
* @param ctx
*/
public DBAdapter(Context ctx)
{
this.context = ctx;
}
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(CREATE_TABLE_ADFILTER);
db.execSQL(CREATE_TABLE_SFILTER);
db.execSQL(CREATE_TABLE_ADMESSAGES);
db.execSQL(CREATE_TABLE_SMILEY);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion)
{
// Adding any table mods to this guy here
}
}
/**
* open the db
* @return this
* @throws SQLException
* return type: DBAdapter
*/
public DBAdapter open() throws SQLException
{
this.DBHelper = new DatabaseHelper(this.context);
this.db = this.DBHelper.getWritableDatabase();
return this;
}
/**
* close the db
* return type: void
*/
public void close()
{
this.DBHelper.close();
}
}
Solution 1:
Safari,
After looking over your code and analyzing what could be causing the error, I've noticed a few things. The issue is that your code is trying to interchange the rowID and viewID, but that is not actually the desired behavior.
In OnItemClick()
, the id
argument refers to rowID
. You don't actually have a rowID
that is guaranteed (by the code) to be unique, so it is failing. While you could "force the issue" via getItemId()
, that function merely provides a pointer to an object (Integer). Ignore getItemId()
as this is only causing you pain. Instead, grab the view itself, and get the viewId
directly from it, like so:
EDIT source = v.getId().toString();
Reason: Since your TABLE doesn't declare a Type, it is most likely going in as a String. We know the ImageID is now returning, and we know the data is there... So that leaves type conversion, so far as I can tell.
parent
and view
often cause confusion, particularly with convoluted nested layouts like GridViews
and ListViews
. However, your GridView
is quite simple and v
should refer to the ImageView
that is stored there. If the ImageView
was stored in a LinearLayout
or other similar parent, there might be an issue, but such is not the case for you.
This will bypass your need to worry about the getItemId(int position)
, as again, this refers to rowId
and only works if you can guarantee to the Adapter
certain things, specifically a unique rowId
for each item.
Second, your viewId
is set to a pointer for an Integer
and not the value itself. An int
is a primitive, so assignment happens as expected. An Integer
is an Object
so assignment happens to the address of the object, not the object itself. I would suggest changing imageView.setId(mThumbIds[position]);
(in your getView()
) to:
imageView.setId(mThumbIds[position].intValue());
This will get the primitive int
value instead of a reference to an Integer
object in memory. Unless something else errant is happening in your code (and I don't see anything right offhand), this should resolve your issue. setId
is meant to fail quietly if an inappropriate id
is assigned to it, so it may not be working and simply not telling you.
Finally, I can't see what type of field the 'SOURCE' is in your code. It doesn't show the actual table creation. So, further guessing at your particular database is impossible. Hope this helps!
Regarding your Database The main thing that stands out about your Database is your CREATE TABLE statement for your Simleys Table. In SQLite, if you do not explicitly assign a Type, SQLite will determine the Type each time you make a query, and return the type according to what it believes is in the field. This means that numbers may be interpreted as String and vice versa. In general, it can be pretty reliable, however, it can lead to pitfalls.
One of the biggest issues in code is assuming the code is doing what you want it to. In fact, you can only guarantee this if you tell it exactly what to do.
Second, I noticed that when you get the images to build your Array
for your ImageAdapter
that you are doing a query on the INFO
field, not the SOURCE
. This is misleading in your code as you tell the onItemClick
that you are getting the SOURCE
. Consider changing this variable name.
Next, there is a dysfunction when querying the INFO
field via getSmiley(String info)
. It is expecting a String and not an Integer according to your arguments. Adding a String
to a ContentValues
object is different than adding an Integer. A String
gets added with '' surrounding it, separating '1' from 1. This means that all of your Integers
were INSERTED as String
and when you are querying you are not including the necessary ''. So a number of changes is advised.
-
First, adjust your CREATE TABLE Statement.
private static final String CREATE_TABLE_SMILEY = " create table smiley (_id integer primary key autoincrement, " +SmileyDBAdapter.SOURCE+" not null ," +SmileyDBAdapter.INFO+ " integer not null );";
Changing the statement in this way will ensure that you are getting an integer and not a string.
Next, change your
getImages()
in the following manner:String infoItem = c.getString( ColumnIndex );
toint infoItem = c.getInt( ColumnIndex );
Next, change your
createSmiley(String source, String info)
tocreateSmiley(String source, int info)
. This should adjust all of your inserts correctly. YourContentValues
object (namedinitialValues
) will know what to do.Next, change your
getSmiley(String info)
togetSmiley(int info)
. This should adjust your query correctly as well. If it does not, change... + "=" + info + ...
to... + "=" + info.toString() + ...
. This will force the issue for you.Next, make your
onItemClick()
match by changing this linesource = v.getId().toString();
back tosource = v.getId();
Finally, you will have to change any of your calls to
createSmiley()
to send the int value, not the value converted to a String.
This is a lot of changes (not really) to make. So, please back up your source files before you make these changes. Then its just a matter of uninstalling the package (including from the emulator, if it is emulated) and reinstalling it, so it doesn't keep the original data (with the Strings and not the Integers).
FuzzicalLogic
Solution 2:
In Your ImageAdapter code.You have overridden method getItemid ther you are returning 0 that is causing problem.try returning mThumbIds[position] i think this will do the trick for you.
cheers.