I am new with android programing and I have a problem with list view
In my app I have to read data from database (name,ID,year) and then add them to listview after that user must select one of
the items and in a new activity again I read data from db and list some of the other Items based on user's selection
Ol at this time In my first activity I read data and add them to listview..To select I must define a listener..right?
I define it like this code
enter code here #Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_read_book);
String SDcardPath = Environment.getExternalStorageDirectory().getPath();
String DbPath = SDcardPath + "/Tosca/" + "persian_poem.db";
ListView list = (ListView) findViewById(R.id.list_poet_name);
try {
db = SQLiteDatabase.openDatabase(DbPath,null,SQLiteDatabase.CREATE_IF_NECESSARY);
getData();
db.close();
}
catch (SQLiteException e) {
Toast.makeText(this, e.getMessage(), 1).show();
}
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v, int position,
long id) {
// TODO Auto-generated method stub
ListView list = (ListView) findViewById(R.id.list_poet_name);
Log.i(TAG, "Listview get Item Pos");
Peot_ID.putString ("Peot_ID", (String) list.getItemAtPosition(position));
Intent Book_list_intent = new Intent (Read.this,Book_list.class);
Book_list_intent.putExtras(Peot_ID);
startActivity(Book_list_intent);
}
});
}
private void getData() {
try {
//txtMsg.append("\n");
// obtain a list of from DB
String TABLE_NAME = "classicpoems__poet_contents";
String COLUMN_ID = "poet_id";
String _ID = "_id";
String COLUMN_NAME = "poet_name";
String COLUMN_CENTURY = "century_start";
String [] columns ={_ID,COLUMN_ID,COLUMN_NAME,COLUMN_CENTURY};
Cursor c = db.query(TABLE_NAME,columns,null, null, null, null, COLUMN_ID);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, c,
new String[] {COLUMN_NAME,COLUMN_CENTURY}, new int[] {android.R.id.text1,android.R.id.text2}, 0);
ListView list = (ListView) findViewById(R.id.list_poet_name);
list.setAdapter(adapter);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), 1).show();
}
}
But here I have a problem..I want to send data of peot_id (Its deffrent from _id column in db) to next activity..Bt I mentioned that
with this code I can get whole row of selected item and I just want part of it(peot_id ) can you help me how to get just Peot_ID from selected
list item?
and I have another question..
As you see in my code I must refer to one spasial listview several times..each time I defined it by this code
enter code hereListView list = (ListView) findViewById(R.id.list_poet_name);
How can I define this listviwe one time and use it in several places in my code?sth like a public variable or sth like that
Thanks for your help.
As you see in my code I must refer to one spasial listview several
times..each time I defined it by this code
No. Just create one global ListView variable list and simply you can access to it from everywhere in your Activity. There is no need to declaring and initialising ListView again in OnItemClick() method.
I want to send data of peot_id (Its deffrent from _id column in db) to
next activity..Bt I mentioned that with this code I can get whole row
of selected item and I just want part of it(peot_id ) can you help me
how to get just Peot_ID from selected list item?
You are using Android's defined basic layout
android.R.layout.simple_list_item_2
I suggest you to create own XML file for row and then simply get whole View from ListView and from View you can get only ID.
Example:
listrow.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
android:background="#drawable/addresses_list_selector"
>
<TextView
android:id="#+id/id_column"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="#+id/name_column"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/id_column"
/>
<TextView
android:id="#+id/century_column"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/name_column"
/>
</RelativeLayout>
Then an usage with CursorAdapter:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.listrow, c,
new String[] {COLUMN_ID, COLUMN_NAME, COLUMN_CENTURY},
new int[] {R.id.id_column, R.id.name_column, R.id.century_column}, 0);
And then for getting ID from row:
public void onItemClick(AdapterView<?> parent, View v, int position,
long id) {
TextView id = (TextView) v.findViewById(R.id.id_column);
if (id != null) {
String idString = id.getText().toString();
}
}
Note:
If you still want to use android's predefined layout, you need to pass into String[] from ID_COLUMN and then access to ID from row via row.findViewById(<id>);
String[] from = {ID_COLUMN, NAME_COLUMN};
int[] to = {android.R.id.text1, android.R.id.text2};
TextView id = v.findViewById(android.R.id.android.R.id.text1);
String idString = id.getText().toString();
You do query like this to get a Particular column record alone :
Cursor mCursor = mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
KEY_NAME, KEY_DESIGNATION}, KEY_ROWID + "=" + yourPrimaryKey, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
I personally prefer to use onListItemclick() method like that
//do not forget to override - very important
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
//TODO what you what you have here the vars position - position of the selected item in list
// and also the id so you can easy trace what selection done the user
// you can play with this
}
Related
In my application I have a spinner that displays a number of spending periods (weekly, bi-weekly, monthly, etc) and I filled it using a SimpleCursorAdapter because those periods are kept in the database. Here is how I implemented it:
Cursor spendingPeriodCursor = dataSource.getSpendingPeriods();
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, spendingPeriodCursor, fromColumns, toColumns);
mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpendingSpinner.setAdapter(mAdapter);
The spinner populates, and at the end of the activity I try to get the selected item like this:
// Get spending period description:
String spendingDesc = mSpendingSpinner.getSelectedItem().toString();
But it doesn't return the actual string value. It looks like a get a string representation of part of the cursor:
android.database.sqlite.SQLiteCursor#410dfae8
What do I have to do to get the actual text of the selected item?
Cursor cursor = (Cursor) mSpendingSpinner.getSelectedItem();
String text = cursor.getString(cursor.getColumnIndex("my_column_name"));
1) Well, with will be enough with:
String spendingDesc = mSpendingSpinner.getSelectedItem().toString();
2) but you can try too:
mSpendingSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View arg1,
int pos, long arg3) {
String spendingDesc= parent.getSelectedItem().toString();
}
}
3) or
Cursor cursor = (Cursor) mSpendingSpinner.getSelectedItem();
String text = cursor.getString(cursor.getColumnIndex("COLUN_NAME"));
I'm populating a spinner with a number of records from my SQlite database using the following code:
DBHelper db = new DBHelper(getBaseContext());
Cursor cursor_clients = db.select("clients", "_id, name", "ORDER BY name"); // table, fields, filter/order
String[] columns = new String[] { "name" };
int[] to = new int[] { android.R.id.text1 };
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, cursor_clients, columns, to, 0);
mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner spnClients = (Spinner) findViewById(R.id.spnClients);
spnClients.setAdapter(mAdapter);
It works great, and I can use
spnAcademias.getSelectedItemId();
To get the _id of the selected record. My problem is: How to select an item on this spinner by the _id?
I have the _id of the row I want, I want it to show this row selected, and not the first row coming from the query.
Doing more research I ended up with the solution here: setSelection on Spinner based on rowId
I thought maybe there was a native solution without a loop, but there is not.
Solution:
public void setSpinnerItemById(Spinner spinner, int _id)
{
int spinnerCount = spinner.getCount();
for (int i = 0; i < spinnerCount; i++)
{
Cursor value = (Cursor) spinner.getItemAtPosition(i);
long id = value.getLong(value.getColumnIndex("_id"));
if (id == _id)
{
spinner.setSelection(i);
break;
}
}
}
If you're able to just as easily get the text value of the row you are looking for, then try the solution here, and more specifically the top comment on it: Set selected item of spinner programmatically
Use the following: spinnerObject.setSelection(INDEX_OF_CATEGORY2).
...
... I also found a way of getting the index without needing to loop through the adapter. I used the following mySpinner.setSelection(arrayAdapter.getPosition("Category 2"));
I'm trying to display a list of contacts that are currently stored in a SQLiteDatabase.
Previously I've retrieved ContactsContract.Contacts.PHOTO_THUMBNAIL_URI and stored it in a form of byte[] in the BLOB column of my database rows.
Now when I'm trying to extract the thumbnails back, by decoding them to Bitmaps in MyBinderView class, the pictures don't appear, instead I see empty spaces(the default image, ic_launcher, is showed correctly). My ListView row layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="1dp">
<ImageView
android:id="#+id/thumbnail"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="50dp"
android:layout_marginRight="1dp"
android:src="#drawable/ic_launcher"/>
<TextView
android:id="#+id/email"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_width="0dp"
android:layout_weight="5"
android:layout_height="wrap_content"/>
</LinearLayout>
ListFragment class:
//DataBaseHelper.PHOTO contains a BLOB fetched from sqlite database
//DataBaseHelper.NAME is a String (no problem here)
String[] from = { DataBaseHelper.PHOTO, DataBaseHelper.NAME };
int[] to = new int[] { R.id.thumbnail, R.id.email };
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
setEmptyText("No E-mail buddies found");
// We have a menu item to show in action bar.
// setHasOptionsMenu(true);
contacts = new DataBaseHelper(getActivity());
contacts.open();
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(getActivity(), R.layout.contacts,
null, from, to);
mAdapter.setViewBinder(new MyViewBinder());
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
ViewBinder class for the photo to be inserted correctly:
public class MyViewBinder implements ViewBinder{
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
// TODO Auto-generated method stub
int viewId = view.getId();
Log.i("ViewBinder: view", Integer.toString(viewId));
Log.i("ViewBinder: name",cursor.getString(2));
Log.i("ViewBinder: email",cursor.getString(3));
Log.i("ViewBinder: photo",cursor.getBlob(4)==null?"NO Photo":"Has photo");
switch(viewId){
case R.id.thumbnail:
ImageView picture = (ImageView) view;
byte[] blob = cursor.getBlob(columnIndex);
if(blob!=null){
picture.setImageBitmap(
BitmapFactory.decodeByteArray(blob, 0, blob.length)
);
}
else
picture.setImageResource(R.drawable.ic_launcher);
return true;
}
return false;
}
}
Any help would be appreciated.
ContactsContract.Contacts.PHOTO_THUMBNAIL_URI
Provides a path to the thumbnail that can be retrieved by.
So after understanding that you build a URI using this path by calling parse function.
next you query your new uri with the help of this embedded class -
private static class PhotoQuery {
public static final String[] PROJECTION = {
Photo.PHOTO
};
public static final int PHOTO = 0;
}
using the code bellow you'll extract the needed byte[] that solved the issue.
the point of getting byte[] is to be able to store it in your DB and manipulate it later on when needed.
private byte[] getImage(String uriString){
if(uriString==null)
return null;
Uri myuri = Uri.parse(uriString);
Cursor photoCursor = getContentResolver().query(myuri, PhotoQuery.PROJECTION, null, null, null);
if (photoCursor != null) {
try {
if (photoCursor.moveToFirst()) {
final byte[] photoBytes = photoCursor.getBlob(PhotoQuery.PHOTO);
if (photoBytes != null) {
return photoBytes;
}
}
} finally {
photoCursor.close();
}
}
return null;
}
Hope it'll help someone
cheers :)
In the following code I am able to retrieve the _id value of each record and display it along with the text in a ListView but when I select an item from the list the returned value is 0 to N dependent on how the results are laid out in the list.
How can I get the _id value, I guess as a named value pair so that when 0 or 1… is selected it outputs the _id field and not 0 or 1… for my OnItemClickListener
This is my method, it’s messy, once I get it working I’ll try to refine it!
private void GetCoordinates(double currentLatitude, double currentLongitude) {
List<String> ar = new ArrayList<String>();
dbBookHelper = new DatabaseHelper(this);
ourCursor = dbBookHelper.getCoordinates();
int counta = 0;
ourCursor.moveToFirst();
do {
id = ourCursor.getInt(ourCursor.getColumnIndex("_id"));
BeachName = ourCursor.getString(ourCursor.getColumnIndex("BeachName"));
beachLatitude = ourCursor.getDouble(ourCursor.getColumnIndex("latitude"));
beachLongitude = ourCursor.getDouble(ourCursor.getColumnIndex("longitude"));
distence = ConvertDistance(beachLatitude, beachLongitude);
if (distence <= 5) {
ar.add(id + " " + BeachName + " - " + distence + "Kms");
counta++;
}
} while (ourCursor.moveToNext());
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.row2, R.id.beachListText, ar);
setListAdapter(adapter);
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(onListClick);
Toast.makeText(getBaseContext(), "There are " + String.valueOf(counta) + " beaches within a 5km radius!", Toast.LENGTH_LONG).show();
}
And this is my OnItemClickListener method
private AdapterView.OnItemClickListener onListClick = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Toast.makeText(getBaseContext(), String.valueOf(id) + " selected", Toast.LENGTH_LONG).show();
}
};
Any help would be greatly appreciated,
Cheers,
Mike.
Edit: Thanks guys, I was hoping for a slicker way too!
But I now have a second array holding just the id values with,
ar1.add(String.valueOf(id));
So the positions are the same, but how do I get them into the OnItemClickListener? I guess somewhere in here???
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.row2, R.id.beachListText, ar);
setListAdapter(adapter);
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(onListClick);
The basic problem is the ArrayAdapter does not know anything about the Cursor or rowId. I think you have 2 choices. The first is to manage the mapping of array position to rowId yourself. For example, create a second array to map the ArrayList position to the rowId, and do a simple lookup in the listener.
If that is not appropriate for some reason then you could create a custom adapter with knowledge of the Cursor, by extending CursorAdapter. It involves over-riding 2 methods newView() and bindView() to allocate and populate the views (with your custom string) that will be displayed in each row. It also provides filtering hooks that would allow you to implement the < 5KM filter you need.
I haven't gone through this particular case myself, but did recently have to extend an ArrayAdapter to implement a SectionIndexer for a very long list. While it was a valuable exercise, I think in your case a custom adapter is possibly overkill. A second array look-up may be simpler and more appropriate.
1) Make your new array a class member so it is accessible in the listener
ArrayList<Long> mIdArr = null;
2) Create this in a similar way to your String array
mIdArr = new ArrayList<Long>();
3) Store the rowId at the same point you add to your String array
ar.add(id + " " + BeachName + " - " + distence + "Kms");
mIdArr.add(new Long(id));
4) Retrieve the Id in your listener like this
private AdapterView.OnItemClickListener onListClick = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Long rowId = mIdArr.get(position);
Toast.makeText(getBaseContext(), String.valueOf(rowId) + " selected", Toast.LENGTH_LONG).show();
}
};
I have a Spinner which is to show a list of data fetched from database. The data is returned to a cursor from query, and the cursor gets passed to spinner's SimpleCursorAdapter. It is working fine as such, but I want to insert another item on top of this data. For example, the spinner is already showing a list of user created templates saved in DB, but I want to insert "New Template" and "Empty Template" on top of the list of templates, and it needs to be inserted into Cursor/SimpleCursorAdapter somehow.
I have considered using an arraylist and populating the arraylist from cursor, but cursor is better solution for me since it contains other related rows of data too. I searched internet for other solutions and found some answers asking to use CursorWrapper for this purpose, but I could not find a concrete example how to use CursorWrapper to accomplish what I want. How can I insert some rows in cursor or can someone please give a easy to follow CursorWrapper example!! Thanks in advance.
You can use a combination of MergeCursor and MatrixCursor with your DB cursor like this:
MatrixCursor extras = new MatrixCursor(new String[] { "_id", "title" });
extras.addRow(new String[] { "-1", "New Template" });
extras.addRow(new String[] { "-2", "Empty Template" });
Cursor[] cursors = { extras, cursor };
Cursor extendedCursor = new MergeCursor(cursors);
This is the method I tried.
MatrixCursor m = new MatrixCursor(c.getColumnNames());
Cursor c = DBHelper.rawQuery("Select values from your_table");
MatrixCursor m = new MatrixCursor(c.getColumnNames());
//Use MatrixCursor#addRow here to add before the original cursor
while (c.moveToNext()) {
//Use MatrixCursor#addRow here to add before the original row
DBHelper.insertRow(c, m);
//Use MatrixCursor#addRow here to add after the original row
}
//Use MatrixCursor#addRow here to add after the original cursor
m.addRow(new String[]{col1Val, col2Val, col3Val,..., //to match the number of columns needed});
DBHelper.insertRow()
public final static void insertRow(Cursor from, MatrixCursor to) {
final String columns[] = from.getColumnNames(), values[] = new String[columns.length];
final int size = columns.length;
for (int i = 0; i < size; i++) {
values[i] = getStringFromColumn(from, columns[i]);
}
to.addRow(values);
}
With this method, you can add any amount of rows anywhere in your cursor. Even though it is not making use of CursorWrapper, it can be used with CursorAdapters or SimpleCursorAdapters.
I tried the solution provided by #naktinis, but the result wasn't what I expected. What I myself wanted to achieve as an adapter in which new elements can be added at the top (index 0). However, with the solution given, new elements were indeed added at the top but only to the END of the MatrixCursor. In other words, when I added rows dynamically to the "extras" MatrixCursor, I got something like this:
"extras" row 1
"extras" row 2
"extras" row 3
"cursor" row 1
"cursor" row 2
"cursor" row 3.
However, what I really wanted to achieve was something like this:
"extras" row 3
"extras" row 2
"extras" row 1
"cursor" row 1
"cursor" row 2
"cursor" row 3.
In other words, most recent elements enter at the top (index 0).
I was able to achieve this manually by doing the follow. Note that I did not include any logic to handle dynamically removing elements from the adapter.
private class CollectionAdapter extends ArrayAdapter<String> {
/**
* This is the position which getItem uses to decide whether to fetch data from the
* DB cursor or directly from the Adapter's underlying array. Specifically, any item
* at a position lower than this offset has been added to the top of the adapter
* dynamically.
*/
private int mCursorOffset;
/**
* This is a SQLite cursor returned by a call to db.query(...).
*/
private Cursor mCursor;
/**
* This stores the initial result returned by cursor.getCount().
*/
private int mCachedCursorCount;
public Adapter(Context context, Cursor cursor) {
super(context, R.layout.collection_item);
mCursor = cursor;
mCursorOffset = 0;
mCachedCursorCount = -1;
}
public void add(String item) {
insert(item, 0);
mCursorOffset = mCursorOffset + 1;
notifyDataSetChanged();
}
#Override
public String getItem(int position) {
// return the item directly from underlying array if it was added dynamically.
if (position < mCursorOffset) {
return super.getItem(position);
}
// try to load a row from the cursor.
if (!mCursor.moveToPosition(position - mCursorOffset)) {
Log.d(TAG, "Failed to move cursor to position " + (position - mCursorOffset));
return null; // this shouldn't happen.
}
return mCursor.getString(INDEX_COLLECTION_DATA);
}
#Override
public int getCount() {
if (mCachedCursorCount == -1) {
mCachedCursorCount = mCursor.getCount();
}
return mCursorOffset + mCachedCursorCount;
}
}