I'm developing an Android network application. I want to have one worker thread that will handle all incoming data over a socket). The thread will be active all the time.
I can start the thread from one of my activities, but how to handle it after the activity is changed?
By handle, I mean how to interact with the thread (passing data from thread to current UI or sending data to the thread from the current UI).
I'm looking at AsyncTask but I'm not sure if it can be used with my situation
I think you want to look at one of two models.
The first is to use a Service which will "own" the socket connection. The second is to spin up a HandlerThread to "own" the connection. Which you choose is based on what the socket is doing.
If the socket connection contains data that you need to receive, typically stuff you'll cache locally, then a Service is more appropriate, because running in a Service means that your work will get done eventually. On the other hand if you are doing something like downloading an image that is only ever displayed in your UI, then using a raw HandlerThread might be the right choice. The reasoning here is that the moment your UI goes away your socket connection might as well be closed. Put another way, the choice is based on how ephemeral the use of the data is.
Now, if you're going to use a Service, please, please, use an IntentService which will handle the grotesque details of shutting down the Service at the appropriate time. It will also put your processing code on the correct Thread. A command sent to a Service by default runs on the main/UI thread of your application. An IntentService marshals the work to a background thread.
If you're going to use a HandlerThread, I would make a class that extends HandlerThread and then use the singleton pattern to handle accessing the same HandlerThread from any Activity.
One important question to ask yourself though is when your Service or HandlerThread shuts down. When is the work done and how is this signaled? Is it just when no more data arrives? When your apps UI goes into the background?
For this requirement I suggest that you create and use JAX-WS or JAX-RS.Here are a lot of examples which fully describe that. In that case you can use AsyncTask easily. Look at this answer, I suppose that this solution can meet your needs.
I would go with this:
Handler mHandler = new Handler();
Thread t = new Thread(new Runnable(
#Override
public void run () {
while (true /* or your breaking condition */) {
//Here you put your socket algorithm
mHandler.post(new Runnable() {
#Override
public void run () {
//Here you put every change you want to do on UI thread
}
}
//This is necessary to reduce process consumption
try {
Thread.sleep(30L);
} catch (Exception e) {
e.printStackTrace();
}
}
}));
t.start();
How to know on which UI
Each handler you create is attached to the class on which it was created.
As you can see here Android | Handler
For example, if you have a class that extends Activity and you create a Handler there, it'll work on that UI thread.
Related
So, I am working in android studio and trying to set a pause between two methods. In the first one, a gif is loaded and in the second one a pop-up message appears. I've tried to use Thread.sleep and the TimeUnit as bellow but both of them execute in a way that the time is waited before running everything else. In another words, my code down bellow waits 4 seconds and then runs gameGif() and gameFinish() simultaneously. Here is my piece of code:
gameGif();
{
try
{
TimeUnit.SECONDS.sleep(4);
}
catch(InterruptedException ex)
{}
}
gameFinish();
This is working for me
gameGif();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
gameFinish();
}
}, 4000);
What you are doing is setting the intention to update the UI. The actual UI updates are performed by the Android Looper separate to your code. In fact, by calling wait(), you're actually blocking the rendering thread from doing its update.
Using a Handler is the correct way to do it, as Matus posts. The Handler will organise the scheduling with the Looper and will still allow the Looper to run (i.e. is non-blocking). When the timeout elapses it will call the Runnable
The one thing you need to be careful with this approach, is to call the Handler on the UI loop (i.e. from one of the 'normal' Android methods). If you call it from your own Thread it won't interact with the Looper correctly.
I'm learning Android, and I have few problems understanding Threads-Handlers.
I saw examples where you declare a handler in working Thread that works with Looper of mainThread- it's clear to me.
Also I saw examples where you create a working Thread and declare your own Looper, like this:
public void run() {
Looper.prepare();
handler = new Handler();
Looper.loop();
}
I understand it creates a thread with with own Looper and a private message queue but what is the purpose of this and why use it?
Is it a message queue that can work on the application UI like mainThread can? is it a speed issue of working on UI faster then mainThread?
And one more thing...I saw a class HandlerThread, if I understand it right, It's the same as creating a new Thread and setting to it new Looper like I showed in the example above? If not I'm interested to know what is the difference and where to use it?
There could be plenty of reasons why to do that. For example, if processing a message takes a significant amount of time you may want to do it on another thread to prevent the UI thread from freezing. It wouldn't be able to directly manipulate the UI thread, but you could always do a runOnUiThread to pass messages back to the UI thread.
HandlerThread basically does exactly what's above. It encapsulates the weird calls you need to do to make a looper, but it makes you use some odd looking code to make the actual handler for that thread. Nothing wrong with using it, but it won't save you much effort.
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.
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();
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?