Hi I'm implementing a custom asynctaskloader to load data in the background, and I need the loading process to run even if the user navigated out of the application. The problem is, once the user presses the menu button for example the loader onStopLoading() is called and then the loadInbackgroud() is called to restart the loading process.
Any ideas how can I prevent the loader to restart the loading process every time I navigate out of the program or turn of the screen given that during the loading process I acquire a partial wake lock.
P.S: The loader is attached to a fragment and the fragment RetainInstance is set to true.
Thanks in advance.
Have you considered using an IntentService instead of an AsyncTask?
An IntentService is a component which runs in the background and is not bound to the lifecycle of an activity, thus will not be affected when a fragment/activity is paused/restarted/destroyed. You can still publish progress/results/failures to activity or fragment-based listeners using a ResultReceiver.
A very basic code sample:
public class MyService extends IntentService
{
public MyService()
{
super("MyService");
}
#Override
protected void onHandleIntent(Intent intent)
{
// Perform your loading here ...
publishOutcome("Success");
}
private void publishOutcome(String outcome)
{
Bundle outcomeData = new Bundle();
outcomeData.putString(OUTCOME, outcome);
receiver.send(MY_OUTCOME, outcomeData );
}
}
For a more detailed discussion on AsyncTask vs IntentService have a look at this StackOverflow question.
Related
I want to perform logic whenever my Android app is in the process of being closed, so to avoid duplicating the same logic on each Activity.
Similar to OnCreate() below, which is invoked whenever the app is starting, I need the close/terminate method.
public class Application : Android.App.Application
{
public override void OnCreate()
{
}
}
Most of the times your Application class will not know that it is going to shut down because usually it is just killed by the system. You can hide activity but you can't hide application since it is always there (as long as process runs). And if user (or system) decides to manually kill it you will not get any chance to save your data since it might be time consuming. So the best way would be to call custom method in Application from your Activity's onStop() and save everything you need. And it will be a good idea to save data in background thread.
In activity class:
#Override
protected void onStop()
{
((CustomApplication)getApplication()).onCloseCustom();
super.onStop();
}
In your application class
public void onCloseCustom()
{
//do whatever you need
}
I have some fragments loaded in a ViewPager, where each "page" is loaded from a row in a cursor. Each fragment shows an image (JPEG) on the device. When the user dismisses the fragment (i.e swipe/page change, hits back/up, or just closes the app entirely) I want to invoke a method which opens the JPEG file for writing and does an update of its metadata. The actual work is eventually handled by the Apache Commons Imaging library.
I've implemented this by invoking my saveToFile() method from each fragment's life cycle onStop() handler. Does this mean the entire file operation ends up running on the UI thread? Should I definitely set up an AsyncTask for this?
Say the file write for some reason suddenly (for some jpeg) should take a long time, eg 2 minutes. What would then happen? Would the UI just wait (freeze) at this page/fragment before resuming? Or would the process (write to file) carry on "in the background" somehow? Or would the process just be killed, stopped short mid-process?
The way I have this wired up currently (onStop invoking saveToFile(), which calls up the imaging library and then updates the file) seems to work as it should. Even if I end the app, I still see my Toast text popping up, saying "Writing to file..." Seemingly, the process is never disturbed, and I can't say I'm experiencing any UI lag.
onStop() handler. Does this mean the entire file operation ends up
running on the UI thread? Should I definitely set up an AsyncTask for
this?
YES
An AsyncTask has several parts: a doInBackground method that does, in fact, run on a separate thread and the onPostExecute method that runs on the UI thread.
You can also use some sort of observer pattern such as EventBus to run async and post results to the UI.
Say the file write for some reason suddenly (for some jpeg) should
take a long time, eg 2 minutes. What would then happen? Would the UI
just wait (freeze)
The application will crash because Android will forcefully close it due to ANR (Application Not Responding).
Refer to the official documentation for details on this: https://developer.android.com/training/articles/perf-anr.html
Android applications normally run entirely on a single thread by
default the "UI thread" or "main thread"). This means anything your
application is doing in the UI thread that takes a long time to
complete can trigger the ANR dialog because your application is not
giving itself a chance to handle the input event or intent broadcasts.
Therefore, any method that runs in the UI thread should do as little
work as possible on that thread. In particular, activities should do
as little as possible to set up in key life-cycle methods such as
onCreate() and onResume(). Potentially long running operations such as
network or database operations, or computationally expensive
calculations such as resizing bitmaps should be done in a worker
thread (or in the case of databases operations, via an asynchronous
request).
The most effective way to create a worker thread for longer operations
is with the AsyncTask class.
Here is what I recommend though. Use the above mentioned, EventBus and create a BaseActivity which will automatically save the data for you onClose() by firing an event that runs Async. You then extend that base activity in all the places where you need autosave capabilities.
Here's what I mean with an example that uses EventBus.
public abstract class BaseActivity extends Activity{
#Override
protected void onResume(){
if(!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
super.onResume();
}
#Override
protected void onDestroy() {
if(EventBus.getDefault().isRegistered(this))
EventBus.getDefault().unregister(this);
super.onDestroy();
}
#Override
protected void onStop() {
super.onStop();
//We fire event and pass the current parent class that inherited this base.
EventBus.getDefault().post(new EventBusProcessMySaveData(this.getClass()));
}
}
//Your model class to use with EventBus
public final class EventBusProcessMySaveData{
private final Class className;
public EventBusProcessMySaveData(final Class className){
this.className = className;
}
public Class getClassName(){
return this.className;
}
}
public class MyMainActivity extends BaseActivity{
//Do you standard setup here onCreate() and such...
//Handle Event for Saving Operation, async.
//This will fire everytime theres an onClose() IN ANY activity that
//extends BaseActivity, but will only process if the class names match.
#Subscribe(threadMode = ThreadMode.ASYNC)
public void methodNameDoesNotReallyMatterHere(final EventBusProcessMySaveData model){
//We make sure this is the intended receiving end by comparing current class name
//with received class name.
if(model.getClassName().equals(this.getClass())){
//Do whatever you need to do that's CPUintensive here.
}
}
}
I am developing an Android App, which displays some images from an website in MainActivity. There are some other activities which are basically dealing with the offline contents like dealing with database and configuration.
Currently the App is designed in such a way like, when it navigates from MainActivity to any other activities, first it will destroy itself (calling finish()) and then navigate. Likewise if navigated to MainActivity from some other Activity, those activities will be destroyed before moving.
App works fine, initially. But if the user navigates between activities too frequently, then the image downloading task in the Main Page takes very long time.
For Example, if user navigates like
MainActivity --> Activity1 --> MainActivity
In the above case, there is no issue displaying the images in MainActivity initially. But in the next instance, it takes unusual time.
What I am planning to to implement a multi threading scenario, which will create a new thread every time the application trie to navigate to MainActivity and destroy the existing one.
Thread-0 : MainActivity --> Activity1 (to go Main) --> Kill Thread-0 and Create Thread-1
Thread-1 : MainActivity --> Activity1 --> Activity2 (to go to Main) --> Kill Thread-1 and create Thread-2
But I have no clue, how to implement the same. Any suggestion or reference link are most welcomed.
Try to use an AsyncTask like this:
public class MyTask extends AsyncTask<Void, Void, Void> {
private volatile boolean running = true;
#Override
protected void onCancelled() {
running = false;
}
#Override
protected Void doInBackground(Void... params) {
while (running) {
// download
}
return null;
}
}
Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
task = new MyTask();
task.execute();
}
#Override
public void onDestroy() {
super.onDestroy();
if (task != null) task.cancel(true);
}
But for me the easiest way to download and display images is using Picasso.
Its that simple:
Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)
Probably the best way to implement this kind of behavior is with using the AsyncTask. You can start it like this
new YourAsyncTask().execute();
Cancel it like this:
mTask.cancel(true);
And you can use it's doInBackground(), onProgressUpdate() and onPostExecute() to make it perform like you wish (every method is pretty much self explanatory by the name itself).
Did you implement the cache memory logic when loading images.So that if an image is downloaded it would not go for the download again instead it(one activity or the other) will look in the cache.
Create BaseActivity class which extends Activity/AppCompatActivity.
extend BaseActivity class from your MainActivity.
Do all download tasks in BaseActivity using AsyncTask
should do the trick. :)
If you are loading images frequently creating/destroying a Thread would not be a good approach considering the overhead of creating and destroying. AsyncTask is an OK approach but risky for memory leaks. My suggestion would be to handle image loading tasks in a service like an IntentService or create a regular Service with a background thread.
I m new in android, I'm not much aware about services.i have an activity class with a UI, i want to make this activity class runs in background, when i click the back button. how to make my activity runs in background like a service, plz help me..
You cannot really run an Activity on background! When an activity is not on foreground it gets to onStop and then the system could terminate it, to release resources, by onDestroy method! see Activity Lifecycle
In order to run on background you need to create a Service or IntentService
Checkout android javadoc about Services here and here or IntentService
and here is a third-party Android Service Tutorial
Edit: you may also need a communication between your service and your activity so you can get through that: Example: Communication between Activity and Service using Messaging
If you simply want your activity runs in back Try using
moveTaskToBack(true);
It seems like you want to run an activity in background when it quits. However, activity can't be run unless it's on foreground.
In order to achieve what you want, in onPause(), you should start a service to continue the work in activity. onPause() will be called when you click the back button. In onPause, just save the current state, and transfer the job to a service. The service will run in the background when your activity is not on foreground.
When you return to your activity later, do something in the onResume() to transfer the service 's job to your activity again.
You should read the developer guide on Threads: http://developer.android.com/guide/components/processes-and-threads.html
Specifically the function doInBackground()
Example from page:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
I want to use AsyncTask to call another application. I have a main app that does its own thing but when I launch it, it does an AsyncTask to call a "messages" application which checks to see if there are any unread messages and then displays a notification in the status bar.
However, when I called execute(), the messages application jumps to the front and I have to press the back button to get to my main application.
Code is as follows (my main application)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MessageUpdate update = new MessageUpdate(this);
System.out.println("Calling Update");
update.execute(null);
....
My AsyncTask:
public class MessageUpdate extends AsyncTask{
Context ctx;
public MessageUpdate(Context ctx){
this.ctx = ctx;
}
#Override
protected Object doInBackground(Object... params) {
Intent notificationIntent = new Intent();
notificationIntent.setClassName("com.test.messages", "com.test.messages.MessageCheck");
ctx.startActivity(notificationIntent);
return null;
}
}
Can anyone tell my why the MessagesCheck jumps to the front and how to stop it? Or if what I'm doing is even feasible?
As others have pointed out, a service is the way to go. However, if you use bindService() the service will only last as long as it's bound.
Just to clarify some of the issues:
Using startActivity to communicate with a background task is not what you want, as an Activity is a user interface component, which will come to the front when activated.
The suggestion is that you add a service to your "messages" application, not the main application.
You can then communicate with the "messages" application from the main application by binding to the service. If you do this (using bindService), the service will not run indefinitely.
The details of how to do this are here.
You could do all this without an AsyncTask, however it may help to avoid blocking the UI thread if the service takes significant time to do its job. Alternatively, your service could use a background thread of its own to check for messages and post the notification.
Have you considered make com.test.messages.MessageCheck a Service not an Activity, then calling startService(...)
You are starting an Activity in your ASyncTask, so your current Activity is brought to the back.
In order to prevent that, you'll have to use a different way to check if there is a new message. You could either do that verification in your ASyncTask and display the notification from it, or use a Service.