I have a bit of a problem I cannot solve, since it might a bug or something like that. I would like to make a chart with androidplot, and it works really good, but of course it needs some time to draw it (using hundreds of data), so I use a progress dialog to indicate the loading. But what happens is really weird.
I can define the appearance of the activity when it's loading and when it's loaded. When its loading I define a textview in the background setting its text to "loading" and if it is loaded, that textview contains lots of datas, text etc.
onCreate
{
Thread thread = new Thread(new Runnable() {
public void run() {
-------what needs to be appeared after its loaded ----
Textview -> 12,3245,456,78,789
}
----what is on the screen while the progressbar is on---
TextView -> loading..
}
But most of the time after the progress dialog disappears, nothing happens, the textview still says "loading" and rarely it loads the datas and makes the data appear and changes the textview. What I noticed that the more data I would like to appear the rarelier it stays at the loading phase. Of course everytime the loading progessbar appeers then disappears.
Any Suggestion? It is really weird because I use it in a tablayout and other tabs never do this, always make the data appear.
Thanks in advance!
UP: Okay, its always the first tab, whatever it contains, so the first tab is somehow wrong...
The Andoid UI toolkit is not thread-safe. So, you must not manipulate your UI
from a worker thread—you must do all manipulation to your user interface from
the UI thread. Thus, there are simply two rules to Android's single thread model:
1. Do not block the UI thread
2. Do not access the Android UI toolkit from outside the UI thread
read this for more information on how to access UI elements from outside.
edit::
use AsyncTask ::
onCreate
{
new myLoading().execute();
}
class myLoading extends AsyncTask<Void, Void, Void>
{
protected Void doInBackground(Void ... ) {
.......... do all the loading here .........
}
protected void onPostExecute(Void ) {
Textview -> 12,3245,456,78,789
}
}
I figured out some workaround. I dont have any clue about the solution, my only guess is the loading screen somehow overtake the arrival of all the data and so the chart cannot be drawn. or whatever...
I put a thread.sleep(1000) and now it works.
Related
I have a method that takes data in a very large array and displays a very large table on the Display. The table is so large that the screen goes blank for awhile. Can I put the display method inside an Asynctask and display a progress bar until the display method is complete?
No, you can't access Views from background. You can load data into array in a background thread (so it won't block UI during load) and then use this array in an adapter for ListView. I can answer you with more details if you post your code
As mentioned by Chaosit you can't access the UI from a background thread.
consider loading the data in an async task, for loading the table to the UI try to render it row by row. if you are using a listView there are techniques to add/edit cells without rendering the whole table .
i used the same techniques when dealing with large number of PINs that needed to be rendered as the user move the Map .i load some of them and render them 1 by 1 to the UI .
The best way to load a big volume of data is to show a ProgressBar in onPreExecute(), load your data in doInBackground(...) and set the visibility of the progress bar to GONE in onPostExecute(Boolean success).
Another nice way to do it is display a Dialog calling .show() in onPreExecute() and dismiss it in onPostExecute(Boolean success), maybe updating the Dialog message in the onProgressUpdate(String... message).
Just remember that you cannot update or change your UI in doInBackground(...), but you can in onPreExecute(), onPostExecute(Boolean success) and in onProgressUpdate(String... message).
If the data is coming from a the database (or from a remote source) then consider using Loaders/CursorAdapter - to build your ListView. This is a very efficient way of loading data.
If you're reading Array data from a file then try to break down the data - and just select the data that you're displaying on the screen, rather than reading all the data from the file, and try to render item that will not be displayed - Then you can use AsyncTask or a Thread(and Handler) to update your table.
As the others have mentioned, only the main thread can update the UI.
Surely not all the data is shown at once!
Have a look at the Loaders guide. It will allow you to load a large data set, and display only part of it, reducing load times.
Said functionality can be achieved using asynctask as
class TestAsync extends AsyncTask<Void, Integer, String>
{
protected void onPreExecute ()
{
//Start showing progress bar here ...
}
protected String doInBackground(Void...arg0)
{
// Do long running operation here ...
return "You are at PostExecute";
}
protected void onPostExecute(String result)
{
// Start displaying data in your table view and dismiss the progress bar
}
}
Call it like this in your activity:
new TestAsync().execute();
I been fighting an odd issue these last few days. I have a custom ExpandableListAdapter where each row contains an ImageView, among other things. I have a class that handles the asynchronous loading of images from the multitude of places they may reside (disk cache, app data, remote server, etc). In my adapter's getView method I delegate the responsibility of returning a View to the list Item itself (I have multiple row types for my group list). I request the image load as follows:
final ImageView thumb = holder.thumb;
holder.token = mFetcher.fetchThumb(mImage.id, new BitmapFetcher.Callback() {
#Override
public void onBitmap(final Bitmap b) {
thumb.post(new Runnable() {
#Override
public void run() {
thumb.setImageBitmap(b);
}
});
}
#Override
public void onFailure() {
}
});
Yeah, it's ugly, but I decided against some contract where you have the BitmapFetcher.Callback execute its methods on the UI thread by default.
Anyway, when I load the Activity that contains the ExpandableListView there will often be thumb images missing from different rows in the list. Reloading the Activity may cause some of the missing thumbs to show but others that were previously showing may not be anymore. The behavior is pretty random as far as I can tell. Scrolling the ListView such that the rows with missing images get recycled causes the new thumb images (when the recycled row gets displayed again) to load fine. Scrolling back to rows that previously contained missing images causes the missing images to appear. I can confirm that all the images are loading correctly from my BitmapFetcher (mFetcher) class. I should also mention that I load other images in other places. Every once in awhile they don't appear either.
After pulling most of my hair out, I discovered that changing:
thumb.post(new Runnable() {
to:
mExpListView.post(new Runnable() {
fixes the issue. I originally thought that the issue might be happening because I was using a final reference to a View, but the other locations in the app use non-final references to a view to post messages, and, as I mentioned, sometimes those did not work. I eventually changed everything to use an Activity's runOnUiThread() method (and my own getUiThreadRunner().execute method when inside Fragments) and that seems to fix the issue all around.
So my question remains, in what cases can View.post() to fail to deliver the runnable to the associated ViewRoot's message queue in the proper order? Or, perhaps the invalidate() is happening before the View is returned from getView and thus before it's placed in a ViewGroup that can be reached from the root View. Those are really the only cases I can think of that would prevent the image from showing up. I can guarantee that none of these calls are happening until at least onStart has finished executing. Further, it looks like it's fine to post to a View even if it hasn't been attached to a Window yet:
// Execute enqueued actions on every traversal in case a detached view enqueued an action
getRunQueue().executeActions(attachInfo.mHandler);
(in performTraversal). The only difference between the runOnUiThread and post seems to be that an Activity has a different Handler than the ViewRootImpl.
Activity:
final Handler mHandler = new Handler();
whereas in ViewRootImpl:
final ViewRootHandler handler = new ViewRootHandler();
But, this should not be a problem provided both Handlers were constructed in the same Thread (or using the same Looper). That leaves me wondering if it is, indeed, a problem to invalidate() a View that has not yet been added to the hierarchy. For this to be the case invalidate should either 1. not do anything if it's not visible, or 2. only be valid for the next performTraversal() that happens.
View.invalidate() checks a nice private method that's not documented called skipInvalidate():
/**
* Do not invalidate views which are not visible and which are not running an animation. They
* will not get drawn and they should not set dirty flags as if they will be drawn
*/
private boolean skipInvalidate() {
return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null &&
(!(mParent instanceof ViewGroup) ||
!((ViewGroup) mParent).isViewTransitioning(this));
}
It looks like number 1 is more accurate! However, I would think this only pertains to a View's VISIBILITY property. So, is it accurate to assume that a View is considered not VISIBLE if it cannot be reached from the ViewRoot? Or is the VISIBILITY property unaffected by the View's container? If the former is the case (which I suspect it is) it raises a concern. My use of Activity.runOnUiThread is not a solution to the problem. It only happens to work because the invalidate() calls are being sent to a different Handler and being executed later (after getView returns and after the row has been added and made visible on the screen). Has anybody else run into this issue? Is there a good solution?
Hey David I ran into a similar issue long time back. The basic requirement for view.post(Runnable r) is that the view should be attached to the window for Runnable to be executed. However, since you are loading images asynchronously in your first case, therefore there is a probability that imageView aren't attached to window when post request is made and hence, some images fail to load.
Quoting earlier version of docs on the same:
View.post() : Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread. This method can
be invoked from outside of the UI thread only when this View is
attached to a window.
Switching to you next question, what is the best solution to handle this situation ?
Can't comment on the best solution. However, I think both handler.post() and activity.runOnUIThread() are good to go. Since, they basically post runnable in main thread queue irrespective of anything and in general, the request to display list rows would be enqueued prior to our thumb.post(). So, they might work flawlessly for most cases. (Atleast I've never faced a problem with them !). However. if you find a better solution, do share it with me.
Try this : setBitmap() like this :
runOnUiThread(new Runnable() {
#Override
public void run() {
thumb.setImageBitmap(b);
}
});
I haven't started coding yet. I'm trying to figure out which libraries that is out there and what the API can offer first.
I need to download a lot of resources before starting my app. Basically I'm going to have a "SplashSreen" and a progressbar that shows which file being downloaded and the progressbar for the entire progress of downloading the x-number of resources.
After looking through some discussions and tutorials on the subject, it seems to me that AsyncTask will do the job. But it's only possible to show the current progress for the current "object" being downloaded, and not for the entire queue.
Could anyone help me out here, give me some tutorials or something to dig into?
TBH; I'm not even sure if AsyncTask is what I'm looking for in this scenario. Basically I need something that can download resources, put in a queue, and let me know the progress of the entire queue, and which resource (name of it) being download at a certain time.
Thanks!
Of course an AsyncTask can do the job. Just put all your files in a asyncTask which display the progress.
class InitTask extends AsyncTask<Void, Integer, Boolean> {
private List<String> mNbFiles;
public InitTask(List<String> filesURL)
{
super();
mFilesURL = filesURL;
}
#Override
protected void onPreExecute() {
//show and init your progress bar here...
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
for(int i = 0 ; i < mNbFiles.size() ; ++i){
//download one file ...
publishProgress(i);
}
}
}
I hope this will help you. Comment if you have any question.
AsyncTask isn't what you should be using for long running downloads. AsyncTasks are really about the UI, and it's important to know that the user navigating away or even rotating their screen will kill the download.
You should use a service to perform the download, so put all of your download code into an IntentService and update some kind of persistant storage to indicate progress (a couple variables in shared preferences would do fine (on to indicate current state, the other to indicate progress)).
You can then use your activity to fire up the service, and then monitor the progress of the downloads via the persistant storage or some callback passed via the intent (persistant storage is probably easiest).
AsyncTask is exactly what you are looking for, you can queue depending on the API an amount of tasks, im going to check the Asynctask implementation if there is a getter for the queue size, but if not you can make a list of asyncTask and update when its finished.
If you queue 15 tasks you can set your progress bar to 15 max and on each onPostExecute increment the progressBar :)
I will check the queue later and edit my answer.
Regards.
AsyncTask is very much what you're looking for. That's not really true that you can only update for the current Object. What that means is that you can update for the current AsyncTask.
Below is the onProgressUpdate method.
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.i(logTag, "onProgressUpdate: " + String.valueOf(values[0]));
View view = getView();
if(view != null)
((ProgressBar)view.findViewById(R.id.progressBar)).setProgress(values[0]);
}
You see it takes any number of integers as the arguments. In your publishProgress method, you could call onProgressUpdate(itemProgress, totalProgress) and then update 2 different progress bars accordingly in onProgressUpdate.
You do all the downloading in doInBackground and each time you want to update the progress bar/bars, call publishProgress which passes your progress ints to onProgressUpdate.
In your AsyncTask doInBackground() method put your code that downloads all your objects and post updates of the progress bar using a handler. Take a look at this example:
http://developer.android.com/reference/android/widget/ProgressBar.html
The following code goes inside doInBackground():
while (mProgressStatus < 100) {
mProgressStatus = doWork();
// Update the progress bar
mHandler.post(new Runnable() {
public void run() {
mProgress.setProgress(mProgressStatus);
}
});
}
I have a table with about 1k rows that I want to display. This task obviously chokes the UI thread, resulting in a black screen while the onCreate() builds the table.
I've solved this by using AsyncTask which builds the wanted TableLayout in the "doInBackground" function and display it on the "onPostExecute" function.
Question #1:
Is there any better practice that I'm not familiar with?
Question #2:
My (simplified) "doInBackground" function looks like this:
protected Void doInBackground(Void... v) {
tmpTableLayout = populateTable("");
return null;
}
And my (simplified) "onPostExecute" function looks like this:
protected void onPostExecute(Void v) {
TableLayout ct = (TableLayout)findViewById(R.id.RealTable);
ct.removeAllViews();
/* WHATS HERE? */
}
What should I write instead of the "WHATS HERE?" in the last line of code in order to display the content of "tmpTableLayout" in "ct" ?
Thanks in advance!
Are you sure you want to display it all in one go?
One approach would be to dynamically load in more lines as the user scrolls down. So have a scroll listener that checks if the user is approaching the end of the content that is displayed and therefore start an AsyncTask or a thread loading more content.
Example:
Android List Activity with dynamically loaded images form the web in android
I would probably use a ListView and CursorAdapter and let Android manage fetching the data for you. See the accepted answer here.
I have an activity that needs to parse an XML from web, then read in images according to the XML info. To speed things along, I created AsyncTask to do the parsing and image fetching. However, I cannot put the images into the activity from within the thread due to "cannot update view objects from outside the view-creating thread..."
So I moved everything back to the main onCreate routine and it slows things down so much that it's not usable (UI not showing until everything is done (I guess when onCreate returns)) .
Any idea on how to tackle this problem (i.e. parsing/fetching using AsyncTask, then placing/updating images dynamically when each becomes available)? or where in the life-cycle should/can I update the UI?
Thanks in advance for all your help.
How are you using the AsyncTask? It's exactly for the purpose you mentioned: AsyncTask.doInBackground() is running in a separate thread and can be used to do the time-consuming task (loading the bitmap), and AsyncTask.onPostExecute() runs on the UI thread and can be used to perform quick operations that have to happen in the UI thread (i.e. replacing the bitmap in your View).
The async task was the right route. Use the async task to do the work in the background then use onpostexecute.
private class DownloadFilesTask extends AsyncTask<URL, Integer, imageview> {
protected imageView doInBackground(URL... urls) {
//parse and load
}
protected void onProgressUpdate(Integer... progress) {
//update progress if you have progress dialog
}
protected void onPostExecute(imageView result) {
//load image into view.
}
}
See Async task
Try this:
runOnUiThread(Runnable action)
//Runs the specified action on the UI thread.
I implemented this to update a ListView after getting data from the web and it works like a charm. If you download the source from this tutorial ( to the bottom ), you can see an implementation of how this works. :-)
Edit: see this rar file: ( Eclipse source code of an upcoming tutorial :-) )