I have an application that uses images from web a a source. for my application I'm first downloading images in seperate thread and only if image exists on disk I show on the list. Downloader is a seperate thread, but I'm very new using threads and now something else is confusing me. My images are not shown unless I refresh the view, that is my list. Now I needed to show my images so I wrote this in my custom view :
private Runnable LoaderTask=new Runnable(){
public void run() {
if(cellIcon!=null){
if(iconCache.get(cellIcon)!=null){
icon.setImageBitmap(iconCache.get(cellIcon));
mHandler.postDelayed(this, 200);
}
}
}
};
private class ImageThread extends Thread{
#Override
public void run() {
// mHandler.removeCallbacks(LoaderTask);
mHandler.postDelayed(LoaderTask, 100);
}
}
And I trigger my thread like this
ImageThread thread=new ImageThread();
thread.start();
the handler is instantiated in the beginning of the class. But when I do this n othing happen until I refresh my views. I tried (Activity).runOnUIThread inside one of my threads I got stackoverflow error. How do I solve that or are there any other advices.you can give me? Thanks
Use AsyncTask. In onPostExecute() method just call a method from the activity and refresh the UI. The onPostExecute() is called when the thread is done.
http://developer.android.com/resources/articles/painless-threading.html
P.S. To call an activity's method just use Interface.
Have a look at this:
http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html
Related
I am a beginner to Android and I have some confusions regarding Android UI Thread. Now, I know that no thread apart from the one that created the UI can modify it.
Great.
Here is the Activity from my first Android app which slightly confuses me.
public class NasaDailyImage extends Activity{
public ProgressDialog modalDialog = null;
//------------------------------------------------------------------------------
#Override
protected void onCreate(Bundle savedInstanceState){
//Instantiate progress dialog, skipping details.
Button b = //get reference to button
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
modalDialog.show(); // show modal
Toast.makeText(getApplicationContext(), "Getting feeds", 500).show();
new AsyncRetriever().execute(new IotdHandler()); // Get the feeds !!
}
});
}
//------------------------------------------------------------------------------
public synchronized void resetDisplay(boolean parseErrorOccured,
boolean imageErrorOccured,
IotdHandler newFeeds){
if(parseErrorOccured || imageErrorOccured){
// make a Toast
// do not update display
}else{
// make a Toast
// update display
// based on new feed
}
}
//------------------------------------------------------------------------------
class AsyncRetriever extends AsyncTask<IotdHandler,Void,IotdHandler>{
#Override
protected IotdHandler doInBackground(IotdHandler... arg0) {
IotdHandler handler = arg0[0];
handler.processFeed(); // get the RSS feed data !
return handler;
}
//------------------------------------------------------------------------------
#Override
protected void onPostExecute(IotdHandler fromInBackground){
resetDisplay( // call to update the display
fromInBackground.errorOccured,
fromInBackground.imageError,
fromInBackground);
}
//------------------------------------------------------------------------------
}
1. onCreate is on the UI thread so I can do whatever I want but onClick is not. Why can I make a ProgressDialog and a Toast in that method? Why no error there?
2. The AsyncTask is subclass of the the NasaDailyImage. This means it can access all the methods of NasaDailyImage including resetDisplay() which updates the display. resetDisplay() is called in the onPostExecute which runs on a different thread from UI. So, why can I update the display there and yet get no errors ?
onClick() is indeed on the UI thread. Most of what happens in an Activity happens on the UI thread.
onPostExecte() (and its counterpart onPreExecute()) runs on the UI thread as well. The AsyncTask.onPostExecte() documentation clearly states this. AsyncTask was deliberately designed such that developers could update the UI before and after they do background work.
In general, your code will be running on the UI thread unless you explicitly tell it otherwise. Once you create AsyncTasks, Runnables, or Threads, you need to ensure you understand where your code is executing. In an Activity, it is typically safe to assume you are on the UI thread.
You are extending AsyncTask class , where async task class is calling its sequential method automatically. First onPreExecute then doBackground and finally onPost. If you want to change any ui change you can use onProgressUpdate method.
To use your activity class simple call activityclass.this.resetDisplay(). Because inner class scope sometimes failed to integrate except global varible.
Thanks
I'm developing an android app, i have a separate class that extends Thread class, here i call a service and fetch data, now i need to know when this thread is completed and on completion its shows me a Toast.
Like
"Successful"
Is there any method like onPostExecute() in AsyncTask Thread?
Thanks
Display a toast is different that modify Views component because toast can be displayed from every thread while views need to be accessed only from the main thread.
So, if you need just to display a Thread just call Toast.makeToast(...).show() wherever you are.
Anyway, you can send messages from a backgrund thread to the main thread using the Handler class:
http://developer.android.com/reference/android/os/Handler.html
http://developer.android.com/guide/faq/commontasks.html#threading
i hope you are using thread like this..
.....
new Thread(new Runnable() {
public void run() {
YourMetod(); //you want to execute first
finishedHandler.sendEmptyMessage(0);//when first method is executed completly you need to call this
}
}).start();
....
create a handler in your class
like this
private Handler finishedHandler = new Handler() {
#Override public void handleMessage(Message msg) {
//create your toast here
}
};
try this hope help
I'm creating a startup activity for an application that downloads and parses some data. While it is loading i want to view my startup_loading.xml file, which contains a progressbar and a textview which is set to "loading".
Everything i need to do in the startup is put in a thread, the startUp thread. After running this thread the data is loaded, and then i want to show a new view: startup_loaded.xml which contains two buttons which send you to different activities in the application.
But i have troubles using two views and displaying them at the time i want to.
I thought that if i put the
setContentView(R.layout.startup_loaded);
at the end of the runnable of my thread it would work, but i get an error that that is impossible
CalledFromWrongThreadException: Only the original thread that created
a view hierarchy can touch its views.
I thought i could fix it like this:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
startUp.start();
String language = Locale.getDefault().getISO3Language();
if (startUp.isAlive()) {
setContentView(R.layout.startup_loading);
tv1=(TextView)findViewById(R.id.tvloading);
if(language.equals("nld")) {
tv1.setText("bijwerken");
} else {
tv1.setText("loading");
}
pbar=(ProgressBar)findViewById(R.id.progressBar1);
pbar.setVisibility(1);
} else {
setContentView(R.layout.startup_loaded);
}
}
Thread startUp= new Thread() {
public void run() {
// all the loading
}
};
But this didn't work either: my startup_loaded never appeared.
I tried finishing my thread (finish(); at the end of the runnable), but it finished by total app. Anyone knows what to do?
Use Handler object. Or, use AsyncTask and set new contrent in onPostExecute() method.
Could someone provide a sample implementation for rotating a button on a thread ? As of now I am rotating my button on the UI thread using the following code:
Animation ranim = (Animation) AnimationUtils.loadAnimation(getBaseContext(),
R.anim.rotation);
buttonRotate.setAnimation(ranim);
following should work for you.
Thread thread = new Thread()
{
#Override
public void run() {
try {
Animation ranim = (Animation) AnimationUtils.loadAnimation(getBaseContext(),
R.anim.rotation);
buttonRotate.setAnimation(ranim);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
you might eventually have to create an AsyncTask which can run independently without disturbing UI Thread.
in your UI thread define
Handler mainHandler = new Handler();
then inside your thread, use this:
mainHandler.post(new Runnable()
{
public void run()
{
//your piece of code
}
});
This has served me well so far in several cases, hope it does for you too! :D
EDIT:
mainHandler.post(new Runnable()
{
public void run()
{
while(someBoolean==true)
{
//your piece of code
}
}
});
if you'd define 'someBoolean' inside your class, just like you did with the handler, the thread is supposed to get it, I believe.
this way, after processing your data, simply set someBoolean to false, and the rotating stops.
Unfortunately I don't have access to my IDE at the moment, so I am going to list the steps for you rather that put buggy code up here.
1) Implement "AnimationListener" in the same class that extends Activity.
2) Set a click listener on your button.
3) Create an AsyncTask class.
4) Override doInBackground (of AsyncTask) and place your resource intensive logic there.
5) In onAnimationStart (of AnimationListener), implement the logic to call your AsyncTask, i.e. new MyTask().execute();
6) Define the animation and set it to your button.
This is how it should go: You click the button, onAnimationStart is called, your AsyncTask logic and animation both start. This way you can have your button rotate at the same that that your background thread is performing resource intensive operations - i.e. concurrently.
And just for fun, you may want to disable your button from being clicked again before the background task has finished.
Sorry for the lack of code, but this should be pretty straight forward from here.
I need to load 30+ images to a page (with teaser text). I load all the images via an AsyncTask, but I can't modify the current layout because you can only perform modifications to a view on the main thread. What's the best way to load EVERYTHING asynchronously so that my app doesn't have to hang during a "page load" ?
I don't think you can build a view in the background. You're best bet would be to show a progress dialoge so the user understands why the app is busy.
If your class extends activity, you can use
runOnUiThread(new Runnable() {
public void run() {
//Update UI elements in this block
}
});
Why cannot modify layout? for AsyncTask, you have onProgressUpdate that guarantees to run on UI Thread. You just need to call publishProgress in your doInBackground code.
==Update==
private class LoadImageTask<Url, String, String> extends AsynTask{
doInBackground(Url... urls){
for(int i=0; i<urls.length; i++){
File img = DownloadImage(urls[i]); // Your download method..
publishProgress(img.filename); // Suppose it is saved in sd card
// publish progress will call onProgressUpdate immediately, but on different thread
}
}
onProgressUpdate(String filename){
// Update the UI.. this method will run on UI thread
displayImage(filename);
}
}