load large amount of data in android spinner blocks UI - android

I am working on an Android app project in one of activities I have a spinner that I used
https://github.com/miteshpithadiya/SearchableSpinner
as I wanted my spinner can be filtered by item name and it works perfect.
But I want to load a very large amount of items in my spinner (about 70000 items). My spinner can load this amount but it takes too long till my UI respond.
I know there are practices that suggest to use paging and other possible resolutions but I can not use them at this moment and also I tried to use a AsyncTask to make this process a background process but it doesn't work either.
Here is my code to load items in spinner by the way (ArrayList goods could contain 70000 items) :
private void prepareProductsSpinner() {
productsSpinner = findViewById(R.id.spinnerProduct);
ArrayList<Good> goods = (ArrayList<Good>) Good.listAll(Good.class);
//fill data in spinner
ArrayAdapter<Good> adapter = new ArrayAdapter<>(AddEditAssetTakingItemActivity.this, android.R.layout.simple_spinner_dropdown_item, goods);
productsSpinner.setAdapter(adapter);
productsSpinner.setTitle("Choose an item");
productsSpinner.setPositiveButton("Select");
}
How can I solve this ?

You can display arraylist in spinner recycleview. The RecyclerView is much more powerful, flexible. it doesn't freezes the UI. It supports the use Viewholder pattern and can contains 100k+ rows it runs very smooth.
Spinner with recylerview.

Related

Android ListView with “tabs”

picture from a reddit news feed
(https://i.stack.imgur.com/6YXMK.jpg)
I am creating an app with a list view that is populated from a sqlite database. Each of the data base items can have a status of either “resolved” or “unresolved”.
I want the listview to have 3 “tabs” with the labels “all items”, “resolved items”, and “unresolved items” with correspoding sqlite queries to populate each.
It should behave similarly to the one pictured.
I assumed this would be a tabbed listview and have been watching tutorials for a week based on those search words and it’s taking taking me down a dark rabbit hole of fragments and changing gradles and so on. I’m not sure tabs are what i really want.
Could I do this with three buttons instead where each button would run a different query and populate my listviewcontainer?
Ideally, when the page is opened, the first “tab” would be highlighted and the listview populated with all records. As the other tabs are pressed, they would highlight and a new query would run.
Would another approach work better?
I’m not asking for code, I just want some conceptual direction on where to focus my research.
If I get you right you need to filter your query results in different lists. Making a lot of queries into database is not the thing that is preferable specially if it's going to be a long process and doing it a lot of times is time and memory consuming.
So to make it work you could simple store your full query result in one variable and change the RecyclerView data using custom method setList() and later using notifyDataSetChanged() to apply the changes.
To make it work you need to get understanding of "how RecyclerView works" and then you will be fine.
So after providing the right logic you would be able to simple split your whole query result as it's needed (by element values for example) as it's showed above:
About the code below:
list - is your query result
leftFilterList or rightFilterList - are lists that contain sorted items
adapter.setList(rightFilterList) - sets the RecyclerView data (filtered items in our case)
adapter.notifyDataSetChanged() - is used to notify RecyclerView that list was changed, and he need to rebuild it.
So we have two Buttons and logic that fillter items in differend ways.
public void left(View view) {
ArrayList<ExampleItem> leftFilterList = new ArrayList<>();
for (ExampleItem item : list) {
if (item.getTitle().length() % 2 == 0) {
leftFilterList.add(item);
}
}
adapter.setList(leftFilterList);
adapter.notifyDataSetChanged();
}
public void right(View view) {
ArrayList<ExampleItem> rightFilterList = new ArrayList<>();
for (ExampleItem item : list) {
if (item.getTitle().length() % 2 == 1) {
rightFilterList.add(item);
}
}
adapter.setList(rightFilterList);
adapter.notifyDataSetChanged();
}
And the result of filtering*:
sorry for wrong toast text. It shows the whole list size.

Android: App response gets slow after several operations

I am developing a POS app for a restaurant. Things work fine, except that after some time the app gets very sluggish. The response appears to be 2 seconds late, and then we need to restart the application.
Here is how it looks like:
Each time when a food category is selected, e.g COLD DRINK, I remove the previous food items below it and add new items according to the selected category.
So, to me it seems that when I frequently add and remove views from the panel (GridLayout), the app gets slower and slower.
I simply do gridLayout.removeAllViews(); to remove all views.
Can anyone tell me how to resolve this please?
You are removing the views, but it don't necessary destroy then, so they continue occupying memory resources.
It's better to use some kind of list with an adapter, like ListView or RecyclerView, witch you can add or remove the views and they will only occupy memory when showing (or all that is showing more two).
You can do something like :
ArrayList<String> listItems = new ArrayList<>();
listaItems.add(yourString); // call that ever you have to add new itens
ArrayAdapter<String> itemsAdapter =
new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);
ListView listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(itemsAdapter);
to remove do something like :
listaItems.remove([INDEX]);
itemsAdapter.notifyDataSetChanged();

Android Listview Filtering versus Repopulation

after some advice really. My app fills a list view on load using a mediastore cursor. This is pulling music linked to user defined folder, which in most cases will be all of their stored music. I have one beta tester that is using an Archos Tablet with approximately 10000 songs on it, running android 2.2. While performance for most users is pretty slick, I wanted to improve the experience for users such as this.
The current process:
User loads app.
App finds default folder
App populates list view with music within and below that folder
User moves to a folder further down the tree, list view is repopulated based on the selected folder
User moves again....list is repopulated based on the selected folder...
So what I'm wondering is this - is it faster/more efficient to use the following process:
User loads app
App finds default folder
app populates list view with music within and below that folder
user moves to a folder within the tree, THE LIST IS FILTERED TO THAT FOLDER
if the user moves higher up the tree than the default data (i.e. potential for new files), the list view is repopulated, but only in this circumstance.
So basically,my questions is "how does filtering compare to repopulation?"
A very good question. Let me try to answer this.
Filtering is actually repopulation the ListView, whereas you create/get a new collection and tell the Adapter it's content has changed by calling notifyDataSetChanged.
The 'heavy' work for a listView is that getView call in it's adapter. I've tested this myself, and if you inflate a new View every time getView is called, the performance drops. Heavenly.
The ListView's adapter is built so that already inflated views can be re-used, which tackles above named problem. Besides, only visible views are loaded, so it's not like the Adapter is going to create 10000 views if you tell it's collection is 10000 items big.
notifyDataSetChanged will tell the adapter to rebuild the listviews content, but it still contains previously inflated views. So here is a big performance win.
So my advice for you is, when you are using the same 'row layout' to just repopulate the ListView using notifyDataSetChanged. I've implemented this multiple times myself without noticing any UI performance issues. Just make sure to do the filtering of your collection an a background thread. (AsyncTask comes in handy here).
One last tip: Do you have any phone thats quite old? Or someone you know does? Find the slowest phone you can and test your application on it for performance. I have a HTC Legend myself, which is outdated and slow if f*ck, but perfect for performance testing. If it runs on my (old) phone, it runs on any phone.
Pseudo code sample if your applications flow:
public class FolderListActivity extends Activity implements OnItemSelected {
// NOTE: THIS IS PSEUDO CODE
private ListView listView
private Adapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstaceState);
// setContentView here
listView = (ListView)findViewById(R.id.your_listview_here);
listView.setOnItemSelectedListener(this);
}
public class AsyncLoadMusicLocationTask extends AsyncTask<Void, Void, List<String>> {
public List<String> doInBackground(Void... params) {
// Load the information here, this happens in the background
// using that cursor, i'm not sure what kind of things you are using
// So I assumed a List of Strings
}
#Override
public void onPostExecute(List<String> result) {
// Here we have our collection that was retrieved in a background thread
// This is on the UI thread
// Create the listviews adapter here
adapter = new Adapter(result, and other parameters);
listView.setAdapter(adapter);
}
}
#Override
public void onItemSelect(Some params, not sure which) {
// THIS SHOULD BE DONE ON THE BACKGROUND THE PREVENT UI PERFORMANCE ISSUES
List<String> collection = adapter.getObjects();
for (int i = 0; i < collection.size(); i++) {
// Filter here
}
// this method will most probably not exist, so you will need to implement your own Adapter class
adapter.setObjects(collections);
adapter.notifyDataSetChanged();
}
}

how to fetch 20 objects at a time from 1000 objects and show in listview

In my application I am fetching the data from a web service in XML format, and parsing it and showing the data in listview. The problem is that if the web service contains 5000 objects then it takes a lot of time to display the data.
Can it be possible to show some data in listview and fetch the data at the same time at the end of the list.
Please provide me some sample code.
If you use convertView in your ListAdapter´s getView method it should not matter how many items you have in the list since the Views are beeing reused.
If your Listadapter takes an array of som sort you could add items to the array continuosly and call
mListAdapter.notifyDataSetChanged();
every time new data is added to the list.
By Using AsyncTask you can do this easily as each object is being fetched can be shown in listview using publishProgress() method while also updating user about what percentage of data hasbeen loaded.
Update:
By the way according to your situation the tool below which is developed by commonsware https://stackoverflow.com/users/115145/commonsware will suits you best...
https://github.com/commonsguy/cwac-endless
cwac-endless: Provides the EndlessAdapter, a wrapper for an existing ListAdapter that adds "endless list" capability. When the user scrolls to the bottom of the list, if there is more data for this list to be retrieved, your code gets invoked in a background thread to fetch the new rows, which then get seamlessly attached to the bottom of the list.

Passing information between views

I am new to android programming, but I am trying to learn. I have written some code that takes in some parameters through a "normal" view with checkboxes and textviews. Then I use this information to generate a lot of numbers that I want to display in a listview. I have managed to create a listview when I press a run button, but how do I pass the information from the main view to the listview. Is it best to pass the information one number at the time or a large array with all the numbers. The list of numbers can be really large.
What you probably what to do is create an adapter with the numbers as the data source. If the numbers are in an array you can create a new ArrayAdapter and set the ListView adapter as that adapter:
ArrayAdapter adapter = new ArrayAdapter<Double>(getApplicationContext(), R.id.id_of_textbox, arrayOfDoubles);
listView.setAdapter(adapter);
In this code I've assumed the numbers are doubles, however ArrayAdapter is a generic class so it can be any object contained in the array. The array can also be presented as a List (like an ArrayList).
Hope that helps you out. Here are some bit of documentation to read and some good video sessions to watch:
ArrayAdapter
ListView.setAdapter()
The World of ListView Google I/O 2010 Session
How big is the array can get?
Most likely that displaying the list as another activity and passing the data as intent's extra will be the solution.

Categories

Resources