Stop a thread downloading images when activity finishes - android

In my app, the activity starts a thread which download images from server. There are more than 30 images. While downloading, the user can switch to another activity. So I want that the thread should stop doing whatever it is doing. I have used mThread.interrupt() method in onDestroy(), but it did not worked. How to do that?

I can suggest simpler&safer approach to handle this
Use common value across your app;
SharedPreferences or inside Application context
Key=IsStopDownload
Value= True / False
part.1)
in Application context (MyApplication)
private boolean isAppActive = false;
public void setAppState(Context context, boolean state) {
isAppActive = state;
// note: you can also store this in SharedPreferences
}
public boolean getAppState(Context context) {
return isAppActive;
// note: you can also load this from SharedPreferences
}
part.2)
Activity onResume and onPause are the guaranteed places to identify state of your activity.
onResume -> activity is active
onPause -> activity is not active
part.3)
let your thread check the activity state and if not active, it can stop itself, thats safer then making external interrupt. threads can act weird when interrupted from outside, it is safer to break the loop from inside.
e.g.
((MyApplication)context.getApplicationContext()).getAppState(context);
if thats false, thread stops itself
hope this helps...
---
Social Coding #AspiroTV

When user will switch the activity , this one will not destroyed but paused so trying your code is onPause() might work .

First of all, you're probably much better using an AsyncTask than a Thread, so, personally, I wouldn't use a Thread at all. In my humble opinion and small experience, in that situation where you're using them, they grow and grow until you have spaguetti code.
And second, as Dr. Nik said, this task is typically better served using a Service. It's is, in my opinion, the best and safer thing you can do.
I would point out several reasons why you should use one:
The service does not need to stop because the activity goes away.
Services are very easy and quick to implement. And the notification code for completion is also easy.
You are downloading images, and it's always better to do the job at once if you can, to save bandwidth and connection time for the user and cache images locally. This used to be worse because today cell phones are full fledged computers. But it's always important to code for efficiency. Therefore, IMHO, you should keep the need for a connection as small/quick as possible.
Finally, even using AsyncTasks inside an activity demands a tricky (simple, but still tricky) code to catch and detach the task when the Activity is going away, and a check for nulls when it's coming back. Since you're downloading images, and that can take a time and it's very possible that the user may demand an orientation change (turn the device to landscape), you will need that. Search stackoverflow for "orientation change asynctask" for examples.
There are probably other reasons, too, but those are on the top of my head right now. And of course, it's my opinion.

Related

How to deal with retained data after Activity comes to foreground when using more than one Activity?

At the moment I'm a little bit confused about the lifecycle management in Android. There are at least 4 possibilities to resume retained data after an Activity comes back to the foreground:
Android handling: If there is enough memory, Android stores and resumes the important data (checked radio buttons, text of EditText,-... and so on) after Activity restart, the user has the same state as before as the Activity went into background.
onPause, onResume: Overriding onPause and save the important data to a database or text file and resume it when onResume is executed next time.
onSavedInstance(Bundle), onRestoreInstance(Bundle): I can save the data as key-value-pair into bundles and restore them after onRestoreInstance is executed.
onRetainNonConfigurationInstance(), getLastNonConfigurationInstance(): I handle all my storage issues in one big object and read getLastNonConfigurationInstance() out when onCreate is executed.
Although it is confusing which approach is best, I guess it relies on development experience to know when to use which possibility. If you have some good examples for each I would be glad, but this is not my question. I wonder how to deal with all that when I have different Activities and one Activity will be killed by Android when it pauses in background:
In my case I have a MainActivity and a MessageActivity. The MessageActivity consists of a ViewSwitcher which consists of two states. State one is a radio button choice list. State two is an EditText with two buttons (send and abort). When I monkey test each state, hit the Android home button, and restart the application, the right Activity with the right state and the old data comes into foreground, when I leave the handling to Android. So that works.
But what happens when Android destroys the MessageActivity in background:
If I use the Android way, the data is lost and I guess MainActivity (instead of MessageActivity->state(1 or 2)) will start next time after I relaunch the application (is that correct?). So when I'd like to keep the data of MessageActivity, I have to use one of the other three possibilities.
How to do that neatly, when the application entry point (so the MainActivity) differs from the last active Activity. The problem is that I have to resume a special Activity with a special state of ViewSwitcher. I could start MessageActivity out of MainActivity with startActivity(Intent) in onStart() or onResume() method (because MainActivity is probably the entry point) but then I run into a lot of logical problems in Lifecycle management. Due to this fact I don't think that this is the right way to do that.
But, what's the right and best way to do that?
I guess MainActivity (instead of MessageActivity->state(1 or 2)) will start next time after I relaunch the application (is that correct?)
No, I don't believe this is correct, depending on what your code does in onCreate(). It certainly doesn't need to be correct if you go about things the right way. A simple way to test this is to rotate your screen, which recreates the running activities, unless you have overridden the default configuration change behaviour.
I recommend reading this section in the android docs carefully:
http://developer.android.com/guide/topics/fundamentals/activities.html#SavingActivityState
In particular:
even if you do nothing and do not implement onSaveInstanceState(), some of the activity state is restored by the Activity class's default implementation of onSaveInstanceState(). Specifically, the default implementation calls onSaveInstanceState() for every View in the layout, which allows each view to provide information about itself that should be saved. Almost every widget in the Android framework implements this method as appropriate, such that any visible changes to the UI are automatically saved and restored when your activity is recreated. For example, the EditText widget saves any text entered by the user and the CheckBox widget saves whether it's checked or not. The only work required by you is to provide a unique ID (with the android:id attribute) for each widget you want to save its state. If a widget does not have an ID, then it cannot save its state.
What this means is, that so long as you don't force any UI state in any onCreate() calls, your activity stack and UI state will be restored.
Personally, my preferred approach is to keep as little state as possible in member variables of my activities, saving and restoring it with onSave/RestoreInstanceState(), and relying on the default implementations to save the rest of the UI state (text box contents, etc). Data that should persist between sessions I commit straight to my DB or preferences as soon as it's changed (e.g. in the on-click handler). This means I don't need to worry about the activity lifecycle for that. As much as possible, my UI just presents a view of the data in my DB (using CursorAdapter etc.).
Edit:
Regarding restoration of the whole activity stack:
When the user leaves a task by pressing the HOME key, ... The system retains the state of every activity in the task. If the user later resumes the task by selecting the launcher icon that began the task, the task comes to the foreground and resumes the activity at the top of the stack.
(See http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html)
It's not my attempt for a best answer, but it's too long to get in the comments section.
First I will suggest not to rely on the "Android way" - this will result in inconsistent application behavior depending on the free memory of the device - bad practice.
My suggestion is to save your state-dependent data in key-value pairs in SharedPreferences, every time you go into onPause() in your MessageActivity. Store a flag in SharedPreferences, which indicates which was the Activity that was last opened (if you only have two Activities you can easily go 0/1 or true/false flags).
When you re-launch your application, it's normal to start the Activity marked in your AndroidManifest.xml as "entry point". So naturally you'll check the flag in onResume() in your MainActivity and start the other Activity if needed. In MessageActivity's onResume() check the values in SharedPreferences and fill in what's necessary...
If your application is "resumed" to the last Activity in the ActivityStack this will call onResume() in the last Activity in the ActivityStack.
The way I have handled an issue like this in the past, is to have a service running in the background, which handles the flow of information from different activities via either Intents and listeners (preferable, since they are the most easily decoupled solution), or if you are extremely careful, and the only viable solution for some reason is to store the data through direct property access or method calls, you can use static properties/methods on the service class as well. However, I would strongly recommend using the Intent/listener method as it is generally more flexible, thread safe, and decoupled. Additionally, it is wise to make sure that not much is happening at any point in time (in other words, only use this service for Intent handling) when it's not needed, otherwise the Service will tend to hog CPU time as well as RAM, when it's not really needed.
Some resources to look at when it comes to this approach would be IntentService and its related classes, including the superclass, Service. IntentService, however, it is worth noting handles a few more things about async Intent processing, etc that Service does not automatically come with.Hope this helps you!
login.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
String name=username.getText().toString();
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = settings.edit();
editor.putString("username", name);
if(name.equals("xxx")) {
Intent intent=new Intent(currentactivity.this,nextactivity.class);
intent.putExtras(bundle);
startActivityForResult(intent,0);
}
}
});

How to prevent activity to reload on back action

I have app that connects to internet to get data. I can access data multi-level.
So let say I start at level 3 and on level 4 I decide to go back, whenever I press back the previous activity reloads the data from the internet.
Is there any possibility to prevent that?
I have tried to run the activity in single-top mode.
Move the data loading code to the single-exec event: onStart or
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
// here
}
}
You have a lot of options here.
The simpler one is to avoid stopping your activity when you switch to another one. When you go to level 4 by means of startActivity(), your onPause() is called on the level 3 activity but it continues living in the background. Then when you come back from 3, onResume() is called.
So as long as you don't load data on resume nor finish() your level 3 activity, you should be fine. If the system happens to be very short on resources then level 3 activity might be killed (though this is very rare) and restarted when you get back to it, but if it happens it means the system needed memory for something important and it's probably fine to reload.
Now, there are other ways. It's usually much better to do it as I described above, but if for some reason you want to finish your level 3 activity, Here are your options.
As it has been noted, you may elect to dump your data somewhere. The saved instance state is an option - though if it's heavy data, more than a few kilobytes, it's not recommended. The idea is, you save your data in onSaveInstanceState() in the Bundle and restore it in onCreate().
If it's heavy data, you would be better off dumping it in a cache file.
If you have a data model, and want to use the same data across several activities, maybe a widget and possibly even a different app, you may want to consider building a ContentProvider to supply the data. It would live independently of the other parts of your application and manage access to the data. Other parts would query it for the data they would need.
The neat thing about that is, it abstracts the data away from the rest of the program. It can be accessed from anywhere and caching policies and everything is handled in a dedicated place. The drawback is, it's significantly more complicated.
One possible solution would be to work with states. You basically have a boolean which indicates if your activity has performed a certain action.
If the action was performed you it won't reach that code again. Of course that flag must be saved somewhere in the Application context or in SharedPreferences.
You can add this parameter to your intent to prevent reloading.
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(new Intent(this,My.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));

Handling of server requests and device rotations

I read a lot about handling rotation in android applications, but I still have so many questions and need to much to understand.
Let me explain my problem or implementation, that I'm using now in my application.
If an activity will be opened, a get request will be sent to server. This request will be executed in a Thread (new Thread(...)) and if request was completed, activity's ui will be refreshed.
But what should I do, if the user rotate his device?
By default, the activity will be destroyed and request will be started again and start a new thread, but the thread of destroyed activity may be still running.
I guess, it's a quite wrong way, I have now.
But what is the best approach, to handle this?
Probably is the best way to forbid rotation, but what If I don't want that?!
May be it's the second part of my question:
I saw a video form Google IO. Mr. Dobjanschi suggested to use services and to store retrieved data in content provider. So, probably I can use a service for executing my requests. But should data be replaced every time the get request was completed?!
Well dont know exactly how its done, You can try saving the instance and retrieving the same when config changes with following methods:
I have read about them but haven't really implemented them yet. I hope it can give you some start.
#Override
public Object onRetainNonConfigurationInstance() {
return(myServerThread);
}
private void restoreServerFunctions() {
if (getLastNonConfigurationInstance()!=null) {
myServerThread=(Thread)getLastNonConfigurationInstance();
}
}
You can specify that the activity handles the rotation itself. This is done through adding:
android:configChanges="keyboardHidden|orientation"
in the tag of the activity inside your android manifest. You don't have to actually handle the rotation but this will tell android to not destroy your activity. The base activity class will handle all the rotating of the user interface for you and your thread will be executed correct.
A small side note: if you are doing only a small server task use AsyncTask to execute the call to the server in the background instead of creating a thread. This will minimze some of the programming effort you need to communicate the results from the thread to the activity and update your UI.
One easy way, though I've never tried it. Instead of refreshing the current UI, when the thread finishes, start a new Activity with the just downloaded content. So first, you start an Activity with a blank page (or just the page's frame), then you rotate the blank page as much as you like, then the downloading Thread spawns a new Activity, replacing the blank page Activity with the loaded content page using the current orientation.

Determining if app is running in background

How can I tell that my application has been put in the background (i.e. none of my app's activities are visible anymore)? I need to determine this so that I can release resources shared among several of my activities (graphics, sound clips and a socket connection).
I've thought about keeping a global counter that's incremented in the activities' onStart() method, and decremented in onStop(). If the counter reaches zero, then all activities have been stopped and my app is running in the background. However I'm not sure if this is going to be 100% reliable. Also, I can't help but think that there must be a better way of doing this.
You shouldn't need to know this, but to answer you:
in your main activity:
public boolean inBackground;
#Override
public void onPause()
{
inBackground=true;
super.onPause();
}
#Override
public void onResume()
{
inBackground=false;
super.onResume();
}
Aren't you after the OnPause()/OnResume() events?
http://developer.android.com/reference/android/app/Activity.html#onPause()
http://developer.android.com/reference/android/app/Activity.html#onResume()
See http://developer.android.com/guide/topics/fundamentals.html#lcycles for an overview.
You could use a global counter assuming it is kept in persistent storage. Always keep in mind the system is free to unload and reload activities from device RAM based on pressure from other apps so instance variables of activities are probably not a good choice to house that data.
I think the Android way of handling a scenario like yours would be to manage your connection state in a service and use persistent storage to monitor application state.
If you need this functionality maybe your architecture is not well designed. Each activity must be in some way "standalone" so when it's stopped release any data associate with it. If you need to store some persistant data between activities use sql or some other data storage and if you need some shared resources between activities put them in service. Try to isolate any coupling between activities.
I haven't tried this myself yet, but I think the following would work.
Create your own custom Activity class that extends Activity (as suggested in this SO question).
Ensure all your activites extend your custom Activity class.
#Override the onStop() method (as per the Activity life cycle docs).
Have onStop() call the utility method below (code based on Droid-Fu project) to figure out if your app is now in the background.
My worry is there could be some timing windows when your last activity closes before its new activity (also i your app) launches, but hopefully that is avoidable.
public static boolean isApplicationInBackground(Context context)
{
ActivityManager am =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty())
{
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName()))
{
return true;
}
}
return false;
}
Let us know how you get on as I might need to implement this feature too!
Update: I've done some quick testing of this code.
It seems to work fine when pressing the home key to exit the application, as the running task changes to ComponentInfo{com.motorola.blur.home/com.motorola.blur.home.HomeActivity} on my device. However, the code doesn't detect the app as in the background when using the back button to exit the application (it still thinks my app is running).
This scenario can be detected by overriding onDestroy() in your top level activities, and checking isFinished() to confirm that the app is getting destroyed (rather than the activity being recreated, e.g. for an orientation change).

android thread management onPause

I have a class that extends the Thread class and has its run method implemented as so.
public void run(){
while(!terminate){
if(paused){
Thread.yield();
}else{
accummulator++;
}
}
}
This thread is spawned from the onCreate method.
When my UI is hidden (when the Home key is pressed) my onPause method will set the paused flag to true and yield the tread. However in the DDMS I still see the uTime of the thread accumulate and its state as "running".
So my question is. What is the proper way to stop the thread so that it does not use up CPU time?
It is actually bad practice to keep a thread running after onPause. The reason is that after onPause your application may drop out of memory at any time without your being able to know, therefore you will not be able to clean up after yourself.
The proper way to do it is stopping the thread onPause and recreating it onResume. If you need state you can use Android's built in saveState methods or settings or whichever to keep that.
Even though you're calling thread.yield(), you're inside of a while() loop which is probably looping thousands of time per second, each time calling .yield() but the fact that it's looping out of control means that it's using up resources. If you put a Log.d message in there you'll see what I mean.
I recommend using a Thread.sleep() instead of Thread.yield(). The reason being, while a thread is sleeping it is yielded. Plus with the sleep you get the added benefit of slowing down the while() and not using up resources. A sleep interval of 500ms should be sufficient =)
Your paused variable is most likely being cached thread-locally. This is because it's only being read and not changed in the loop. So what is happening is that compiler/interpreter/jitter optimizes by only reading the variable once and then only executing the else branch. You need to mark that field as volatile for the pause variable to be read every iteration through the loop. Check out the documentation of the volatile keyword. Here's some info about threading and some info about synchronization and concurrency.

Categories

Resources