I hate a list created by simple cursor adapter:
Cursor c = myDbHelper.rawQ(select);
startManagingCursor(c);
// the desired columns to be bound
String[] columns = new String[] { "Books.BookTitle",
"Publishers.Publisher" };
// the XML defined views which the data will be bound to
int[] to = new int[] { R.id.ISBN_entry, R.id.Title_entry };
// Getting results into our listview
try {
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this,
R.layout.listlayout, c, columns, to);
this.setListAdapter(mAdapter);
} catch (Exception e) {
}
The layout involved with the list are two simple textviews.
What i want to do is create a listener
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
The part im failing at is retrieving the BookTitle part of the specific entry(row) in order to requery the database and present the data with AlertDialog.Builder.
When i try doing :
String selection = l.getItemAtPosition(position).toString();
i'm only getting android.database.sqlite SQLiteCursor#44f99e80 and im rather confused on how this should be done (I know why it's crashign just can;t get my mind around on how it should be done properly.
Full code atm:
...
Cursor c = myDbHelper.rawQ(select);
startManagingCursor(c);
// the desired columns to be bound
String[] columns = new String[] { "Books.BookTitle",
"Publishers.Publisher" };
// the XML defined views which the data will be bound to
int[] to = new int[] { R.id.ISBN_entry, R.id.Title_entry };
// Getting results into our listview
try {
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this,
R.layout.listlayout, c, columns, to);
this.setListAdapter(mAdapter);
} catch (Exception e) {
}
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
//super.onListItemClick(l, v, position, id);
String selection = l.getItemAtPosition(position).toString();
new AlertDialog.Builder(v.getContext())
.setTitle("Title")
.setMessage(selection)
.setPositiveButton(android.R.string.ok, null)
.show();
} }
Try something like this...
Cursor theCursor = ((SimpleCursorAdapter)((ListView)l).getAdapter()).getCursor();
String selection = theCursor.getString(theCursor.getColumnIndex("Books.BookTitle"));
Just get the data from the cursor:
l.getItemAtPosition(position).getString(0); // it might be 1
See here.
Related
So I have used Cursor in my application to retrieve all tracks from the storage. The problem is that it is returning only one track not all the tracks. The code is perfect and no errors. Even I have tried accessing the ArrayList in which I am retrieving and storing all the tracks. The ArrayList's size is 1 instead of many. I am attcahing the code below:
private void Encrypt() {
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if(cursor!= null && cursor.moveToFirst()){
int TrackTitle = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
int Artist = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
int Path = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
do{
String Tracktitle = cursor.getString(TrackTitle);
String Trackartist = cursor.getString(Artist);
String Trackpath = cursor.getString(Path);
arrayList = new ArrayList<CustomListView>();
arrayList.add(new CustomListView(R.drawable.none, Tracktitle, Trackartist, Trackpath));
CustomListViewAdapter customListViewAdapter = new CustomListViewAdapter(this, arrayList);
tracks.setAdapter(customListViewAdapter);
tracks.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
});
}while (cursor.moveToNext());
What the heck is wrong with code??
You are creating a new ArrayList in each loop, move this line out of your do-while loop:
arrayList = new ArrayList<CustomListView>();
do {
...
I'm implementing swipe to delete in RecyclerView but I've notice that is not working as espected.
When the app launch for first time, items are collected from the db and polulated, when I swipe works fine. After thar if I add an item to the list (also to the db) I'm recovering all items again from the db and recreating the adapter, but if I swipe one element, the size of the adapter in SwipeToDeleteCallback doesn't match with the database items, so I'm getting an IndexOutOfBounds error.
Can you help me? I don't know what's wrong...
public SwipeToDeleteCallback(RecyclerviewAdapter adapter) {
super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
mAdapter = adapter;
icon = ContextCompat.getDrawable(mAdapter.getContext(), R.drawable.ic_delete);
background = new ColorDrawable(Color.RED);
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
mAdapter.deleteItem(position);
}
public void deleteItem(int position) {
mRecentlyDeletedItem = vehiculos.get(position);
mRecentlyDeletedItemPosition = position;
vehiculos.remove(position);
notifyItemRemoved(position);
showUndoSnackbar();
}
RecyclerviewAdapter recyclerviewAdapter = new RecyclerviewAdapter(context);
recyclerviewAdapter.setVehiculosList(vehiculos);
ItemTouchHelper itemTouchHelper = new
ItemTouchHelper(new SwipeToDeleteCallback(recyclerviewAdapter));
itemTouchHelper.attachToRecyclerView(recycler);
recycler.setAdapter(recyclerviewAdapter);
This is the code I've follow:
https://medium.com/#zackcosborn/step-by-step-recyclerview-swipe-to-delete-and-undo-7bbae1fce27e
vehiculos = new ArrayList<Vehiculo>();
Database dbHelper = new Database(context);
SQLiteDatabase db = dbHelper.getReadableDatabase();
String[] columns = new String[]{
Database.SQL_FIELD_MATRICULA,
Database.SQL_FIELD_ETIQUETA,
Database.SQL_FIELD_DESCRIPCION
};
Cursor c = db.query(Database.SQL_TABLE_MATRICULAS, columns, null, null, null, null, null);
c.moveToFirst();
while (!c.isAfterLast()) {
Vehiculo vehiculo = new Vehiculo(c.getString(c.getColumnIndex(Database.SQL_FIELD_MATRICULA)), c.getString(c.getColumnIndex(Database.SQL_FIELD_ETIQUETA)), c.getString(c.getColumnIndex(Database.SQL_FIELD_DESCRIPCION)));
vehiculos.add(vehiculo);
c.moveToNext();
}
c.close();
db.close();
I want to make a to-do list app, and I wanted to delete the item in the list by tapping the checkbox.
I tried to make a "deleteTask"(as you see in the code) method in the database class. Also, you can see the "populateListView"
method, it provides data from the database into listview, I use it to refresh after each time a task got deleted from the database.
public void deleteTask(String task) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, COL2 , new String[]{task});
}
public void populateListView() {
try {
mDataBaseHelper = new DataBaseHelper(MainActivity.this);
data = mDataBaseHelper.getData();
mArrayList = new ArrayList<>();
if (data.getCount() != 0) {
while (data.moveToNext()) {
mArrayList.add(data.getString(1));
ListAdapter listAdapter = new ArrayAdapter(MainActivity.this, R.layout.list_items, R.id.checkBox, mArrayList);
list = (ListView) findViewById(R.id.myListId);
list.setAdapter(listAdapter);
}
mDataBaseHelper.close();
} else {
toastMessage("the Database is empty");
}
}catch(Exception e){
Log.e(TAG, "populateListView: error"+e.getStackTrace() );
}
}
when the application gets started, I tapped the item that I want to delete, but I see that the items start to be deleted by order from above!
one by one each time I tapped any checkbox.
You want :-
public void deleteTask(String task) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, COL2 + "=?" , new String[]{task});
}
If you weren't trapping the error by using the try/catch using db.delete(TABLE_NAME, COL2 , new String[]{task}); you would get an exception along the lines of :-
java.lang.IllegalArgumentException: Too many bind arguments. 1 arguments were provided but the statement needs 0 arguments.
However
Assuming that the issue with deleting rows sequentially rather than according to the checked item(s), is likely due to the handling of the checked items. However, as the code for this is not provided it would only be guess work to know where in the code you are going wrong.
One thing is that you do not want to be creating a new listadapter instance every time you populate the ListView.
As a hint to handling a ListView, but deleting an item when it is long-clicked based upon the COL2 value, perhaps consider the following which has been based upon your code (but deletes according to long clicking an item) :-
public void populateLisView() {
mDataBaseHelper = new DataBaseHelper(this); //<<<<<<<<<< NOTE 1
list = (ListView) this.findViewById(R.id.myListId); //<<<<<<<<<< NOTE 1
data = mDataBaseHelper.getData(); //<<<<<<<<<< get the data to be listed
if (listadapter == null) { //<<<<<<<<<< Only need to instantiate one adapter when it has not bee instantiated
listadapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,android.R.id.text1,data); // for convenience using a stock layout
list.setAdapter(listadapter);
//<<<<<<<<<<< add the onItemLongClick listener
list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
mDataBaseHelper.deleteTaskByCol2(data.get(position)); //<<<<<<<<<< gets the value of the item according to it's position in the list
populateLisView(); //<<<<<<<<<< as the item has been deleted then refresh the Listview
return true; // flag the event as having been handled.
}
});
//<<<<<<<<<<< If the Adapter has been instantiated then refresh the ListView's data
} else {
listadapter.clear(); // Clear the data from the adapter
listadapter.addAll(data); // add the new changed data to the adapter
listadapter.notifyDataSetChanged(); // tell the adapter that the data has changed
}
}
NOTE 1
you would typically instantiate these variables once.
Check the comments
You may wish to edit your question to include how you are handling the check events.
The Full Working Example
DatabaseHelper.java
Note this may differ from yours a little
public class DataBaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "mydb";
public static final int DBVERSION = 1;
public static final String TABLE_NAME = "mytable";
public static final String COL1 = "col1";
public static final String COL2 = "col2";
SQLiteDatabase db;
private static final String CRT_MYTABLE_SQL = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME +
"(" +
COL1 + " TEXT, " +
COL2 + " TEXT" +
")";
public DataBaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
db = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CRT_MYTABLE_SQL);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public long addMytableRow(String col1, String col2) {
ContentValues cv = new ContentValues();
cv.put(COL1,col1);
cv.put(COL2,col2);
return db.insert(TABLE_NAME,null,cv);
}
public ArrayList<String> getData() {
ArrayList<String> rv = new ArrayList<>();
Cursor csr = db.query(TABLE_NAME,null,null,null,null,null,null);
while (csr.moveToNext()) {
rv.add(csr.getString(csr.getColumnIndex(COL2)));
}
csr.close();
return rv;
}
public void deleteTaskByCol2(String task) {
db.delete(TABLE_NAME,COL2 + "=?",new String[]{task});
}
}
MainActivity.java
i.e. an example activity that is based upon your code, but according to the above :-
public class MainActivity extends AppCompatActivity {
DataBaseHelper mDataBaseHelper;
ArrayList<String> data;
ListView list;
ArrayAdapter<String> listadapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addSomeTestData();
populateLisView();
}
private void example001() {
}
public void populateLisView() {
mDataBaseHelper = new DataBaseHelper(this);
list = (ListView) this.findViewById(R.id.myListId);
data = mDataBaseHelper.getData();
if (listadapter == null) {
listadapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,android.R.id.text1,data);
list.setAdapter(listadapter);
list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//mDataBaseHelper.deleteTaskWrong(data.get(position)); // ooops
mDataBaseHelper.deleteTaskByCol2(data.get(position));
populateLisView();
return true;
}
});
} else {
listadapter.clear();
listadapter.addAll(data);
listadapter.notifyDataSetChanged();
}
}
private void addSomeTestData() {
if (mDataBaseHelper == null) {
mDataBaseHelper = new DataBaseHelper(this);
}
if (DatabaseUtils.queryNumEntries(mDataBaseHelper.getWritableDatabase(),DataBaseHelper.TABLE_NAME) > 0) return;
mDataBaseHelper.addMytableRow("Test1","Test1");
mDataBaseHelper.addMytableRow("Test2","Test2");
mDataBaseHelper.addMytableRow("Test3","Test3");
mDataBaseHelper.addMytableRow("Test4","Test4");
}
}
Note AddSomeTestData adds some data for testing/demonstration.
Result
When first run :-
After LongClicking Test 2
i.e. the long clicked item has been removed (from the list and the database) and the list refreshed.
Try to replace
db.delete(TABLE_NAME, COL2 , new String[]{task});
By
db.delete(TABLE_NAME, COL2 + " = ?" , new String[]{task});
I want to implement loadmore with gridview and I am facing problems.
I am able to fetch new data on scroll and I am able to see new views itself. but previous views are disappearing.
I used notifyDataSetChanged().
But still this problem exists help me.
Here is my activity code
setting on scroll method in oncreate
grid.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int lastInScreen = firstVisibleItem + visibleItemCount;
if ((lastInScreen == totalItemCount) && !(loadingMore)) {
if (stopLoadingData == false) {
// FETCH THE NEXT BATCH OF FEEDS
listBikes();
}
}
}
}
listbikes is server call to fetch data on scroll.
In Processlistener method i will set the data to adapter.
bikeList = (CollectionResponseBike) result;
mCursor = bikeList.getNextPageToken();
items = (ArrayList) bikeList.getItems();
Collections.sort(items, new Comparator<Bike>() {
#Override
public int compare(Bike lhs, Bike rhs) {
String id1 = ((Bike) lhs).getTitle();
String id2 = ((Bike) rhs).getTitle();
return id1.compareTo(id2);
}
});
grid.setAdapter(new BikeCustomGrid(BikeGridList.this,items));
loadingMore = false;
progressBar.setVisibility(View.GONE);
Adapter code is here
public BikeCustomGrid(Context c, ArrayList<Bike> mItems) {
mContext = c;
items = mItems;
mLayoutInflater= LayoutInflater.from(c);
VolleySingleton mVolley= VolleySingleton.getInstance(mContext);
mImageLoader=mVolley.getImageLoader();
notifyDataSetChanged();
}
Please let me know the solution for this. thank you in adavance.
Whenever you call your database just add the new data into same list(don't replace it) and don't call the constructor again and again make some method in adapter to provide list and after that just notify the adapter.
Something like this:
mItems.addAll(yourListData coming from server or local db)
adapter.addItems(mItems);
method in adapter:
public addItems(List list){
items.addAll(list)
notifyDataSetChanged();
}
I have DB table with 10,000 rows which I want to display in the listview. I want to display first 20 and when the user scrolls down to the last item the next 20 should be loaded (and so on.). it really takes a lot of time to load all the datas in the listview so thats why i want it to load 20 datas first..
inside onCreate() Method the code is:
dbHelper = new WordDbAdapter(this);
dbHelper.open();
//Generate ListView from SQLite Database
displayListView();
then on the displayListView() method the code is like this:
#SuppressWarnings("deprecation")
private void displayListView() {
final Cursor cursor = dbHelper.fetchAllWords();
// The desired columns to be bound
String[] columns = new String[] {
WordDbAdapter.KEY_WORD,
WordDbAdapter.KEY_ROWID,
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.Word,
R.id.imgStar,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.word_info,
cursor,
columns,
to
);
ListView listView = (ListView) findViewById(R.id.Diclist);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
listView.setOnScrollListener(new OnScrollListener(){
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int lastInScreen = firstVisibleItem + visibleItemCount;
if(cursor != null){
if(lastInScreen == totalItemCount && isLoadingMore == false){
isLoadingMore = true;
loadedPage ++;
new LoadWords().execute();
}
}
}
public void onScrollStateChanged(AbsListView view, int scrollState) {}
});
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
// Get the cursor, positioned to the corresponding row in the result set
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
// Get the word name from this row in the database.
String wordSelected =
cursor.getString(cursor.getColumnIndexOrThrow("word"));
String wordSyllabication =
cursor.getString(cursor.getColumnIndexOrThrow("syllabication"));
String wordPartofSpeech =
cursor.getString(cursor.getColumnIndexOrThrow("partofspeech"));
String wordMeaning =
cursor.getString(cursor.getColumnIndexOrThrow("meaning"));
String wordSpeak =
cursor.getString(cursor.getColumnIndexOrThrow("speakword"));
EditText TextDic = (EditText) findViewById(R.id.TextDic);
TextDic.setText(wordSelected);
speakMeaning = wordMeaning;
speakSyllabication = wordSyllabication;
speakPartOfSpeech = wordPartofSpeech;
speakWord = wordSpeak;
speakGetWord = wordSelected;
//Toast.makeText(getApplicationContext(),
// wordSyllabication + "\n" + wordPartofSpeech + "\n" + wordMeaning , Toast.LENGTH_SHORT).show();
}
});
EditText TextDic = (EditText) findViewById(R.id.TextDic);
TextDic.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
speakWord = "";
speakMeaning = "";
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
dataAdapter.getFilter().filter(s.toString());
}
});
dataAdapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
return dbHelper.fetchWordsByWord(constraint.toString());
}
});
}
then my AsyncTask is like this:
private class LoadWords extends AsyncTask<String, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(DictionaryActivity.this);
Cursor cursor = dbHelper.fetchAllWords();
#Override
protected void onPreExecute() {
this.dialog.setMessage("Loading books...");
this.dialog.show();
}
public void execute() {
// TODO Auto-generated method stub
}
#Override
protected Void doInBackground(String... arg0) {
try{
cursor = dbHelper.fetchAllWords();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
#SuppressWarnings("deprecation")
#Override
protected void onPostExecute(final Void unused){
if(cursor != null){
if(dataAdapter == null){
startManagingCursor(cursor);
String[] columns = new String[] {
WordDbAdapter.KEY_WORD,
WordDbAdapter.KEY_ROWID,
};
int[] to = new int[] {
R.id.Word,
R.id.imgStar,
};
getListView().setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
dataAdapter = new SimpleCursorAdapter(DictionaryActivity.this, R.layout.word_info, cursor, columns, to);
ListView listView = (ListView) findViewById(R.id.Diclist);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
}else{
dataAdapter.notifyDataSetChanged();
}
}
if(dialog != null && dialog.isShowing()){
dialog.dismiss();
}
isLoadingMore = false;
}
private AbsListView getListView() {
// TODO Auto-generated method stub
return null;
}
}
The adapter doesn't load everything at once, and that should not be the reason you're seeing poor performance. ListView and SimpleCursorAdapter are fully capable of scrolling a list of only 10,000 items. The adapter only loads items as the user scrolls through the list. From the code that you've posted, I would say that your performance issues come from
dbHelper.deleteAllWords();
dbHelper.insertSomeWords();
If you post the code for these methods and dbHelper.fetchAllWords(), perhaps we can offer more help. Additionally, you can solve user interface problems by executing these long running tasks on a background thread (check out AsyncTask) and using a ProgressDialog to inform the user what is going on.
Take a look at Endless Adapter from the great Mark Murphy. It makes it really easy. You'll have your dataset that contains just the items you're displaying. In the adapter you can then tell it to grab the next set from your database and add it to the dataset.