First time ,i invoke HandlerThread.start() to handle the background service. after all the stuffs completed,I wanna to end this Thread by calling HandlerThread.quit().
Then the second time,I start this Handler,and checked the HandlerThread.isAlive(),the isAlive() return false, but when i invoke HandlerThread again by HandlerThread.start().
But I got the IllegalThreadStateException,why?
How can i really stop the HandlerThread before I invoke handlerThread.start() again safely?
onCreate(){
...............
CurrentLocationPresenter =
new CurrentLocationPresenter(getApplicationContext(),mHandler);
}
public void onClick(View v) {
int id = v.getId();
switch (id){
case R.id.showplacebutton:
showPlaceInMapActivity();
break;
case R.id.showgpsbutton:
if (mCurrentLocationPresenter.isAlive()){
break;
}
mCurrentLocationPresenter.start();
break;
private Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
if (msg.what == CurrentLocationPresenter.WHATCODE){
mCurrentLatlng = (LatLng) msg.obj;
mTextView.setVisibility(View.VISIBLE);
if (mCurrentLatlng!=null) {
mTextView.setText(mCurrentLatlng.toString());
}
mCurrentLocationPresenter.getLooper().quit();
}
}
};
As stated, you can never call the start/run/execute method on a thread object more than once, as you will get the IllegalThreadStateException.
You can, however, use something such as an ExecutorService which will allow you to use the same Runnable multiple times.
Also, if you use a ThreadPoolExecutor, which is a descendant of ExecutorService, the memory and thread management is taken care of.
You can't call asyntask.execute() on same object more than one.
Always call MyasynTask asyntask=new MyasynTask();
asyntask.execute();
for more enter link description here
Related
Here are two Handler:
Handler handler1 = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_A:
break;
}
}
}
Handler handler2 = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_ONE:
doSomethingOne();
break;
case MESSAGE_TWO:
doSomethingTwo();
break;
}
}
}
I can guarantee that MESSAGE_A and MESSAGE_ONE(or MESSAGE_TWO) will be sent in pairs, but don't know which one is the first. Now I want call doSomethingOne() only if handle MESSAGE_A and MESSAGE_ONE, call doSomethingTwo() only if handle MESSAGE_A and MESSAGE_TWO.
For example, I receive MESSAGE_ONE, now I need to wait for MESSAGE_A, then call doSomethingOne().
Similarly, I receive MESSAGE_A, now I need to wait for MESSAGE_TWO(or MESSAGE_ONE), then call doSomethingTwo()(or doSomethingOne).
What should I do?
Make sure the MESSAGE_A, MESSAGE_ONE, and MESSAGE_TWO are DIFFERENT.
write a method outside your handler classes, e.g. handleMessageTogether(message m)
in the method handleMessage() of your handler class, call the handleMessageTogether() method instead.
You can call handler2 from handler1 (when case message A). For example instead of sending messages messageone and messagetwo, you can do that with boolean, then when messageA is finished, call handler2 and see which boolean is true.
I have the below handler :
public static final int WORK = 2;
public static final int UPDATE = 1;`
private Handler uiHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case UPDATE:
// Perform UI updates here
this.sendMessageDelayed(this.obtainMessage(WORK), 15000);
break;
case WORK:
{
new Thread(doWork).start();
}
break;
default:
super.handleMessage(msg);
}
}
};
This works super well.
However, the downside I am facing is the following.
Assume I run inside onResume() the following uiHandler.sendMessageDelayed(uiHandler.obtainMessage(WORK), 500);
Now the handler will run perfectly, lets say at time 9:00:10 , and will trigger to run the thread.
However, whenever I leave the activity, and go to another activity, then come back (rapidly) , another timer for the handler is starting.
Assume I came back from the other activity at 9:00:13
I will be having two threads running at both 9:00:15 and 9:00:28
And more if I go back and forth.
in my onPause I am calling uiHandler.removeMessages(WORK); but it is of no help.
I need to do some recursive tasks, say do something after every five seconds. How to achieve that? I will need to do the recursive task in the background, so I think I can go with a Started Service.
PS. What I am actually trying to do is: taking picture using camera after every five seconds, from a background service.
I found following code in the developer-guide. The method below resides in a custom class which extends Handler class:
#Override
public void handleMessage(Message msg) {
// Do Something
// HOW CAN i MAKE A RECURSIVE CALL (TO SOMEHOW CALL THIS FUNCTION) AFTER 5 SECONDS?
// Stop the service using the startId
stopSelf(msg.arg1);
}
}
Can I call something like Thread.sleep(5000) just before stopSelf()? (Not making sense to me...)
Or can I call something like this.sendMessageDelayed(msgOb, 5000); ?
Thanks.
Ok then this is one way to do with a handler:
int counter=0;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_TAKE_PIC:
if(counter==5) {
mHandler.removeMessages(MSG_UPDATE_CALLTIME);
break;
}
else {
//take pic here and then
counter++;
sendEmptyMessageDelayed(MSG_TAKE_PIC, 5000);
}
}
}
};
and where you want to start taking the pic just:
mHandler.sendEmptyMessageDelayed(MSG_TAKE_PIC, 5000);
I'm assuming you can modify the service that takes photos since you didn't say otherwise.
Why don't you just send a message for start to take photos and another for stop to take photos? The service will start taking photos every 5 seconds when you send the START message, until you send a STOP message.
Something like this:
class IncomingMessageHandler extends Hanlder implements Runnable {
private Boolean takePhotos = false;
public void handleMessage(Message msg) {
switch(msg.what) {
case START:
takePhotos = true;
new Thread(this).start();
break;
case STOP:
synchronized (takePhotos) {
takePhotos = false;
}
break;
}
}
public void run() {
while(takePhotos) {
takePhoto();
synchronized (takePhotos) {
takePhotos.wait(5000);
}
}
}
}
(this is the Service's hanlder implementation)
I have a activity (myActivity) and a thread (MyThread) , both with a handler which allow me to send message between the UI thread and myCustomThread.
Now i would like to call periodically (10sec) the ALIVE message of the MyThread thread from MyActivity. How can i achieve that ?
MyActivity :
public void onResume()
{
super.onResume();
this.thread = new MyThread(activityHandler);
this.threadHandler = this.thread.gethandler();
threadMessage = this.threadHandler.obtainMessage();
threadMessage.what = AUTH;
this.threadHandler.sendMessage(threadMessage);
}
MyThread :
#Override
public void run()
{
Looper.prepare();
this.threadHandler = initHandler();
this.message = this.activityHandler.obtainMessage();
this.message.what = CONNECTED;
activityHandler.sendMessage(this.message);
Looper.loop();
}
private Handler initHandler()
{
return new Handler() {
public void handleMessage(Message msg)
{
switch(msg.what)
{
case AUTH :
{
auth();
break;
}
case ALIVE :
{
sendAlive();
break;
}
}
}
};
}
Thanks for your help
The correct solution really depends on what you are trying to put together...
This is a walk through for performing an action on a timer as well as how to use a delayed post (the preferred way of executing on a schedule because it doesn't use a thread for the timer). It is a good write up and they include the why.
Hope this helps.
I finally find a solution with sendEmptyMessageDelayed(ALIVE,10000)
Long story short, i call once ALIVE from my UI thread and at the end of the sendAlive() method i'm sending a delayedMessage to the thread itself to re-call ALIVE after X milliseconds.
With this solution no need of a new Thread or timer.
Which is the better way to use a handler. Any advantages. All examples I have come across seem to give the inline version.
Using implements Handler.Callback in the class and implementing interface method.
or
Using inline code version
private Handler mHandler = new Handler(){ ....};
The common term or these inline class definitions is Anonymous Classes.
You can read more about the discussion on these in Java/Android: anonymous local classes vs named classes
Essentially the main differences are readbility, speed of coding, re-use and scope.
From a resource point of view the anonymous class creation may cause an overhead in the garbage collector as discussed in Avoid Creating Unnecessary Objects. I am not certain on the exact details of anonymous class creation, however, it is logical that implementing the interface on the class is more efficient.
#WilliamTMallard has provided an example of what NOT to do. In his example, a long and syntacticly complex handler should be implementented on the class rather than anonymous handler because it is harder to read and edit when defined inline.
http://developer.android.com/reference/android/os/Handler.html
package : android.os
public class
Handler
extends Object
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler:
to schedule messages and runnables to be executed as some point
in the future; and
to enqueue an action to be performed on a different thread than
your own.
Exmaple 1
use handler in app splash page.
if (!isFirstIn) {
mHandler.sendEmptyMessageDelayed(GO_HOME, SPLASH_DELAY_MILLIS);
} else {
mHandler.sendEmptyMessageDelayed(GO_GUIDE, SPLASH_DELAY_MILLIS);
}
/**************************************************************************************
*1. Handler
*/
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if(isAuto){
switch (msg.what) {
case GO_HOME:
goHome();
break;
case GO_GUIDE:
goGuide();
break;
}
}
super.handleMessage(msg);
}
};
private void goHome() {
Intent intent = new Intent(SplashActivity.this, MainAct.class);
SplashActivity.this.startActivity(intent);
SplashActivity.this.finish();
}
private void goGuide() {
Intent intent = new Intent(SplashActivity.this, GuideActivity.class);
SplashActivity.this.startActivity(intent);
SplashActivity.this.finish();
}
Example 2
use Handler request network in child thread if the request work may takes time.
new Thread(new Runnable(){
#Override
public void run() {
String versionPath = Parameters.getCheckVersionPath();
String result = RequestHelper.doGet(versionPath, null);
Message msg = new Message();
Bundle data = new Bundle();
data.putString("result",result);
msg.setData(data);
handler1.sendMessage(msg);
}
}).start();
handler1 = new Handler(){
#Override
public void handleMessage(Message msg) {
String result = msg.getData().getString("result");
JSONObject obj;
try {
obj = new JSONObject(result);
Map<String, String> versionInfo = Helper.getSoftwareVersion(obj);
if (versionInfo != null) {
newVersion = versionInfo.get("version");
updateUrl = versionInfo.get("url");
}
} catch (JSONException e) {
Log.w("net work error!", e);
}
}
};
Example 3
use Handler and Timer to update progress bar.
logobar = (ImageView) findViewById(R.id.splash_bar);//progress bar.
logobarClipe = (ClipDrawable) logobar.getBackground();
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
updateLogoBarHandler.sendEmptyMessage(0);
}}, 0, rate);
/**************************************************************************************
*2. Handler
*/
//update progress bar.
private Handler updateLogoBarHandler = new Handler() {
public void handleMessage(Message msg) {
if(logobarClipe.getLevel() < 10000){
//1.update image.
logobarClipe.setLevel(logobarClipe.getLevel() + rate*2);
//2.update text.
float percent = logobarClipe.getLevel() /100;
String percentTxtVerbose = String.valueOf(percent);
String percentTxt = percentTxtVerbose.substring(0, percentTxtVerbose.indexOf('.')) + "%";
bartxt.setText(percentTxt);
}else{
timer.cancel();
}
super.handleMessage(msg);
}
};
This really isn't an answer to the above question because I don't know what "the best way" is, and it likely depends on what you're doing. However, I'll explain what I'm doing and why.
I'm writing an app that serves as a remote controller. There are several activities that will interact with the controlled device, and different things need to happen based on the result of the command and the activity it came from. Two things I didn't like about handlers are A) that they end up being a sort of "kitchen sink" construct, implementing functionality from different sources, and B) that they separated an action (the send of the command in my case) from the processing of the result of that action. However, using an anonymous (right term? I'm such a noob.) handler as a parameter allows me to keep the logic together. Here's the pseudocode for my approach:
command = "Wake up!";
mDeviceInterface.write(command, new Handler() {
#Override
public void handleMessage(Message msg) {
switch(msg.what) {
case DeviceInterface.MESSAGE_TIMEOUT: // Process the timeout.
announce("Device not responding.");
break;
case DeviceInterface.MESSAGE_READ: // Process the response.
byte[] readBuf = (byte[]) msg.obj;
if (readBuf[0] == 0x05) {
// Success, update device status.
} else {
announce("Error!");
break;
}
}
}
});
(Always remember, this is probably worth exactly what you've paid for it. ;) )
There is a danger in using anonymous classes in Android. As described in this blog post -
In Java, non-static inner and anonymous classes hold an implicit
reference to their outer class.
And here comes an opportunity for a leak.
So, the short answer would be: implement the interface methods or use static inner classes (which don't hold an outer class reference).
For instance, a leak-safe Handler could look like this:
private static class ChangeTextHandler extends Handler {
private final WeakReference activity;
public ChangeTextHandler(MainActivity activity) {
this.activity = new WeakReference<>(activity);
}
#Override
public void handleMessage(Message msg) {
MainActivity activity = this.activity.get();
if (activity == null) {
Log.e(TAG, "Activity is null ChangeTextHandler.handleMessage()!");
return;
}
final String text = (String) msg.getData().get(BUNDLE_KEY);
if (!TextUtils.isEmpty(text)) {
switch (msg.what) {
// do something
}
}
}
}
I made a blog post around usage of Handlers, so might be worth checking as well :)