Background HTTP tasks - java

I have a splash page on my app, and what I want to do is initiate a background task to start downloading things so they're ready when the user needs them.
So for example a picture of the week or something.
Splash screen starts (start background task)
Splash screen finishes (background task still working)
Home screen starts (temporary "loading" place holder)
User navigates to another activity
Download finishes
User returns to home screen which is updated with picture of the week
Now I'm aware of Async Tasks, but I've heard that async tasks get canceled on finish() and I've also heard they don't get canceled.
Is this sort of task, background loading best handled in a service?
Can anyone provide me with a tutorial on loading things like this in the background?
EDIT:
People are mentioning that UI work should be in the UI and non-UI in the non-UI. I've considered handlers, but does the listener work when the current activity isn't active?
Lets say I start a handler in the main and then switch pages. When I come back I'm pretty sure the main UI won't be updated because the listener didn't trigger while I was viewing another page.
I'm assuming I'll have to create a class just for storing variables or something. Once the service finishes, it'll set a "pic_of_week_loaded" to true and when the main reloads it checks this var. How would I go about this?

You can extend from Application class, create a thread (or AsyncTask) within it that will basically download stuff from Internet. After it finishes, you can notify the home screen activity to show up the contents into the place holder.

Another choice is to use the Android Asynchronous Http Client
I would just do it in the activity but make sure to check that the activity is still active when you go to display it (make sure onDestroy hasn't been called on it yet)..
Then I would cache the result so you don't have to load it again from the web (store the date in the filename so you know which date the picture is for so you know if the cache holds the latest one already).

Consider using IntentService to do your background job, so you will not be bond to activity life cycle.
EDIT: as per comments.
Using own application object is quite simply. Just create it like this:
final public class MyApplication extends Application {
....
}
then update your Manifest to look like this:
<application
android:name=".MyApplication"
...
and theoretically that's it. You can now add your own methods there, incl. async task operations. And you can get handle to your application object with just MyApplication app = (MyApplication)getApplicationContext(); and then do app.XXX(); Some important notes though: if you'd like to use AsyncTask in your ApplicationObject, be aware of Android Bug #20915. The workaround, as per discussin there is to do this in onCreate():
public void onCreate() {
// Workaround for android bug #20915
// http://code.google.com/p/android/issues/detail?id=20915
try {
Class.forName("android.os.AsyncTask");
} catch (Exception e) {
e.printStackTrace();
}
super.onCreate();
...

I will try to explain why (1) keeping global state in Application sublcass and (2) using AsyncTask are both bad approaches for this case.
(1) OS may kill your app process if the app is not in the foreground and there is no running services in the app at the moment. More details on this in this post: How to declare global variables in Android?
(2) AsyncTask is tricker than it looks at first. :) For instance, if ((OS < 1.6) || (OS >= 3.0)) all tasks are run on the same background worker thread by default. I mean ALL tasks for the current Java process are executed on the only background thread. So the next possibly started tasks in other activities will have to wait untill that first/init one is done. I think this is not what you'd like to get (if user navigates from Home activity to some other activity and that another activity will need to load some data using AsyncTask, then make sure your first/init task is done quickly, because it will block any subsequent tasks). Of course, if the amount of work for the first/init task is not big, then you can don't worry about this point. More details on how AsyncTask works in this post: Running multiple AsyncTasks at the same time -- not possible?
So my advice would be to use IntentService to download the image/date you need on startup. Once it downloads the data it sets the flag in SharedPreferences and sends a broadcast. By this time the Home activity may be in 3 states:
active (passed onResume(), but not yet onPause())
paused (passed onPause(), but not yet returned to onResume)
destroyed
While it is active it uses broadcast receiver to listen to the service. When it is paused it unregisters the broadcast receiver, but when it comes to active the first thing it does is to check the flag from SharedPreferences. If flag is still not set, then registers broadcast receiver.

1. Well AsyncTask was introduced into android to give what its know for Painless Threading, but i don't think thats the case here....
2. Now Its always good to keep the UI work on the UI thread, and Non-UI work on the Non-UI thread, and that became a rule from the arrival of HoneyComb version of Android.
3. Now as you want to download few things at background, which DOES NOT INCLUDE reflecting the output on the UI. Then i think you look into CountDownLatch Class in the java.util.concurrent.
4. Else you can always run a Non-UI thread at background.

I prefer to use Threads and Handlers for background tasks. The thread will execute some operation in the background, then when the task is complete, update the handler to update the UI. Here is some sample code below:
Handler handler = new Handler() { //Declare this as a global variable to the class
#Override
public void handleMessage(Message msg) {
//display each item in a single line
if(msg.obj.equals("update subcat")){
subcategoryAdapter.notifyDataSetChanged();
}else if (msg.obj.equals("update products")){
productsAdapter.notifyDataSetChanged();
}else if (msg.obj.equals("update cat")){
categoryAdapter.notifyDataSetChanged();
}
}
};
Here is your background task:
Thread background = new Thread(new Runnable() {
#Override
public void run() {
getSubCategories(((Categories)searchResults.get(pos)).ID);
handler.sendMessage(handler.obtainMessage(pos, "update subcat"));
}
});
background.start();

Related

Does starting an AsyncTask inside onResume method does cost more memory?

I use AsyncTask to update list from local database(sqlite) as the following :
#Override
public void onResume() {
super.onResume();
new MyAsynctask().execute();
}
I need a clear explanation what happen every time when new MyAsynctask execute and what happen to the previous MyAsynctask that was created earlier, and if this way cost more memory?
Your new async task does nothing.
AsyncTasks are executed after each other.
Only when your old async task ends the new one will start running.
AsyncTask is just a implementation of thread to manage Background task and UI updation . AsyncTask is designed to be a helper class around Thread and Handler in android .From the documentation .
AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
So for your question each time you call new MyAsynctask().execute(); A new thread will starts . And the older one will run also if not finished .
To cancel previous task you can use a global instance of task and check if status is RUNNING by getStatus()
if(asyncTask!=null && asyncTask.getStatus()== AsyncTask.Status.RUNNING){
asyncTask.cancel(true);
}
In your case you create new task in onResume() so each time your activity resumes new thread will created and this is not memory efficient solution to refresh screen.
For more detail on cancel task read Section Cancelling a task and cancel(boolean).
If you know how to manage it, then it's not a memory leak.
Your AsyncTask will be executed inside the onResume() function, thus it will run when:
Every-time the Activity is (re)created
You come back from another Activity
You change screen orientantion
You come back from another Application started by an Intent
You close and re-open your App
...
You might want to keep a class field for your AsyncTask and instantiate it in onCreate():
private MyAsyncTask asyncTask;
In case the Activtyis not destroyed (points: 1, 2 (maybe), 4(maybe), 5(maybe)), you can easily check the asyncTask status and cancel it if needed.
The problem is that the old AsyncTask might still be running when you start a new one if the Activity was re-created. And since the Activity instance is new, the asyncTask reference will point to a new Object as well: in that case you will have a savage Thread running in the background.
Unless Android's OS kills Activity's owned Thread (not sure about that), you might still get away by knowing and making sure that your AsyncTask will run for a few seconds at most, without performing any blocking IO operation. But this isn't really an engineered solution.
I'd say, the best and more standard-compliant solution is: by keeping the reference to the AsyncTask in your Activity, just call asyncTask.cancel() in your onPause() method. And you'll be sure that the AsyncTask's thread will be canceled before your Activity is either paused or destroyed.
Your code will then look like this:
private MyAsyncTask asyncTask;
protected void onCreate() {
this.asyncTask = new MyAsyncTask();
}
protected void onResume() {
this.asyncTask.execute();
}
protected void onPause() {
this.asyncTask.cancel();
}

Multiple UI Threads with one Working Thread

I have an app with following Diagram:
Start Screen -> Control Screen <-> Settings Screen <-> Message Screen
The Working-Thread that always have to run is a HTTP Request which gathers Information constantly so it is started at Start Screen.
The Start Screen jumps into Control Screen.
The Information gathered in Working-Thread have to be passed to the Message Screen and being displayed all, even if I change to Settings or Control Screen. Is this made by running 2 UI Threads simultaneausly to update the Message Screen in the background?
(I first throught about What's app where the Messages are constantly displayed)
There is usually only 1 UI thread. If you want to have longer running tasks (especially if you want them to keep going regardless of the UI) then you should use a service. The service can to it's work in the background even when the app is closed. This way you can have one class responsible for all of your network traffic and data collection and all of your activities can just bind to that.
First of all, there is only ONE UI Thread, and it is the main thread that runs the application, looking at this answer will help you understand Threads in android much better:
The UIThread is the main thread of execution for your application.
This is where most of your application code is run. All of your
application components (Activities, Services, ContentProviders,
BroadcastReceivers) are created in this thread, and any system calls
to those components are performed in this thread.
Now, you want to perform actions that require access to the UI Thread(e.g. displaying something on the screen, animating a view, ...etc), So, you have more than an option to achieve that:
1- use the method runOnUIThread():
This method uses the current Activity context or the application context in order to run the wrapped-in-it code inside the UI thread(main thread), only you have to use its signature anywhere in the running activity:
runOnUiThread(new Runnable() {
#Override
public void run() {
mInfo.setText(str);
}
});
or even you can run it from outside the current activity by holding the activity or the application context anywhere and hence you will be able to run it even from a normal class:
MainActivity.mContext.runOnUiThread(new Runnable() {
#Override
public void run() {
mInfo.setText(str);
}
});
2- use AsyncTask:
AsyncTask is the android way to do a background work in a background thread then apply the result to the main thread(UI Thread).
All you have to do is use the method doInBackground() provided by AsyncTask
in order to handle background work that has to be done in a worker thread(like handling HTTP requests in your case), and then use the method postExecute() in order to reflect the result to the UI Thread:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// handle your worker thread work here
return "result";
}
#Override
protected void onPostExecute(String result) {
// update your UI here
}
}
have a look here to put your hands better on it.

What does the common advice "start a thread in a service" even mean?

Service callbacks run on the main thread just like activities' (unless otherwise specified). I seem to stumble upon lots of advice here on SO that goes something like "start a thread in a service [to do work in the background]". That doesn't make sense to me. What does it matter if I start a thread from activity code compared to service code, just as long as there exists a started service component in the application process?
If the answer is what I think (that it doesn't matter) then it's a shame that people give the impression that a service object needs to be somehow related to the background thread.
The term "background" can be misleading when it comes to Services as it can have two meanings. Services are used, simplistically talking, to run tasks even if there is no Activity of your application running. To clarify, think of a music player; you want the music to still play even if the Activity is not running. That is the definition of background that doesn't have to do with Threads; you are running a portion of your application in the background because you do not have any visible component of your app on the screen (maybe some Notification but no full screen UI).
Now, lets say you want to download some data from the internet. As you might know, you cannot perform long running tasks in the UI Thread (as of API 11+ you will get a NetworkOnMainThreadException), so you need to use a background Thread. Let's say you do not want to use an AsyncTask to download the content because a Service is better suited for your needs. In this case, you will have to start the Service on a background Thread. That is the second meaning of background, which basically means creating a new Thread. Android provides a class that does exactly this; IntentService. It is a Service that runs on a background Thread and that it finishes itself when the given task is done.
It does not matter where you actually start a thread if the lifetime of that thread is reflected via your app process state: http://developer.android.com/guide/components/processes-and-threads.html#Lifecycle
Android does not care if there is a Thread running or not. Threads just run even when your app is considered an empty process "that doesn't hold any active application components." Don't abuse that, since users don't want that apps are secretly active although they look dead.
If you want (and you should) that Android does not kill you randomly although your threads are not done you have to make sure that you keep e.g. a Service in started state.
Creating a thread from within a Service (or just using IntentService) will primarily result in better, simpler & cleaner code. For example because a Service has a Context and you can't leak your Activity from there. You also get free callbacks from the system.
And leaks via threads are extremely easy.
new Thread(new Runnable() {
#Override
public void run() {
SystemClock.sleep(Long.MAX_VALUE);
}
}).start();
Will leak your activity if you just put it in e.g. onCreate because the anonymous inner Runnable keeps a reference to your Activity and will not release it until the thread stops running and is itself garbage collected.
In case you really know what you are doing, feel free to start threads in Activities and sync their lifecycle manually to some empty Service. I would not recommend it because it's unlikely to be less work to do that correctly.

How to know if this thread is a UI Thread

Is there any way on Android to know, if the thread running my code, is the UI Thread or not ? In swing there was SwingUtilities.isEventDispatchThread() to tell me if i am on the UI Thread, or not. Is there any function in the Android SDK that lets me know this ?
Answer borrowed from here: How to check if current thread is not main thread
Looper.myLooper() == Looper.getMainLooper()
Any Android app has only one UI thread, so you could somewhere in the Activity callback like onCreate() check and store its ID and later just compare that thread's ID to the stored one.
mMainThreadId = Thread.currentThread().getId();
Anyway, you can omit checking if you want to do something on the UI thread and have any reference to Activity by using
mActivity.runOnUiThread( new Runnable() {
#Override
public void run() {
...
}
});
which is guaranteed to run on current thread, if it's UI, or queued in UI thread.
Yes, there is a way.
Check the current thread object against main lopper's thread object. Main looper is always in the UI thread.
boolean isOnUiThread = Thread.currentThread() == Looper.getMainLooper().getThread();
Hum actually due to Android architecture, all Activities run in the main thread, ie the UI thread. So when you are coding an activity, everything that is in your Activity is in the UI thread.
That is why in Honeycomb an error have been added when you are making network calls in the main thread : it totally blocks the UI.
So by default you are in fact always working in the UI thread.
Another thing : unless you explicitely ask it to be in another thread, a Service will operate on the same thread as the activities of its application.
So, what to do ?
When you have to do heavy calculation in your activity; one solution is to use an AsyncTask (a class designed to allow you to easily use another thread). The code in onExecute() is run in another thread (but be cautious postExecute runs in your main thread). Another one is to manually start a new thread when AsyncTask is not really adapted.
If you create a service that does costly background tasks, make it run in another thread with the android:process=":my_process" attribute of the manifest. You will need to create an AIDL to communicate with this separated service, but it is not a complicated task.
Many objects, like for example the MediaPlayer, have Async variations of their methods. Try to to always use them.
Put a breakpoint where you want to check and, when it gets hit, check if you can interact with your UI (ie, if the UI is not frozen). If you can't interact with the UI then you are in the UI Thread, otherwise you are in a background thread.

Blocking Dialog from within JNI code

I'm writing an app that's basically a wrapper around a 250K JNI. The JNI (a game engine) has APIs like handle_penUp(int x, int y). Sometimes it needs to query the user from inside handle_penUp() (via callbacks into Java code), so the dialog I use to implement the query must block.
I understand that the main thread of execution can't block. So I've spawned a second thread that makes all the JNI calls that might result in callbacks that would need to block. Inside that second thread, when I need to put up a blocking dialog, I call startActivityForResult() and then acquire() on a semaphore. When onActivityResult() gets called on the main thread it calls release() on the same semaphore.
This works if my query is implemented as a new Activity, but not if I want to showDialog() within the existing Activity. Log messages tell me my thread needs a Looper. I'm adding one -- and will append info on whether it works -- but it feels as if I'm going down the wrong path here. What I need is a recipe for doing blocking dialogs (useful if only because every other platform has them and so ported code will often work that way.)
It sound very close to a problem I had with setting visible/invisible some view from the touch thread.
the problem is that you can't do some operations on the GUI form another thread (which is your case)
what you need to do is to use a Handle in your main thread
I declared it in the Activity
public static final Handler handlerVisibility = new Handler() {
public void handleMessage(Message msg) {
int visibility = msg.getData().getInt("visibility");
view.setVisibility(visibility);
}
};
I chose the option of public static so that I can access in anywhere (because I never have more that one call at a time and that I felt lazy to pass it along to the sub classes).
then what you want to do is send a message to this handler and since the Handler is in the same thread as the gui it works ^^
Message msg = MainActivity.handlerVisibility.obtainMessage();
Bundle b = new Bundle();
b.putInt("visibility", View.VISIBLE);
msg.setData(b);
MainActivity.handlerVisibility.sendMessage(msg);
That should solve your looper error and allow you to send GUI request from one thread to another
hope it helps
Jason
You definitely don't want two UI threads. There should be only one thread that communicates with the Android SDK as far as the control flow and display go (i.e. anything related to drawing, starting activities, displaying dialogs, etc).
Also, keep in mind that you don't want to actually keep your thread running - everything is based on events, so you want your code to respond to something, do something, and then exit as soon as possible.
When you say "block", what exactly do you mean? What needs to be blocked? If you simply need to stop responding to events, why not have a boolean that is set to true while the dialog is visible, and simply ignore all events while it is true?

Categories