notifyDataSetChanged doesn't work when i am reading from sqlite - java

When I attempt to read from SQLite and use adapter.NotifyDataSetChanged. I don't see any changes in my recyclerView.
The main idea is to search in SQLite where the name contains a value from a textView.
Then to repopulate again my adapter.
I create an Instance
private List<InventoryPreviewClass> mItems;
private RecyclerView mRecyclerView;
adpInventoryPreview adapter;
Then inside onCreate() method
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + CategoryID + ""); //Here i am reading from sqlite
mRecyclerView.HasFixedSize = true;
var layout = new GridLayoutManager(this, InventoryRowsPerLine, GridLayoutManager.Vertical, false);
mRecyclerView.SetLayoutManager(layout);
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);
Until now the code works.
My recyclerView is populated with my items from sqlite.
Here is the method when a user types something in TextView
private void EtSearchAlwaysOn_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter.NotifyDataSetChanged();
}
When I am typing something nothing changes in my recyclerView.
Why is this happening?
The only way I found that this works is to reset my items inside my adapter for example:
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);
Why is this happening? I don't think that the second method is right.

This is happening because you are assigning a new object to mItems
The first time you create the mItems list, you pass it onto your adapter, when the next time you are getting a response from your SQLite DB is creating a new instance of the list since you are assigning it to the object.
What you need to do is
Create a method in the adapter that accepts your items like adapter.updateItems(newItems)
The method should clear the list like items.clear() and then add the new items you passed it with items.addAll(newItems)
After that you can call notifyDataSetChanged() within the adapter itself and it will work.
In your, adapter it will look like this
public void updateItems(final List<InventoryPreviewClass> newItems) {
items.clear();
items.addAll(newItems);
notifyDataSetChanged();
}
and then you can call it like this
updatedList = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + CategoryID + "");
adapter.updateItems(updatedList);
I think you missed the point that this is the typical case of pass by value and not pass by reference.

This is a byRef issue.
You pass memory pointer 1 to your adapter and tell it to monitor for changes.
Then you load a list and repoint your memory pointer to spot 2.
Then you tell adapter that it's monitored memory at pointer 1 has changed.
You have two options.
Modify the original list by comparing new results with old results, removing and adding as necessary
or Tell the adapter it has a new memory pointer that it is monitoring by changing the items inside the adapter. Making a method for swapItems(items) will work. Then call notifyDataSetChanged inside the adapter.

you have to set items in your adapter,
create a setter like this :
private List<InventoryPreviewClass> mItems;
.
.
.
public void setItems(List<InventoryPreviewClass> items)
{
mItems=items;
}
and then update your search method like this
private void EtSearchAlwaysOn_TextChanged(object sender,
Android.Text.TextChangedEventArgs e)
{
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass
where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter.setItems(mItems);
adapter.NotifyDataSetChanged();
}

Notify adapter after you set adapter.
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);
adapter.notifyDataSetChanged();

Related

How to make a custom view respond to a search view?

after taking a look at the app by google called google keep, I was immediately curious on how exactly does the search of the app works.
Here is the image of the app:
Whenever you search something, the card that doesn't match would disappear. How exactly do they achieve this because I think that the card are basically custom views and the layout is a custom layout. My problem is that I don't know how to implements a search for custom view.
Note: I have taken a look at some internet example online for search view and I can only find the implementation of searches for listview which is not precisely what I want.
I had a similar problem, so I made my Custom views properties (e.g. name, tag, id, etc...) into a single String spaced by a single space " ".
Something like this inside my CustomView class:
public String toString() {
return (this.name + " " + this.tag + " " + this.coords + " " + this.id );
}
And then I filtered my Custom views through all current Custom views that were shown:
ArrayList<CustomView> filteredList = new ArrayList<>();
...
private void filter(String constraint) {
for(CustomView view : AllViews) {
if (!filteredList.contains(view))
if (view.toString().toLowerCase().contains(constraint.toLowerCase())) {
filteredList.add(view);
break;
}
}
}
// Do something to add the filteredList to your adapter
// and show the new list of CustomViews.
}
You can call filter(newText) method inside onQueryTextChange(String newText) from SearchView OnQueryTextListener().
This way, if whatever word you type in the SearchView is found anywhere in any CustomView, the correspondent CustomView will be visible, otherwise the view will "disappear".
Hope this helps.

Android: Add listvew items to an array list or any work around to achieve the below?

In the below code, where the item’s position and title is getting saved in list_items works fine if list_items and items are ArrayList. For ex;
ArrayList.add(ArrayList.get(position));
But I am trying to use listview:
ArrayList.add(Listview.get(position));
Below is my code
final Listadapter Adapter =new Listadapter(this,packageList1,packageManager);
items.setAdapter(Adapter);
items.setChoiceMode(apps.CHOICE_MODE_MULTIPLE_MODAL);
items.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener()
{
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked)
{
count = count +1;
mode.setTitle(count + "items selected"); //problem resides in the below line
list_items.add(items.get(position));
}
In the above code, on selecting an item from listview I am trying to save it in an Arraylist i.e list_items which could be used in onActionItemClicked method for further action on that respective item.
Any ideas on how to solve or find a workaround to use a listview in the above situation?

Display data from sqlite database in listview instead of toast?

Is it possible to display the following data from sqlite database in a listview instead of a toast as shown in the code below ?
btnlist = (Button) findViewById(R.id.btnlist);
btnlist.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
handler = new Datahandler(getBaseContext());
String getName, getaddress, getDate, getTime, getSchoolName;
getName = "";
getaddress = "";
getDate = "";
getTime = "";
getSchoolName = "";
handler.open();
Cursor C = handler.returnData();// return actual data from
// database
if (C.moveToFirst()) {
do {
getName = C.getString(0);
getaddress = C.getString(1);
getDate = C.getString(2);
getTime = C.getString(3);
getSchoolName = C.getString(4);
} while (C.moveToNext());
}
handler.close();
Toast.makeText(
getBaseContext(),
" Name :" + getName + "Address :"
+ getaddress + "Date :" + getDate + "Time :"
+ getTime + "School :" + getSchoolNname,
Toast.LENGTH_LONG).show();
}
});
}
By list view I'm assuming you mean the first row to have the name, second row to have address, third to have date and so forth? If so I would suggest that you actually make 10 textviews, 5 for labels, and 5 for data. You can put them into a scroll view if you need scrolling. Once you have these text views call .setText(...) on the 5 ones with data to populate them with the data you have in the variables such as getName.
The reason I say to do this is to stay more consistent with typical Android design. Typically list views are used to show lists of data where each row shows different values for the same key such as your contacts. It looks like you will always have five data points so we don't need the overhead of a list view and a static set of text views will serve this purpose just fine.
yes of course its possible :)
You've already done the hard work of getting the data out of the database.
I've put together a super quick example for you. Obviously you'll need to fill in the gaps by reading about a bit and following a few tutorials. Here's a good start:
http://www.vogella.com/tutorials/AndroidListView/article.html
http://webdeveloperpadawan.blogspot.co.uk/2014/09/android-listview-with-differing-rows.html
What you need to do is create a custom object for your student details or whatever they are. Then instead of doing
String getName = C.getString(0)
you would do something like this:
List<Student> students;
Student student;
do{
student.setName(C.getString(0));
...
//Then you add that student into a List of students
students.add(student);
}
Then create a custom adapter which extends your list of students:
public class AdapterStudents extends ArrayAdapter<Student>{
//...
}
Then you create an instance of your adapter and finally just set that adapter to your listview.
As I say follow a few tutorials for more specifics but there's your basic plan of action :)
Good luck.

Object of main activity in result activity not properly accessing boolean variable?

I have a main class that holds two array lists of class objects. Long story short, I'm calling an activity via startActivityForResult to get a return of the position of a spinner item selection. I have two boolean variables in the main activity that basically tell the application which list is being worked with: booleans listASelected and listBSelected. If listASelected = true, then listBSelected = false and visa-versa. In the result activity I basically generate the spinner this way:
MainActivity mainAct = new MainAtivity();
Spinner dropdown = (Spinner)findViewById(R.id.mainMenu);
for(int i = 0;i<mainAct.pickThreeNumbers.size(); i++){
optionsPickThree.add(mainAct.pickThreeNumbers.get(i).getNumbers(1)+mainAct.pickThreeNumbers.get(i).getNumbers(2)+mainAct.pickThreeNumbers.get(i).getNumbers(3));
}
for(int r = 0; r<mainAct.pickFourNumbers.size();r++){
optionsPickFour.add(mainAct.pickFourNumbers.get(r).getNumbers(1)+mainAct.pickFourNumbers.get(r).getNumbers(2)+mainAct.pickFourNumbers.get(r).getNumbers(3)+mainAct.pickFourNumbers.get(r).getNumbers(4));
}
if(mainAct.pickThreeSelected){
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, optionsPickThree);
}else{
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, optionsPickFour);
}
dropdown.setAdapter(adapter);
Then, I use this to do my setResult.
Intent output = new Intent();
if(mainAct.pickThreeSelected){
output.putExtra("slot", position);
output.putExtra("list", "PickThree");
}else{
output.putExtra("slot", position);
output.putExtra("list", "PickFour");
}
setResult(1,output);
finish();
}
The issue is that nomatter what it always works as if mainAct.pickThreeSelected = true, even if I know it is false because other sections of the app are functioning properly. What I assume is happening is that the class object is accessing the variable's initialized values instead of their current values at the time of execution. That, or I'm an idiot and there's a different way to accomplish this.
Any help, fellas? Thanks in advance!
Make pickThreeSelected as static. That way you will update the same instance everytime.
What is the default value that you have set to the mainAct.pickThreeSelected??If its true,make it as false.Then if user selects the listA change the value to true.

ArrayAdapter : Remove by Index

I have a ListView that is populated by a news server rundown (just a list of story slugs) and an arrayAdapter to modify that ListView.
I can remove items by the 'remove(Object)' function but what if there are multiple instances of 'Object'? remove() only removed the first instance of 'Object'. I cannot remove, for example, the second 'Object' in my array adapter without removing the first one. So my question is how can i work around this?
ex : Rundown A
story 1
story 2
Break
story 3
story 4
Break
story 5
etc...
so in this example i cannot delete the Second 'Break' because remove('Break') will remove the first one. if i could removeByIndex(5), that would be perfect but....
Ive tried writing my own remove function that creates a whole new adapter with all members but the specified index. here is what i was messing around with.
public ArrayAdapter<String> removeIndex(ArrayAdapter<String> arr, int index) {
ArrayAdapter<String> temp = new ArrayAdapter<String>(arr.getContext(),R.layout.list_item);
for(int i =0 ; i<arr.getCount();i++){
if(i != index) temp.add(arr.getItem(i));
}
return temp;
}
Help or suggestions are appriciated.
Handle the collection of strings yourself with a List and pass the object into the constructor of the ArrayAdapter. This leaves you with a reference to the List so you can alter the data while allowing the adapter to manage and display as needed.
Note: When modifying the data object you must call
myAdapter.notifyDataSetChanged()
afterwards - which must also be on the UI thread. Obviously the changes to the list don't have to take place on the UI thread and should most likely not happen on the UI thread.
private ArrayList<String> mData = new ArrayList<String>();
private ArrayAdapter<String> mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
// Code that adds the strings
// Create the list adapter
mAdapter = new ArrayAdapter<String>(myActivity.this, android.R.layout.simple_list_item_1, mData);
}
private void removeItem(int index) {
mData.removeAt(index);
myActivity.this.runOnUiThread(new Runnable() {
public void run() {
mAdapter.notifyDataSetChanged();
}
}
}

Categories

Resources