I am new to android and was reading the demo applications on official android website. And I came across a method of Handler class named as postDelayed(Runnable r, long milliseconds).
Can anybody please explain what this method does ?
You can see the documentation.
But to understand the docs, you should first understand several concepts: Message, Message Queue, Handler and Looper, and their relationship.
The following illustrates how Looper works, it shows that the looper is a thread local object and its relationship with MessageQueue:
class Looper{
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
}
}
Several remarks:
Looper is a thread local object such that every thread has one looper. Every looper is associated with a message queue. The looper continously get messagese("tasks", "commands" or whatever you like to call them) from the queue, and dispatch the message to its target, which is a handler to handle that messag(e.g. by calling back a Runnable contained in the message). When there are no messages left in the queue, the thread blocks until there are new messages. To stop a Looper, you have to call quit() on it (which probably does not stop the loop immediately, but rather sets a private flag that is checked periodically from the loop, signaling the it to stop).
Android framework provides the Handler class to simplify things. When you create a Handler instance, it is (by default) bound to the Looper already attached to the current thread. (The Handler knows what Looper to attach to because we called prepare() earlier, which stored a reference to the Looper in a ThreadLocal.)
With a Handler, you can just call post() to "put a message into the thread's message queue" (so to speak). The Handler will take care of all the IdleHandler callback stuff and make sure your posted Runnable is executed. (It might also check if the time is right already, if you posted with a delay.)
The following code shows the typical ways we use them.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Handler is widely used in Android services. Android support inter application communication. Typically when we implement a service, which doesn't need to handle multithreading, we implements a Handler that receives a callback for each call from a client. Then create a Messenger object (reference to the Handler), which is a Binder object and return this object to clients when they bind this service. So the client can use this Messenger to send messages (into the thread-local queue, send to handler through Looper) to this service, and get them handled in the Handler. Code sample is attached:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
postDelayed (Runnable r, long delayMillis)
Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses. The runnable will be run on the thread to which this handler is attached.
Runnable Represents a command that can be executed.
delayMillis represents the time after which it should be executed.
Basically, it delays the execution of command(some code maybe) for particular period of time (delayMillis), so as to execute the command after specified time.
public class ApiHandler {
public static final String BASE_URL = "http://xxx.yyy/xx/";
private static final long HTTP_TIMEOUT = TimeUnit.SECONDS.toMillis(120);
private static Webservices apiService;
public static Webservices getApiService() {
if (apiService == null) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS);
okHttpClient.setWriteTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS);
okHttpClient.setReadTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS);
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(BASE_URL)
.setClient(new OkClient(okHttpClient))
.setConverter(new GsonConverter(new Gson()))
.build();
apiService = restAdapter.create(Webservices.class);
/*RestAdapter.Builder builder = new RestAdapter.Builder();
builder.setConverter(new StringConverter())
.setEndpoint(BASE_URL)
.setClient(new OkClient(new OkHttpClient()))
.setLogLevel(RestAdapter.LogLevel.NONE);
RestAdapter adapter = builder.build();
apiService = adapter.create(Webservices.class);*/
return apiService;
} else {
return apiService;
}
}
}
Related
I have an App (Client) that performs remote calls using AIDL to a second App (Server). Each call to through the Binder is executed in the Server app in a different thread (TID) as designed by AIDL solution.
Is it possible to make all calls executed in the Server app be executed in just one thread? We have control over all callers (Client apps) and they will perform call in a serial mode and we don't need Server app perform the calls in a multithread way.
So, if the Client App 1 performs a remote call to a method that takes 30 seconds and before it, a second Client App 2 performs a call to the same method (or even other method) we want this second call be executed in the same Thread of the first call.
Messenger is not an option for now.
=== Updated ====
Message is not an option (for now). Here more details: We have a service with 2 type of binders: a) TransacionManager (tm) and DAOImpl (dao).
We first do a call to tm.begin() in the client and even its processed synchronously, on the Service side its is executed in a thread from Thread Pool (android aidl code). This thread TID #1 performs the begin transaction command in SQLite database.
Then we do a call to dao.selectNextId() - synchronously - and in the Service it is executed in the TID #2. In the selectNextId() method we check if the database is inTransaction and it returns false.
To confirm that the threads was the problem, we put everything in a single call to another binder (allDAO). So when we call allDAO.do() it runs on the Service side in another thread TID #3 and performs begin transc and insert very well.
Not sure if the problem is SQLite that manage different threads as separated requests (how to deal with)... We just want the Service (using aidl) perform every call from any clients in a same single thread everytime.
I was working with Mario on this issue and using the #pskink's code snippet we solved the multithreading issue.
The issue was solved redirecting all aidl calls to the main thread. To do this, we used a Handler thats receives the MainLooper and a Runnable that extends CountDownLatch.
The code of our solution bellow:
// SyncHandler.class
public class SyncHandler {
private SyncRunnable mRunnable;
public SyncHandler() {
super();
}
public SyncHandler start(#NonNull SyncRunnable runnable) {
mRunnable = runnable;
final Looper looper = Looper.getMainLooper();
Handler handler = new Handler(looper);
handler.post(mRunnable);
try {
mRunnable.await();
} catch (InterruptedException e) {
Log.e(this, "Error when SyncHandler was awaiting.", e);
}
return this;
}
public static class ReturnValue<T> {
public T value;
}
}
// SyncRunnable.class
public final class SyncRunnable extends CountDownLatch implements Runnable {
private Runnable mRunnable;
public static SyncRunnable create(Runnable runnable) {
return new SyncRunnable(runnable);
}
private SyncRunnable(Runnable runnable) {
super(1);
mRunnable = runnable;
}
#Override
public void run() {
Log.d(this, "SyncRunnable.run() executed on thread: " + Thread.currentThread());
mRunnable.run();
countDown();
}
}
//And the database call:
// TransactionManager.class
public synchronized void begin(final int ownerHashCode, String ownerName) throws RemoteException {
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
#Override
public void run() {
if (mOwner == null) {
mOwner = ownerHashCode;
for (Database database : mDatabases) {
database.beginTransaction();
}
} else if (mOwner == ownerHashCode) {
throw new DbTransactionException("Error: TransactionOwner == owner");
}
}
}));
}
// DaoHelper.class
public synchronized long insert(Dao dao) {
final SyncHandler.ReturnValue<Long> value = new SyncHandler.ReturnValue<>();
SyncHandler handler = new SyncHandler().start(SyncRunnable.create(new Runnable() {
#Override
public void run() {
Log.d(DaoHelper.this, "db.inTransaction: " + mManagerDb.getDatabase().inTransaction());
value.value = mManagerDb.getDatabase().insert(mTable, null, mContentValues);
}
}));
return value.value;
}
handler is passed as this:
public void getUserYouTubeFeed() {
new Thread(new GetYouTubeUserVideosTask(responseHandler, username, i)).start();
}
Handler responseHandler = new Handler() {
public void handleMessage(Message msg) {
populateListWithVideos(msg);
}
};
and in the run method of thread
public class GetYouTubeUserVideosTask implements Runnable {
// A handler that will be notified when the task is finished
private final Handler replyTo;
public GetYouTubeUserVideosTask(Handler replyTo, String username, int frag) {
this.replyTo = replyTo;
}
#Override
public void run() {
// some code here
Library lib = new Library(username, videos);
// Pack the Library into the bundle to send back to the Activity
Bundle data = new Bundle();
data.putSerializable(LIBRARY, lib);
// Send the Bundle of data (our Library) back to the handler (our Activity)
//Message msg = Message.obtain();
Message msg = new Message();
msg.setData(data);
// getting null pointer exception here
replyTo.sendMessage(msg);
}
}
had this same issue. I wanted to create a client thread class in a separate .java file. In order to work, however, it would need to know the handler of the main UI thread. Unfortunately, since Java does not support pointers, passing the handler from the UI to your custom class and assigning it:
public GetYouTubeUserVideosTask(Handler replyTo, String username, int frag) {
this.replyTo = replyTo;
}
simply creates a copy of the handler and associates it with your thread (not a link to the main UI handler).
Messages sent to a thread (or main UI) require a Looper which dispatches the messages from the message queue, which then can be processed by the message handler. The main UI has a message loop associated with it by default, accessed through Looper.getMainLooper() and, therefore, you can simply create a handler in your main UI which threads can post to. Threads, however, don't have a message loop by default, so when you try to call:
replyTo.sendMessage(msg); // NullPointerException
you are actually trying to send the message to your new thread's handler which doesn't have a message loop associated with it causing the exception.
You can look at the Looper documentation to see how to create a message loop for you thread, but remember: the looper and the handler in your thread ONLY handle messages TO your thread (this is how you can communicate between threads).
I want to write a module that connects to a remote Service.
The module can be used by developers in their apps to connect to a specific (bluetooth-)hardware. It should then connect to a single remoteservice that can be updated seperately in the market.
Because the Remote Service is only allowed to have a single thread for all the apps using it at the same time (Only one connection over bluetooth), I have chosen the messenger approach over AIDL.
My problem is now that I wanted to provide a synchronous method in my public API but the service returns in an handler - and as far as I have understood, the handler will allways wait for the current task to finish... So is there any way to get the answer in a differen thread?
the code of the synchronous method as I would like it to be:
responseDataSync = new Sync<ResponseData>();
// Send message
Message msg = Message.obtain(null, Constants.DATA, 1, 0);
send(msg);
try {
ResponseData responseData = responseDataSync.get();
// with responseDataSync using a countdown latch to synchronize...
// but it never fires thanks to the handler.
//etc...
Thanks in advance. I hope my question was somewhat understandable... ;)
/EDIT:
I want some method that returns data from the server. like
public ResponseData returnResponse(Data dataToSend)
but I can't wait for the service's return because then I am stuck in the thread what blocks the handler from returning...
A Handler is associated with a single message queue. If you send a Message from any Thread it will get enqueued there.
The Thread that receives all the Messages will get the appropriate message off the queue and handle it - one by one.
Meaning for you that if you have a Handler and you run all Messages through you handler you don't need synchronization since everything is handled in a single thread.
Edit: to create a Handler that handles messages in a background thread:
HandlerThread ht = new HandlerThread("threadName");
ht.start();
Looper looper = ht.getLooper();
Handler.Callback callback = new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// handled messages are handled in background thread
return true;
}
};
Handler handler = new Handler(looper, callback);
handler.sendEmptyMessage(1337);
Edit2: wait on Messages might work like this
// available for all threads somehow
final Object waitOnMe = new Object();
HandlerThread ht = new HandlerThread("threadName");
ht.start();
Looper looper = ht.getLooper();
Handler.Callback callback = new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// handled messages are handled in background thread
// then notify about finished message.
synchronized (waitOnMe) {
waitOnMe.notifyAll();
}
return true;
}
};
Handler handler = new Handler(looper, callback);
// in a different Thread:
synchronized (waitOnMe) {
handler.sendEmptyMessage(1337);
try {
waitOnMe.wait();
} catch (InterruptedException e) {
// we should have gotten our answer now.
}
}
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 :)
So, I am getting an error that I am updating the UI from the wrong thread. This of course was not my intention. My case is quite long, but I will try to do it justice with code snippets. My end goal is to run an expensive task in a separate thread and post update that happen along the way and at the end to my listView.
public class test extends Activity {
private ArrayAdapter<String> _mOutArrayAdapter;
private ListView _mOutView;
private EditText _mCmdEditText;
private Button _mRunButton;
private Interpreter _interpreter;
// Need handler for callbacks to the UI thread
public final Handler _mHandler = new Handler() {
public void handleMessage(Message msg) {
_mOutArrayAdapter.add(msg.getData().getString("text"));
};
};
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_interpreter = new Interpreter(true);
_mOutView = (ListView)findViewById(R.id.out);
_mCmdEditText = (EditText)findViewById(R.id.edit_command);
_mRunButton = (Button)findViewById(R.id.button_run);
_mOutArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
_mOutView.setAdapter(_mOutArrayAdapter);
_mOutArrayAdapter.clear();
_interpreter.setOutputAdapter(_mOutArrayAdapter);
Thread t = new Thread() {
public void run() {
_mResults = _interpreter.executeExpression("startup;",_mHandler);
_mHandler.post(mUpdateResults);
}
};
t.start();
);
And then inside inpterpreter I do this:
public class Interpreter
{
private static Handler _mHandler;
public String executeExpression(String expression, Handler handler)
{
_mHandler = handler;
//Do a bunch of stuff that sometimes calls displayText from this class or from others
return answer;
}
public void displayText(String text)
{
Message msg = new Message();
Bundle bndl = new Bundle();
bndl.putString("text", text);
msg.setData(bndl);
_mHandler.dispatchMessage(msg);
}
}
The display of the final answer works. And the dispatchMessage is ending up triggering handleMessage, but it throw an error that I cannot modify the UI from outside of the UI thread which I know is illegal. So, what am I doing wrong?
Thanks!
_mHandler.dispatchMessage(msg);
dispatchMessage() causes the Handler to be run on the current thread.
http://developer.android.com/reference/android/os/Handler.html
dispatchMessage(Message msg)
Handle system messages here.
You should be using _mHandler.sendMessage(msg); It will put the message on the queue to be run by the Thread that declared the Handler.
sendMessage(Message msg)
Pushes a message onto the end of the message queue after all pending messages before the current time.
I would strongly suggest you stick with an AsyncTask (or one of the droid-fu versions if you need rotation/background support) unless you know what you're getting into. It'll help you cleanly keep track of what code is running in your UI thread and what code is in the background task, and save you a lot of confusion that dealing with Threads and Handlers yourself can cause.
Handler's post method requires a Runnable object in parameter, and scheduling execution of that runnable block. Instead you can use Handler.sendEmptyMessage() or Handler.sendMessage() to send a message to Handler. SO change your code to following:
Thread t = new Thread() {
public void run() {
_mResults = _interpreter.executeExpression("startup;",_mHandler);
Message msg= _mHandler.obtainMessage();
msg.obj= _mResults;
_mHandler.sendMessage(msg);
}
};