I have a Listview which pulls and displays data from a sqlite DB. Data in the first column of the DB is displayed in the ListView and when clicked, an Activity starts showing the rest of the column associated with the first column. When the data is edited the ListView needs to be updated to reflect this, but it doesn't show the updates unless the application is restarted.
I've tried calling, notifyDataSetChanged() and startActivityForResult() in my onResume() method but that didn't work. What method should I use to accomplish updating the ListView in my current code?
I understand a SimpleCursorAdapter may be used and I have tried to implement that code with no success. I'm a novice and need actual code to understand what needs to be done.
public class LoginList extends Activity implements OnClickListener, OnItemClickListener {
private ListView loginList;
private Button webLogin;
private ListAdapter loginListAdapter;
private ArrayList<LoginDetails> loginArrayList;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_listview);
loginList = (ListView)
findViewById(R.id.loginlist);
loginList.setOnItemClickListener(this);
webLogin = (Button)
findViewById(R.id.button3);
webLogin.setOnClickListener(this);
loginArrayList = new ArrayList<LoginDetails>();
loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, populateList());
loginList.setAdapter(loginListAdapter);
}
#Override
public void onClick (View v) {
Intent webLoginIntent = new Intent (this, LoginPlusActivity.class);
startActivity(webLoginIntent);
}
public List<String> populateList () {
List<String> webNameList = new ArrayList<String>();
dataStore openHelperClass = new dataStore (this);
SQLiteDatabase sqliteDatabase = openHelperClass.getReadableDatabase();
Cursor cursor = sqliteDatabase.query(dataStore.TABLE_NAME_INFOTABLE, null, null, null, null, null, dataStore.COLUMN_NAME_SITE, null);
startManagingCursor(cursor);
while (cursor.moveToNext()) {
String sName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_SITE));
String wUrl = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_ADDRESS));
String uName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_USERNAME));
String pWord = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_PASSWORD));
String lNotes = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_NOTES));
LoginDetails lpDetails = new LoginDetails();
lpDetails.setsName(sName);
lpDetails.setwUrl(wUrl);
lpDetails.setuName(uName);
lpDetails.setpWord(pWord);
lpDetails.setlNotes(lNotes);
loginArrayList.add(lpDetails);
webNameList.add(sName);
}
sqliteDatabase.close();
return webNameList;
}
#Override
protected void onResume() {
super.onResume();
loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, populateList());
loginList.setAdapter(loginListAdapter);
}
#Override
public void onItemClick(AdapterView<?> arg0 , View arg1, int arg2, long arg3) {
Toast.makeText(getApplicationContext(), "Selected ID :" + arg2, Toast.LENGTH_SHORT).show();
Intent updateDeleteLoginInfo = new Intent (this, UpdateDeleteLoginList.class);
LoginDetails clickedObject = loginArrayList.get(arg2);
Bundle loginBundle = new Bundle();
loginBundle.putString("clickedWebSite",clickedObject.getsName());
loginBundle.putString("clickedWebAddress",clickedObject.getwUrl());
loginBundle.putString("clickedUserName",clickedObject.getuName());
loginBundle.putString("clickedPassWord",clickedObject.getpWord());
loginBundle.putString("clickedNotes",clickedObject.getlNotes());
updateDeleteLoginInfo.putExtras(loginBundle);
startActivityForResult(updateDeleteLoginInfo, 0);
}
}
This is exactly what a Loader is great for. I suggest you create a SimpleCursorAdapter to bind the DB to the UI (ListView in this case), a ContentProvider to interface with the DB, and a CursorLoader to monitor the DB for changes, and update the UI when necessary. The Loader will handle all DB changes and update your ListView by simply updating your adapter. It seems like a lot of work up front, but is incredibly powerful once configured, and will work through the entire Android lifecycle.
These tutorials should be helpful:
https://developer.android.com/training/load-data-background/index.html
http://www.vogella.com/articles/AndroidSQLite/article.html#background_loader
https://github.com/browep/AndroidCursorLoaderTutorial
Edit
private ArrayList<LoginDetails> loginArrayList = new ArrayList<LoginDetails>();;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_listview);
loginList = (ListView)
findViewById(R.id.loginlist);
loginList.setOnItemClickListener(this);
webLogin = (Button)
findViewById(R.id.button3);
webLogin.setOnClickListener(this);
loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,loginArrayList );
loginList.setAdapter(loginListAdapter);
populateList();
}
#Override
public void onClick (View v) {
Intent webLoginIntent = new Intent (this, LoginPlusActivity.class);
startActivity(webLoginIntent);
}
public void populateList () {
loginListAdapter.clear();
loginArrayList.clear();
dataStore openHelperClass = new dataStore (this);
SQLiteDatabase sqliteDatabase = openHelperClass.getReadableDatabase();
Cursor cursor = sqliteDatabase.query(dataStore.TABLE_NAME_INFOTABLE, null, null, null, null, null, dataStore.COLUMN_NAME_SITE, null);
startManagingCursor(cursor);
while (cursor.moveToNext()) {
String sName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_SITE));
String wUrl = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_ADDRESS));
String uName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_USERNAME));
String pWord = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_PASSWORD));
String lNotes = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_NOTES));
LoginDetails lpDetails = new LoginDetails();
lpDetails.setsName(sName);
lpDetails.setwUrl(wUrl);
lpDetails.setuName(uName);
lpDetails.setpWord(pWord);
lpDetails.setlNotes(lNotes);
loginArrayList.add(lpDetails);
webNameList.add(sName);
}
loginListAdapter.notifyDatasetChanged();
sqliteDatabase.close();
}
You are losing reference to your listview that why your list isn't updating...
Do this modification in your code.
1. Initialize your ArrayList when it is declared(globally).
ArrayList loginArrayList = new ArrayList<LoginDetails>();
Directly set assign list to Adapter (onCreate)
loginListAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1, loginArrayList);
call populateList() in onCreate().
In your populateList() instead of Adding data to the new list add to existing list associated with your Adapter i.e loginArrayList
if your list is completely new call adapter.clear() and loginArrayList.clear() in the populateList() before adding data to the loginArrayList.
After Adding the data to the loginArrayList call adapter.notifyDataSetChanged()
This should Work...
My recomendation.
Do not do a loop to load your list. If it is a simple list with all
strings. Try to use a SimpleCursorAdapter and will make your app
faster and shorter code.
Once you update the database, then what you do is query the DB to get the Cursor, and to the Adapter use .swapCursor(newCursor). That will update your list while maintaining the scroll position.
If you're manually creating the backing data of the adapter (in this case you're using an ArrayAdapter - which is completely acceptable in a lot of cases) then when the database changes you need to requery the database, recreate your dataset, change the backing dataset of your adapter, and tell the list that the dataset has changed.
A way to accomplish this may be to broadcast an intent that lets your activity know to perform the steps mentioned above (by catching that intent with a BroadcastReceiver).
Here's my sample code for editing the each row as well as the database of the listview I hope it will helps you
First create I create an Adapter name "ListAdapterItem.java"
import java.util.ArrayList;
import java.util.HashMap;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class ListAdapterItem extends BaseAdapter {
private ArrayList<HashMap<String, Object>> list;
private Context context;
private RelativeLayout ll;
// used to keep selected position in ListView
private int selectedPos = -1; // init value for not-selected
private TextView label,label_id;
String name,id;
public ListAdapterItem (Context context,ArrayList<HashMap<String, Object>> list) {
this.list = list;
this.context = context;
}
public void setSelectedPosition(int pos) {
selectedPos = pos;
// inform the view of this change
notifyDataSetChanged();
}
public int getSelectedPosition() {
return selectedPos;
}
public View getView(int position, View convertView, ViewGroup parent) {
ll = (RelativeLayout) LayoutInflater.from(this.context).inflate(R.layout.data_list_item, null);
// get text view
label = (TextView) ll.findViewById(R.id.txtview_country_name);
label_id=(TextView) ll.findViewById(R.id.txtview_id);
id=list.get(position).get("Id").toString();
name = list.get(position).get("Name").toString();
label.setText(name);
label_id.setText(id);
return ll;
}
public int getCount() {
return this.list.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
}
And here's my data_list_item
<?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="fill_parent"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="#+id/txtview_id"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_margin="8dp"
android:layout_marginRight="2dp"
android:textColor="#android:color/black"
android:textSize="22dp"
android:visibility="invisible"/>
<TextView
android:id="#+id/txtview_country_name"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_margin="8dp"
android:layout_marginRight="2dp"
android:textColor="#android:color/black"
android:textSize="22dp" />
</RelativeLayout>
And the main Class "Main.java"
public class Main extends Activity implements OnClickListener {
String name;
SQLiteDatabase db;
Cursor cursor;
private ProgressDialog progressDialog;
public ListAdapterItem list_adapter;
private ArrayList<HashMap<String, Object>> lst_data;
private HashMap<String, Object> hm;
private ListView listview;
private String list_id;
private int counter_id,selectedPosition;
private View selectedView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
lst_data = new ArrayList<HashMap<String, Object>>();
listview = (ListView) findViewById(R.id.list);
new FetchDB().execute();
}
private class FetchDB extends AsyncTask<String, Void,ArrayList<HashMap<String, Object>>> {
protected void onPreExecute() {
progressDialog = ProgressDialog.show(Main.this,"Fetching Data", "Loading,Please wait...", true);
}
protected ArrayList<HashMap<String, Object>> doInBackground(String... lstStrings)throws IllegalArgumentException {
try {
db = openOrCreateDatabase("MyDB", MODE_PRIVATE, null);
cursor = db.rawQuery("SELECT * FROM person WHERE Id <> ''",null);
if (cursor != null && cursor.getCount() > 0) {
if (cursor.moveToFirst()) {
do {
hm = new HashMap<String, Object>();
hm.put("Id",cursor.getInt(cursor.getColumnIndex("Id")));
hm.put("Name", cursor.getString(cursor.getColumnIndex("Name")));
lst_data.add(hm);
} while (cursor.moveToNext());
}// end of cursor.moveToFirst()
cursor.close();
}
} catch (Exception e) {
e.getMessage();
}
db.close();// database close
return lst_data;
}// end of doInbackgournd
#Override
protected void onPostExecute(ArrayList<HashMap<String, Object>> result) {
progressDialog.dismiss();
list_adapter = new ListAdapterItem(Main.this,result);
listview.setAdapter(list_adapter);
listview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
list_adapter.setSelectedPosition(arg2);
selectedPosition = arg2;
selectedView = arg1;
list_id=((TextView) selectedView.findViewById(R.id.txtview_id)).getText().toString();
}
});
}
}// end of FetchDBTask
private class SaveTask extends AsyncTask<String, Void,ArrayList<HashMap<String, Object>>> {
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(Main.this,"Saving Data", "Loading,Please wait...", true);
}
protected ArrayList<HashMap<String, Object>> doInBackground(String... arg0)throws IllegalArgumentException {
counter_id++;
name = editext_name.getText().toString();
hm = new HashMap<String, Object>();
hm.put("Id",counter_id);
hm.put("Name",name);
lst_data.add(hm);
saveDB();
return lst_data;
}// end of doInbackgournd
protected void onPostExecute(ArrayList<HashMap<String, Object>> result) {
progressDialog.dismiss();
list_adapter = new ListAdapterItem(Main.this,result);
listview.setAdapter(list_adapter);
listview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
list_adapter.setSelectedPosition(arg2);
selectedPosition = arg2;
selectedView = arg1;
list_id=((TextView) selectedView.findViewById(R.id.txtview_id)).getText().toString();
}
});
}
}// end of saveTask
public void saveDB(){
String sql;
db = openOrCreateDatabase("MyDB", MODE_PRIVATE, null);
// create table if not e exist
db.execSQL("CREATE TABLE IF NOT EXISTS person(Name VARCHAR ,Id INT(3));");
sql = "SELECT * FROM person WHERE Id="+list_id; //selected or click row in list item
Cursor cursor = db.rawQuery(sql, null);
if (cursor.moveToFirst()) {
String sqlUpdate = "UPDATE person SET Name=? WHERE Id="+db_id;
db.execSQL(sqlUpdate, new Object[] {db_name});
cursor.close();
db.close();// database close
} else {// empty insert
String sqlInsert = "INSERT INTO person VALUES (?,"+null+")";
db.execSQL(sqlInsert, new Object[] {db_name,db_address,db_phone,db_email,db_license,db_comments,db_company,db_policy,db_phone_insurance,vehc_year,vehc_make,vehc_model,vehc_license,vehc_vinnum,vehc_color,db_position });
cursor.close();
db.close();// database close
}
}
//Edit by row
private class EditData extends AsyncTask<String, Void,ArrayList<HashMap<String, Object>>> {
protected void onPreExecute() {
progressDialog = ProgressDialog.show(Main.this,"Saving Data", "Loading Please wait...", true);
}
protected ArrayList<HashMap<String, Object>> doInBackground(String... id)throws IllegalArgumentException {
name = editext_name.getText().toString();
hm = new HashMap<String, Object>();
hm.put("Id",counter_id);
hm.put("Name",name);
lst_data.set(selectedPosition, hm); //specific row update
list_id=Integer.parseInt(edit_counter);
saveDB();
return lst_data;
}// end of doInbackgournd
protected void onPostExecute(ArrayList<HashMap<String, Object>> result) {
progressDialog.dismiss();
list_adapter = new ListAdapterItem(Main.this,result);
listview.setAdapter(list_adapter);
}
}
}
And the main_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#android:color/transparent"
android:cacheColorHint="#00000000"
android:dividerHeight="2dp"
android:paddingTop="8dp"
android:transcriptMode="normal" />
</LinearLayout>
Specify your id every listrow in the listview hope that this answer your question
I think that in your populate() method before the while block you should call loginListAdapter.notifyDataSetChanged() and loginListAdapter.clear();
That would clear the adapter and notice to it of the new list of data.
The block will look like this:
loginListAdapter.notifyDataSetChanged();
loginListAdapter.clear();
while (cursor.moveToNext()) {
String sName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_SITE));
String wUrl = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_ADDRESS));
String uName = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_USERNAME));
String pWord = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_PASSWORD));
String lNotes = cursor.getString(cursor.getColumnIndex(dataStore.COLUMN_NAME_NOTES));
LoginDetails lpDetails = new LoginDetails();
lpDetails.setsName(sName);
lpDetails.setwUrl(wUrl);
lpDetails.setuName(uName);
lpDetails.setpWord(pWord);
lpDetails.setlNotes(lNotes);
loginArrayList.add(lpDetails);
webNameList.add(sName);
}
I Just edited because the order you call the notify and clear wasn't correct. The clear must occur after the notify, is just what i got from my experience, unless the adapter wouldn't redraw the list.
Try this code
in public area add variable : List<String> arrayList = new ArrayList<String>();
and in onCreate() add this :
arrayList = populateList();
//then add variable in adapter like this
loginListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, arrayList );
in onResume() this code:
#Override
protected void onResume() {
super.onResume();
loginArrayList.clear();
arrayList.clear();
arrayList = populateList();
loginListAdapter.notifyDataSetChanged()
}
Let us know if you solved it.
Related
I display a listview with database rows. When a row is clicked, a dialog pops up with the (editable) items of that row.
public class ViewDataActivity extends ListActivity {
private ListView listView;
HashMap<Integer, String> results = new HashMap<Integer, String>();;
ArrayList<String> dataValues = new ArrayList<String>();
ArrayList<Integer> keyValues = new ArrayList<Integer>();
ArrayAdapter<String> arrayAdapter;
Integer itemKey;
String itemValue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
results = (HashMap<Integer, String>) getIntent().getSerializableExtra(MainActivity.EXTRA_MESSAGE);
for(Map.Entry<Integer, String> entry: results.entrySet()) {
keyValues.add(entry.getKey());
dataValues.add(entry.getValue());
}
// Display items
listView = getListView();
View v = getLayoutInflater().inflate(R.layout.list_view_header, null);
listView.addHeaderView(v);
arrayAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
dataValues );
listView.setAdapter(arrayAdapter);
// Make Items clickable
listView.setChoiceMode(CHOICE_MODE_SINGLE);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.d("List position clicked", String.valueOf(listView.getCheckedItemPosition()));
itemKey = keyValues.get(listView.getCheckedItemPosition()-1);
itemValue = dataValues.get(listView.getCheckedItemPosition()-1);
showInputBox(itemKey, itemValue);
}
});
}
// Show dialog with values
public void showInputBox(final Integer itemKey, String listItemValue){
final Dialog dialog=new Dialog(ViewDataActivity.this);
dialog.setTitle("Edit Item");
dialog.setContentView(R.layout.list_item_edit_popup);
TextView txtMessage=(TextView)dialog.findViewById(R.id.txtmessage);
txtMessage.setText("Update");
txtMessage.setTextColor(Color.parseColor("#ff2222"));
String[] listItemValues = listItemValue.split(",");
final String liCategory = listItemValues[2];
final String liDescription = listItemValues[3];
final String liAmount = listItemValues[4];
EditText editText1=(EditText)dialog.findViewById(R.id.txtinput1);
EditText editText2=(EditText)dialog.findViewById(R.id.txtinput2);
EditText editText3=(EditText)dialog.findViewById(R.id.txtinput3);
editText1.setText(liCategory);
editText2.setText(liDescription);
editText3.setText(liAmount);
Button bt=(Button)dialog.findViewById(R.id.btdone);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Write new Values
dbHelper.updateExpense(itemKey, liCategory, liDescription, liAmount);
// Refresh ListView
arrayAdapter.notifyDataSetChanged();
dialog.dismiss();
}
});
dialog.show();
}
}
But when i update the values in the dialog and click the button, the dialog closes but the row isn't updated in the database. The update being executed is this:
public boolean updateExpense(Integer id, String category, String description, String amount) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COLUMN_CATEGORY, category);
contentValues.put(COLUMN_DESCRIPTION, description);
contentValues.put(COLUMN_AMOUNT, amount);
// Returns 1 but no update
Log.d("DBUpdate", String.valueOf(db.update(TABLE_NAME, contentValues, COLUMN_ID + " = ? ", new String[] { Integer.toString(id) } )));
return true;
}
What am i missing?
Hard to tell as clearly the code you're showing us is incomplete, but if you're using database.beginTransaction();, make sure you use database.setTransactionSuccessful(); after your update call. Also don't forget database.endTransaction(); in your finally statement.
I want to sort my listview so that the newest data added is on the top. I've tried to sort by using the order by clause and for loop as seen from other Q & A . But I just can't get the result. Please help. Thank you.
View Class
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
_productlist.clear();
db = new DatabaseHelper(getApplicationContext());
db.getWritableDatabase();
ArrayList<ProductModel> product_list = db.getProudcts();
for (int i = 0; i < product_list.size(); i++) {
String tidno = product_list.get(i).getIdno();
System.out.println("tidno>>>>>" + tidno);
String tname = product_list.get(i).getProductname();
String tprice = product_list.get(i).getProductprice();
String tadd = product_list.get(i).getProductadd();
ProductModel _ProductModel = new ProductModel();
_ProductModel.setIdno(tidno);
_ProductModel.setProductname(tname);
_ProductModel.setProductprice(tprice);
_ProductModel.setProductadd(tadd);
_productlist.add(_ProductModel);
}
listview.setAdapter(new ListAdapter(this));
db.close();
}
My getAllData method
public ArrayList<ProductModel> getProudcts() {
cartList.clear();
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from producttable", null);
if (cursor.getCount() != 0) {
if (cursor.moveToFirst()) {
do {
ProductModel item = new ProductModel();
item.idno = cursor.getString(cursor
.getColumnIndex("productidno"));
item.productname = cursor.getString(cursor
.getColumnIndex("productname"));
item.productprice = cursor.getString(cursor
.getColumnIndex("productprice"));
item.productadd = cursor.getString(cursor
.getColumnIndex("productadd"));
cartList.add(item);
} while (cursor.moveToNext());
}
}
cursor.close();
db.close();
return cartList;
}
Collections.sort(list);
Collections.reverse(list);
Or you could implement your own Comparator to sort on and eliminate the reverse step:
Collections.sort(list, new Comparator<Long>() {
public int compare(Long o1, Long o2) {
return o2.compareTo(o1);
}
})
;
Or even more simply use Collections.reverseOrder() since you're only reversing:
Collections.sort(list, Collections.reverseOrder());
Add yout list items at index 0
_productlist.add(0,_ProductModel);
It worked for me. Give it a try.
and after adding object ot list call notifyDataSetChanged()
listAdapter.notifyDataSetChanged();
Here is an example:
public class MainActivity extends Activity {
private ListView lv;
private Button bt;
int i = 0;
private ArrayList<Integer> al;
private ArrayAdapter<Integer> aa;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.listView1);
bt = (Button) findViewById(R.id.button1);
al = new ArrayList<Integer>();
aa = new ArrayAdapter<Integer>(getApplicationContext(),
android.R.layout.simple_list_item_1, al);
lv.setAdapter(aa);
bt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
al.add(0, i++);
aa.notifyDataSetChanged();
}
});
}
I'd go with what #dipali suggested but then call notifyDataSetChanged() on the listviews adapter.
You can do it in three different ways.
You can add time stamp column in your database table. Update this column whan you add or edit a product and sort your product according to the time stamp.
You can use ORDER BY DESC in your query to get ordered result.
Set value from Adapter in reverse order
for (int i =productlist.size(); i >0 ; i--)
{
}
I'm new in Android programming and I'm wondering witch is the most appropriate way to fill a ListView from DataBase.
Here the method I'm using in database to get my items
// Getting All stats
public List<StatParcours> getAllSats() {
List<StatParcours> statList = new ArrayList<StatParcours>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_STATS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
StatParcours stat = new StatParcours();
stat.setID(Integer.parseInt(cursor.getString(0)));
stat.setDate(cursor.getString(1));
stat.setDuration(cursor.getString(2));
stat.setDistance(Double.parseDouble(cursor.getString(3)));
stat.setSpeed(Double.parseDouble(cursor.getString(4)));
stat.setCondition(cursor.getString(5));
// Adding contact to list
statList.add(stat);
} while (cursor.moveToNext());
}
// return contact list
return statList;
}
and in the main activity, I'm using this. I know there is something wrong with the populateMyStatsList method, but I still don't know how to fix it.
public class History extends Activity {
public DatabaseHandler db;
private List<StatParcours> MyStats = new ArrayList<StatParcours>();
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("oncreate", "ok");
super.onCreate(savedInstanceState);
setContentView(R.layout.history);
populateMyStatsList ();
populateListView();
registerClickCallback();
}
private void populateMyStatsList (){
MyStats = db.getAllSats();
}
private void populateListView() {
ArrayAdapter<StatParcours> adapter = new MyListAdapter();
ListView list = (ListView) findViewById(R.id.HistListView);
list.setAdapter(adapter);
Log.i("Populate", "ok");
}
private void registerClickCallback() {
ListView list = (ListView) findViewById(R.id.HistListView);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View viewClicked,
int position, long id) {
StatParcours clickedCar = MyStats.get(position);
String message = "You clicked position " + position
+ " Which is car make " + clickedCar.getDate();
Toast.makeText(History.this, message, Toast.LENGTH_LONG).show();
}
});
}
private class MyListAdapter extends ArrayAdapter<StatParcours> {
public MyListAdapter() {
super(History.this, R.layout.item_view, MyStats);
Log.i("MyListAdapter", "ok");
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = convertView;
if (itemView == null) {
Log.i("Make sure", "ok");
itemView = getLayoutInflater().inflate(R.layout.item_view, parent, false);
}
Log.i("getview", "ok");
StatParcours currentStat = MyStats.get(position);
TextView makeText = (TextView) itemView.findViewById(R.id.item_txtMake);
makeText.setText(currentStat.getDate());
TextView yearText = (TextView) itemView.findViewById(R.id.item_txtYear);
yearText.setText("" + currentStat.getDistance());
TextView condionText = (TextView) itemView.findViewById(R.id.item_txtCondition);
condionText.setText(currentStat.getCondition());
return itemView;
}
}
}
You need to use a SimpleCursor Adapter. I can't reach the developer site for the documentation but here is an example with your code above.
EDIT: Here is the link to the android developer website.
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
SECOND EDIT: This would go in the populateListView()
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_STATS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// Set your layout to int[]
int[] to = new int[]{R.id.item_txtMake,R.id.item_txtYear,R.id.item_txtCondition};
//set your columns to string[]; fill in your actual column names
string[] from = new string[]{"make","year","condition"};
//set up adapter
SimpleCursorAdapter adapter = new SimpleCursorAdapter(getActivity(),R.layout.item_view, cursor, from,to,null);
//set adapter to listview
ListView list = (ListView) findViewById(R.id.HistListView);
list.setAdapter(adapter);
Since you only have TextView in your ListView you can just simply use SimpleCursorAdapter.
// Getting All stats
public Cursor getAllSats() {
List<StatParcours> statList = new ArrayList<StatParcours>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_STATS;
SQLiteDatabase db = this.getWritableDatabase();
return db.rawQuery(selectQuery, null);
}
And in your History class
public class History extends Activity {
public DatabaseHandler db;
private List<StatParcours> MyStats = new ArrayList<StatParcours>();
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("oncreate", "ok");
super.onCreate(savedInstanceState);
setContentView(R.layout.history);
Cursor c = getAllSats();
String[] fromColumns = {Your database column name for date,
Your database column name for distance,
Your database column name for condition};
int[] toViews = {R.id.item_txtMake,
R.id.item_txtYear,
R.id.item_txtCondition};
adapter = new SimpleCursorAdapter(this, R.layout.item_view,
c, fromColumns, toViews, 0);
ListView list = (ListView) findViewById(R.id.HistListView);
list.setAdapter(adapter);
registerClickCallback();
}
I have serious problems with my ListActivity. When I open it and start scrolling, the app freezes for some seconds and after that it can be scrolled smoothly. I don't get an "application not responding" error. I made a *.hprof heap dump and put it into MAT. Here you can see my leaks:
Seems like something is fishy. Maybe I'm not using the cursor in the right way.
Here you can take a look at my code:
public class ListViewActivity extends ListActivity implements OnClickListener {
// Resources
static String like;
// Cursor
private SimpleCursorAdapter adapter;
private Cursor cursor;
String[] showColumns;
int[] showViews;
// Database
private DBAccess dbAccess;
#Override
public void onCreate(Bundle savedInstanceState) {
// Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview);
ListViewActivity.like = "";
Intent intent = getIntent(); // gets the previously created intent
ListViewActivity.like = intent.getStringExtra("like");
new DatabaseTask().execute(null, null, null);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Cursor item = (Cursor) getListAdapter().getItem(position);
Intent intent = new Intent(ListViewActivity.this, ListClickActivity.class);
intent.putExtra("id", item.getString(0));
startActivity(intent);
}
private class DatabaseTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Log.v("doInBackground", "started!");
dbAccess = new DBAccess(ListViewActivity.this, 1, "FishingMatey.db");
dbAccess.initDownloadedDatabase();
cursor = dbAccess
.createBewirtschafterListViewCursor(ListViewActivity.like);
showColumns = new String[] { "gewName", "reviergrenzen" };
showViews = new int[] { R.id.datensatz_gewName,
R.id.datensatz_reviergrenzen };
Log.v("doInBackground", "finished!");
return null;
}
protected void onPostExecute(Void params) {
adapter = new SimpleCursorAdapter(ListViewActivity.this,
R.layout.datensatz, cursor, showColumns, showViews);
setListAdapter(adapter);
dbAccess.closeDatabase();
Log.v("onPostExecute", "finished!");
}
}
}
EDIT1:
The issue doesn't come from the database because I have the same leak with the following code:
public class ListViewActivity extends ListActivity {
// Activity
public static Activity forFinish;
// Resources
static String like;
// Cursor
private SimpleAdapter adapter;
String[] showColumns;
int[] showViews;
#Override
public void onCreate(Bundle savedInstanceState) {
// Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview);
forFinish = this;
ListViewActivity.like = "";
Intent intent = getIntent(); // gets the previously created intent
ListViewActivity.like = intent.getStringExtra("like");
// create the grid item mapping
showColumns = new String[] { "gewName", "reviergrenzen" };
showViews = new int[] { R.id.datensatz_gewName,
R.id.datensatz_reviergrenzen };
// prepare the list of all records
List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < 20; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("gewName", "See" + i);
map.put("reviergrenzen", "Revier" + i);
fillMaps.add(map);
}
// fill in the grid_item layout
SimpleAdapter adapter = new SimpleAdapter(this, fillMaps,
R.layout.datensatz, showColumns, showViews);
setListAdapter(adapter);
}
}
Would be awesome if someone can find the memory leak.
Greetings Mike!
If you are using images in your list items then move the image loading to a background task. You could have a look at smoothie, an asynchronous loading list that can be used with Android-BitmapCache for better performance.
I try to create a AutoCompleteTextView with custom list items, like showing a picture and a name in one list item. I know how to create it with 1 line of text in a list item but i'm a bit confused on who to do this with more views. I was thing about a ListAdapter and assigning the values to the right views. I'm pretty stuck here. I hope someone can give me a push in the right direction. Question is updated below.
Main activity:
public class AutocompleteCustomActivity extends Activity {
String[] firstView = {"Apple","Banana","Strawberry"};
String[] secondView = {"Green","Yellow","Red"};
AutoCompleteTextView autocomplete;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/*
// Simple 1 line list item
this.autocomplete = (AutoCompleteTextView) findViewById(R.id.autocomplete);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.list_item, firstView);
autocomplete.setAdapter(adapter);
*/
// 2 Lines of text in list item
this.autocomplete = (AutoCompleteTextView) findViewById(R.id.autocomplete);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.two_list_items, firstView);
autocomplete.setAdapter(adapter);
}
}
XML:
<?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="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
UPDATE:
After a lot of hardcore Googling and trial and erroring i came up with this code. I think it's pretty oké but the list items keep showing after selecting one. I know it's the settext that opens the new listitems.
I found this post: Disable Android AutoCompleteTextView after user selects item from drop down
But i don't know what he means :( Anyone knows how to fix this?
package com.sb.autocompletecustom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AutoCompleteTextView;
import android.widget.SimpleAdapter;
public class AutocompleteCustomActivity extends Activity {
AutoCompleteTextView autocomplete;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Data to fill autocomplete
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Map<String, String> curGroupMap = new HashMap<String, String>();
list.add(curGroupMap);
curGroupMap.put("name", "Banana");
curGroupMap.put("color", "Yellow");
curGroupMap = new HashMap<String, String>();
list.add(curGroupMap);
curGroupMap.put("name", "Strawberry");
curGroupMap.put("color", "Red");
curGroupMap = new HashMap<String, String>();
list.add(curGroupMap);
curGroupMap.put("name", "Strawberry");
curGroupMap.put("color", "Black");
// 2 Lines of text in list item
this.autocomplete = (AutoCompleteTextView) findViewById(R.id.autocomplete);
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.two_list_items, new String[] { "name", "color" }, new int[] { R.id.textView1, R.id.textView2 });
autocomplete.setAdapter(adapter);
autocomplete.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> p, View v, int pos, long id) {
Map<String, String> map = (Map<String, String>) p.getItemAtPosition(pos);
String itemName = map.get("name");
autocomplete.setText(itemName);
}
});
}
}
use a custom list adapter. you can inflate the layout and assign the values
public class AutoCompleteCursorAdapter extends CursorAdapter implements Filterable{
private TextView txtDrName, txtDrugName, txtDrugManufacturer;
private int rowResID;
private static Cursor c;
private String autoCompleteTextName;
Context context;
int layout;
public AutoCompleteCursorAdapter(Context context, int layout ) {
super(context, c);
// this.c = c;
this.context = context;
this.autoCompleteTextName = autoCompleteTextName;
this.layout = layout;
}
public long getItemId(int position) {
return position;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(layout, parent, false);
txtDrName = (TextView)v.findViewById(R.id.txtAutoName) ;
....
}
return v;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
txtDrName = (TextView) view.findViewById(R.id.txtAutoName) ;
}
#Override
public String convertToString(Cursor cursor) {
// this method dictates what is shown when the user clicks each entry in your autocomplete list
String name="";
name = cursor.getString(cursor.getColumnIndex("prefix"))+" "+cursor.getString(cursor.getColumnIndex("firstName"));
}
return name;
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
// this is how you query for suggestions
if (getFilterQueryProvider() != null)
{ return getFilterQueryProvider().runQuery(constraint); }
if(constraint!=null){
DataBaseHelper db = new DataBaseHelper(context);
db.openDataBase();
if(autoCompleteTextName.equals(AppConstants.AUTOCOMPLETEDOCTORNAME)){
c = db.getStaffStartingWith((String) constraint);
}
else if (autoCompleteTextName.equals(AppConstants.AUTOCOMPLETEDRUGNAME)){
c = db.getDrugsForStartingWith((String) constraint);
}
c.moveToFirst();
db.close();
}
return c;
}
`