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.
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 was wondering how I could force a new ASyncTask in Android to be the next task executed. Imagine I have multiple ASyncTask's to load content from the internet, e.g. in my case I pre-load all objects of DataModelA, DataModelB and DataModelC. All the data is loaded to a central application model. I guess my current queue would look like this (but I do not manage it as a queue, yet):
1. DataModelA-Object1
2. DataModelA-Object2
3. DataModelA-Object3
4. DataModelB-Object1
5. DataModelB-Object2
6. DataModelB-Object3
7. DataModelB-Object4
8. DataModelC-Object1
9. DataModelC-Object2
10. ...
I start my tasks like this:
DataModelALoaderTask task = new DataModelALoaderTask();
task.execute("http://my-rest-api.com/datamodel/a");
// and the same for the other tasks
...
The task class looks like this:
private class DataModelALoaderTask extends AsyncTask<String, Void, List<DataModelA>> {
#Override
protected List<DataModelA> doInBackground(String... params) {
String data = params[0];
return DataModelAContentProvider.loadContentFromUrl(data);
}
#Override
protected void onPostExecute(List<DataModelA> models) {
// finally add the loaded content to the central application data model
...
}
}
What I would like to achieve:
Now within my GUI, I like to click on a button and force to load a single part of a model first, because I need to display it right now. Usually this is a task which is already in the queue, but in my case I could also just start a new task, e.g. to load DataModelC-Object2 first before all others are loaded. The queue could load a large number of objects, so that it makes sense to re-schedule a single task or start a new task which does the job immediately.
Any idea how I can handle that? If you would need to see more code snippets, please let me know.
Thanks in advance.
Best regards,
Michael
UPDATE: somehow my question seems to be related to this post. Is that the only way? Or could I simply start a parallel running task using the THREAD_POOL_EXECUTOR? How would I use that?
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.
I am facing an issue of having a screen which gets an id from the SharedPreferences and then I call a remote database, and then I have to display that data on the screen.
Is it possible to do that with ViewText or is there another way to place text on the screen after a remote db call is made?
Whats the best way to do that and how do I accomplish it?
Thanks!!
Use a loader for your db call. Once the data has loaded use onLoadFinished to either add a TextView to your layout or replace the text in an existing layout.
My suggestion would be to create a TextView in your layout in xml so that you can position it exactly as you wish, then replacing the text after your database call using myTextView.setText(databasetext)
The way you display data from a database is completely independent of the way you're getting that data. If it's simply text you need to display, then a TextView seems to be a logical view element to use.
In simple terms, the steps you should be taking would likely be:
Get ID from SharedPreferences
Query database with ID for result
Pass the result to your view layer
Use a TextView to display the result
It's best (and required since 4.0) to make network calls in a thread separate from the UI thread. The best way is probably using an AsyncTask. For example:
private class GetDbItemTask extends AsyncTask<Integer, Void, MyDbItem> {
protected MyDbItem doInBackground(Integer... ids) {
return mDbService.load(ids[0]);
}
protected void onPostExecute(MyDbItem result) {
mTextView.setText(result.toString());
}
}
Have you tried a custom alert dialog this link?
This allows you to have a textview on your screen without changing your activity.
I hope I answered this correctly since you ask
"Is it possible to do that with ViewText or is there another way to
place text on the screen after a remote db call is made?".
Then there is the option of refreshing the screen using onResume() on the activity lifecycle.
The logic would that I would use is to build your screen in XML and have a Textview named myTextView
in your activity declare a Textview
TextView name_field;
String name;
....
.
.
.
//call my database info
//this example get a variable and pass it into String variable name and then display it in your text view
name_field = (TextView) findViewById(R.id.myTextView);
name_field.setText(name);
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 :-) )