I have a little app that is doing something like the following
inflating the layout
getting viewpager from layout
getting json object from network using asyntask without .get() to avoid blocking UI
setting viewpager adapter that requires the json object from network and using data from json
Returning layout
The issue here is that if using asyntask without .get() in some case I get null object and app crashes, most likely due to no json object present yet. I should somehow have the user wait there, and I do use splash screen on pre-execute and hiding on completion of asyntask, but the order there can't be changed, since it's within the viewpager adapter setup. So the execution of the code does not stops there.
With these case, what is the best or proper approach. It seems to me that I can't avoid the UI blocking. Has anyone else had a similar case?
Some pointers would really be great :(
Thank you.
There is no need in calling AsyncTask.get(). I guess you are misusing AsyncTask. It only returns that what you are returning in your doInBackground() implementation, and here you are returning null somehow.
Blocking UI is definetly no option! Forget it!
I would recommend to use well known http libraries like retrofit
or Volley
Related
I am using Async task to populate auto-complete suggestions from server.
Problem:
when user types and removes the text in edittext so many times.
lets say he typed: cofee > cof > coffee >coffee late .... etc for so many times.
for each text changed after 3 keyword(threshold) i am initializing an asynctask and ask for result.
so in current scenario i have so many threads running in background. so some of my latest async threads are waiting for there chance.
Whole this make my app very slow.
What can I do to tackle this problem?
If it is possible to load entire data from server at beginning...then you can avoid calling asynctask repeatedly and fetching the data from server. This will improve performance of you app. If data displayed in Listview is String, following link show how to filter it:
http://www.androidhive.info/2012/09/android-adding-search-functionality-to-listview/
And if custom object is used in ListView adapter, try:
Filtering ListView with custom (object) adapter
Hopefully this helps.
You should cancel the current task before issuing a new one. Use AsyncTask#cancel(true) for that and make sure that the execution of the task can be quickly stopped. This means correct handling of interruption and frequent checking whether the task was cancelled in the body of AsyncTask#doInBackground.
And you cannot execute again the AsyncTask you have cancelled. You have to create a new one. (Trying to execute it again leads to IllegalStateExceptions)
It worked for me by cancelling the task each time you change the text (if it is still running).
You need to define your request once outside the listener(private for the class), and then start your listener function by (if your request is not finished, then cancel it).
define your request out side the function
private YourSearchTaskClass YourTaskReq = new YourSearchTaskClass();
then start your addTextChangeListener/afterTextChanged by this
if (YourTaskReq.getStatus()!= AsyncTask.Status.FINISHED)
YourTaskAvReq.cancel(false);
YourTaskReq= new YourSearchTaskClass(keyword);
In my Android app, I am making a http request, getting some data, putting it in my local sqlite database & then populating a gridview using that data. I have the code working for an activity but I need to use fragment now to get this done as there are many similar pages to be shown. I read that using Loader is the best way to deal with data in a fragment.
I am not sure about:
Whether to use CursorLoader, Async taskLoader or SQLiteLoader(developed by commons guy).
In which of the loader functions (onCreateLoader(), onLoadFinished() etc.) do I put my code for making http request, populating the local database & getting the data displayed in a gridview in my fragment
I am also using a lazyload list to show images. How will that fit into the entire thing if I use loader
Can anybody help me with this one? Tried searching for good examples or tutorials but I haven't really found something that's really useful. So, please suggest any if you can. Thanks
Whether to use CursorLoader, Async taskLoader or
SQLiteLoader(developed by commons guy).
CursorLoader is for ContentProviders(which is not your case) and AsyncTaskLoader is the way to go. I haven't use the classes from Commonsware but if they allow overriding of some of their methods then I guess you can use it.
In which of the loader functions (onCreateLoader(), onLoadFinished()
etc.) do I put my code for making http request, populating the local
database & getting the data displayed in a gridview in my fragment
In none of those callbacks because they run(most likely) on the main UI and you must not do network operations in there. The Loader subclasses have the loadInBackground method which runs on a background thread. On this method the Loader queries for data and in which you could place your networks requests and database updating. But you would need to be very careful to not insert duplicate data in the database.
I am also using a lazyload list to show images. How will that fit into
the entire thing if I use loader
As I haven't seen your code, I don't think this two parts are connected. I'm guessing that you use the lazy image loading code directly in the GridView's adapter.
My advice is to not use Loaders for loading and inserting data because their purpose is to only load data on a background thread(having taking care of configuration changes). For your particular situation I would make my own AsyncTaskLoader(or use Commonsware's library) which queries the database for new data. I would then start a new AsyncTask to do the http request and to insert data in the database and then I would trigger a Loader restart in the onPostExecute method of the AsyncTask(with getLoaderManager().restartLoader...). Have a look at this similar question for some problems related to what you're trying to do.
Although I have not tried it yet, but from theoretical point of view I'm asking this question just to clear my doubts.
I have a scenario like:
1. Send a request to a server and receive JSON response. For this I'm using AsyncTask as there can be delay in receiving response.
2. From this response fetch an image URL.
3. Using one more AsyncTask, call the image URL and fetch the image. (Again may take time to fetch image)
So do you think using of 2 AyncTask just to get that image is inefficient.
OR, in step 1, instead of using AsyncTask, run the code sequentially and set Timeout instead.
Please suggest.
I'm going to go ahead and suggest this as an answer, which was originally in my comment:
Just fetch the image synchronously in the same AsyncTask that you're fetching the JSON from. For example:
doInBackground(Void...params){
//fetch JSON
// once JSON is fetched, fetch image
}
Not sure how you want to structure this exactly, but documentation says:
execute(Params...) must be invoked on the UI thread.
http://developer.android.com/reference/android/os/AsyncTask.html
so you cannot execute new async task from other async task background method.
even if you tried doing this from progress method, then since HONEYCOMB asynctasks are serialized, so your second async task will get queued anyway - you would have to use THREAD_POOL_EXECUTOR to make it run parallel.
The endless adapter that I've used in my code, doesn't stop expecting data even if I am out of it. Thus the throbbing symbol, which is the loading symbol here, keeps on circling expecting some data.
How do I stop it? How do I make the endless adapter know that I'm out of data?
Also, I would like to tweak the adapter so that it can use multiple lists. Is it possible? By multiple lists, I mean list embedded inside another list. If yes, is there an example or any ideas as to how to do it?
How do I make the endless adapter know that I'm out of data?
Quoting the documentation:
Your EndlessAdapter subclass also needs to implement cacheInBackground(). This method will be called from a background thread, and it needs to download more data that will eventually be added to the ListAdapter you used in the constructor. While the demo application simply sleeps for 10 seconds, a real application might make a Web service call or otherwise load in more data.
This method returns a boolean, which needs to be true if there is more data yet to be fetched, false otherwise.
Since this method is called on a background thread, you do not need to fork your own thread. However, at the same time, do not try to update the UI directly.
If you expected to be able to retrieve data, but failed (e.g., network error), that is fine. However, you should then return false, indicating that you have no more data.
Also, I would like to tweak the adapter so that it can use multiple lists. Is it possible? By multiple lists, I mean list embedded inside another list.
No. Android does not support the notion of lists inside of lists. You are welcome to take a look at my MergeAdapter (if you really mean that you wish to concatenate multiple lists together) or Android's ExpandableListView (if your lists-in-lists is really some sort of shallow tree structure).
It is possible to use different data for your own Adapter this data can be of any type such as
ArrayList<HashMap/HashSet<?,List<?>>> it is your own business how you will use it within your getView(...) method. You can implement a poller service which will update your Adapter with data accordingly and setAdapter() after. If there's no data just idle...
hope this helps abit.
I like that my GUI appears immediately when the user starts the app.
Then some data (text, pictures) gets loaded in the background (like YouTube app).
The ListView and Gallery gets updated automatically with this new data.
I initiate my ListView, start a Thread and load the data... and then the ListView does not get updated!
Several people told me I should use notifyDataSetChanged().
But I cannot place this command in my Thread (just unknown).
Any ideas?
I have this same problem... and I got excited when I came across this question. But no answer? :-(
After, letting the problem sit for about two weeks I found the solution here:
Long story short:
Quote from above link:
We must use a Handler object because
we cannot update most UI objects while
in a separate thread. When we send a
message to the Handler it will get
saved into a queue and get executed by
the UI thread as soon as possible.
Once you check out the code you see get what the author is saying.
NOTE: Even with a handler, Android may not let you update a view object from the thread's run() method.
I got this error:
05-31 02:12:17.064: ERROR/AndroidRuntime(881):
android.view.ViewRoot$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
To get around it I updated an array of data in my run() method and used that array to update the view in the handler's handleMessage() method.
I hope this helps others out there.
You may use the slowAdapter to refresh the View:
SlowAdapter slowAdapter = new SlowAdapter(this);
list.setAdapter(slowAdapter);
slowAdapter.notifyDataSetChanged();
Just found it myself while reading this thread and trying around.
Short: AsyncTask's method onProgressUpdate can touch the view: http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...)
Background: I needed to call requery on my cursor so a ListView kept being updated while the task fills the database. The requery call made in doInBackground failed with the mentioned CalledFromWrongThreadException but same code in onProgressUpdate works.