I am using Runnable to do some background task in my android application. The runnable after completing the background task will call a callback which is implemented by caller of the function which implemented runnable. Now i want to handover execution to main thread once the callback is called.
public void DoInBackground(Callback callback)
{
Thread thread = new Thread(new Runnable(){
//Execution that to be done in background
//calling callback once the result is obtained
});
thread.start()
}
public void callee(){
DoInBackground(new callback(){
#Override
public void onSuccess(int value){
//Do operations after completion of background task
}
});
}
I want the onSucess to run on the main thread rather than the new runnable created in DoInBackground function.
I know it can be done with async task. Is there any other way to do it.
you can use an Handler to post a runnable in the UI Thread queue, or if the context is the Activity ones you can use the runOnUiThread method. The snippet inside the runnable will be run on the UI Thread
put your callback function inside runOnUiThread function :
runOnUiThread(new Runnable() {
#Override
public void run() {
// callback function
}
});
Related
I have a service that executes a huge time-consuming computation. So I added an AsyncTask to run it in background. I have the call to requestLocationUpdates() which apparently can't be executed in an AsyncTask without a Looper. Most suggested against using a Looper, for I don't know why. So finally I had to add a Runnable in the AsyncTask.doInBackground() with a Handler. The Runnable seems to be blocking the activity that calls this service. This does not happen when my application is minimised. In fact, another activity of my app is also momentarily blocked whenever the execution happens.
1. What exactly is happening when I call a Runnable on a Handler?
2. How do I make it really run in background?
private void forkAsyncForTracking(){
new AsyncTask<Void, Void, Void>(){
private Location loc = null;
#Override
protected Void doInBackground(Void... params) {
handler.post(new Runnable(){
#Override
public void run() {
loc = getLocation();//this blocks the activity
}
});
return null;
}
#Override
protected void onPostExecute(Void lol){
doIt(loc);
}
}.execute();
}
By default, a service runs on 'main' thread. So if you declare a handler as a private to the service, it's considered as declared on main thread. Hence, the runnable declared inside the doInBackground will execute on main thread. Remember, it depends on the handler which is posting the runnable on where it'll be executed. You've to declare the handler inside the worker thread (which in this case will be doInBackground method), and also define a looper using Looper.prepare() (since, by default a worker thread doesn't have a looper, so there'd be no message queue which the handler can use). Try this out, and that method shouldn't cause any blocking thereafter.
protected Void doInBackground(Void... params) {
Handler handler = new Handler(); //Declared on worker thread.
Looper.prepare();
handler.post(new Runnable(){
#Override
public void run() {
loc = getLocation();//this blocks the activity
}
});
return null;
}
Another approach could be to use an IntentService, which runs on a worker thread by default, so you won't need any async task then. For IntentService, check this out : http://developer.android.com/reference/android/app/IntentService.html
I need to update ui from runnable. My logic goes like below.
I start the runnable from onCreate of the fragment lifecycle. And the runnable instance is responsible to request network. The problem is I don`t know how to update the fragment after runnable instance fetched the data from network.
code to start runnable in fragment in CustomFragment.java.
public void onCreate(Bundle savedInstanceState) {
Log.d(DEBUG_TAG, "onCreate");
super.onCreate(savedInstanceState);
accountMgr.requestAccountInfo();
}
code to start runnable in AccountManager.java
/**
* request Account info from server
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void requestAccountInfo() {
Account act = getCurrentAccount();
Thread t = new Thread(new RequestAccountInfoTask(act));
t.start();
}
/**
* automatically update Account info, like space usage, total space size, from background.
*/
class RequestAccountInfoTask implements Runnable {
private Account account;
public RequestAccountInfoTask(Account account) {
this.account = account;
}
#Override
public void run() {
doRequestAccountInfo(account);
}
}
runOnUiThread() requires Activity reference. There are alternatives. You don't need Activity reference to your Thread. You can always get UI handler with the main looper. Pass other arguments like your interface to update the fragment upon completion of your task.
class RequestAccountInfoTask implements Runnable {
private Account account;
private Handler mHandler;
public RequestAccountInfoTask(Account account) {
this.account = account;
mHandler = new Handler(Looper.getMainLooper());
}
#Override
public void run() {
doRequestAccountInfo(account);
//use the handler
}
}
Anything you run on the instantiated Handler will be on UI thread.
Of course, using runOnUiThread() is totally reasonable.
you can use runOnUIThread method of activity.
here's code may be help you:
class RequestAccountInfoTask implements Runnable {
private Account account;
public RequestAccountInfoTask(Account account) {
this.account = account;
}
#Override
public void run() {
doRequestAccountInfo(account);
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// you can update fragment UI at here
}
});
}
}
}
Please take a look at AsyncTask for updating the UI from a thread:
http://developer.android.com/reference/android/os/AsyncTask.html
Here are the highlights from the above link:
Class Overview AsyncTask enables proper and easy use of the UI thread.
This class allows to perform background operations and publish results
on the UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. AsyncTasks
should ideally be used for short operations (a few seconds at the
most.) If you need to keep threads running for long periods of time,
it is highly recommended you use the various APIs provided by the
java.util.concurrent package such as Executor, ThreadPoolExecutor and
FutureTask.
An asynchronous task is defined by a computation that runs on a
background thread and whose result is published on the UI thread. An
asynchronous task is defined by 3 generic types, called Params,
Progress and Result, and 4 steps, called onPreExecute, doInBackground,
onProgressUpdate and onPostExecute.
You Cannot Update UI from runnable. You Need Handler for Updating UI. See this for more info.
The UI only can be modified by the thread that create it. In tho most cases is by the UI thread. So you need yo update using runOnUiThread method. Good Luck
I recommend using an AsynTask or you can just try this
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getActivity(), "ON UI Thread", Toast.LENGTH_LONG).show();
}
});
I know it's a bit different answer. But I want you to see Android Annotations. Which are very easy to use . I use them only for background and Ui thread. Do every task in background thread by writing #Background over your method name. And do all the UI update in UI thread. I advice you to just check it once. http://androidannotations.org/
Thanks
And as far as your answer is concern . You can not update your UI from runnable. See the asyn task for updating your Ui.
You can use the event bus to do it - http://square.github.io/otto/
It is pretty simple. Just send event from your Thread when you need to update the UI like this:
...
//in the end of your heavy job:
bus.post(new YourEvent());
and in your Activity create method:
#Subscribe
public void onYourEvent(YourEvent event) {
//do what you want there
}
by the way, you can pass any data through event, it is your custom class! Please read manual how to set up this lib, register activity for bus. It is very useful and easy-to-use
You can create a Runnable that then posts to the main thread. From Google's developer pages on Processes and Threads
This implementation is thread-safe: the background operation is done
from a separate thread while the ImageView is always manipulated from
the UI thread.
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
// a potentially time consuming task
final Bitmap bitmap =
processBitMap("image.png");
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
in my mainActivity, which is the sole activity of my application, I am creating the below handler and running a runnable inside it.
I have some misunderstandings about handlers and where they run.
See the code
Handler handler;
#Override
protected void onCreate(Bundle bundle)
{
handler = new Handler();
handler.postDelayed(r , 5000);
}
Runnable r = new Runnable()
{
#Override
public void run() {
FetchServerAndUpdateStatus(); //network stuff in here
handler.postDelayed(r , 5000);
}
}
I assume this code will still run in UI thread and I won't be able to make any network calls in there no ?
If yes, what shall I do ? Create and use a seperate thread ?
If I created a new thread, How can I run the postdelayed method ? The thread does not have post delayed ?
Does not using handler/runnable and using TimerTask and Runnable instead a better approach ? Or, just like the above handler/runnable, that will also run on the UI thread, unless created inside a seperate one.
When you construct a Handler it is bound to the thread it is constructed on.
onCreate() is run on the UI thread so this handler will be bound to the Looper on the main thread, and thus will run on that thread.
If you want a handler you can use on another thread you can construct one.
See the looper docs: https://developer.android.com/reference/android/os/Looper.html
Which has this block:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
synchronized (this) {
this.notifyAll();
}
Looper.loop();
}
}
Add this class and then in your onCreate do the following:
mLooperThread = new LooperThread();
mLooperThread.start();
synchronized (mLooperThread) {
while (null == mLooperThread.mHandler) {
mLooperThread.wait();
}
}
mLooperThread.mHandler.postDelayed(r , 5000);
This will cause the runnable to be run NOT on the UI thread, which is probably what you wanted.
For tasks that need to interact with the UI an AsyncTask may be better since it includes a mechanism to run things that touch Views when the task is done on the UI thread, since anything that touches a View must be done on the UI thread.
The other mechanisms for executing on the UI thread are to post to the view itself:
https://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable)
or
[https://developer.android.com/reference/android/view/View.html#postDelayed(java.lang.Runnable, long)](https://developer.android.com/reference/android/view/View.html#postDelayed(java.lang.Runnable, long))
Or to ask the Activity to run it on the UI for you:
https://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
It depends on what you do with your handler, you didn't show, how you want to obtain m_handler. If you create it with new Handler(Looper.getMainLooper()), it will run on UI thread.
If you want to run code in background (network operations) you should use AsyncTask
I have a thread inside an invokeLater method in Blackberry like:
startButton.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field arg0, int arg1) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Thread thread = new Thread(){
public void run() {
uploadFile();
}
};
thread.start();
}
});
}
I have a thread because I want to run that function in the background and want to be able to do other stuff while its doing its job. What I am wondering is if this is a good approach. Do I really need the invokeLater in this case ?
Short answer: no.
Long answer:
InvokeLater puts the Runnable on the event queue so that, in time, when the event loop sees the Runnable it will execute it on the event thread. Since you are calling invokeLater in the fieldChanged method of a FieldChangeListener, you are calling it from the event thread. Unless what you want to do is delay the start of your thread to some unknown later time then no you don't need to use invokeLater.
Im running a Thread inside methode and i want to return a value once the thread finish, the problem that i tried to do join() but that blocks the UI thread.
How could i wait for the thread to finish and then return the value without blocking the UI thread ?
Boolean foo(){
myThread mt = new myThread();
mt.start();
return mt.isSentSuccessfully;
}
You can use Android's AsyncTask for that.
http://developer.android.com/reference/android/os/AsyncTask.html
When I use it, I put the background task in a class that extends AsyncTask and overwrite the onPreExecute() and onPostExecute(..) methods to show/hide the ProgressDialog. It works quite nicely.
If you really don't want to use the AsyncTask, then you might like to define a Handler
then in your background thread send a message to the main thread when the background job finishes with something like:
ActivityMainThreadClassName.this.myUpdateHandler.sendMessage(m);
where myUpdateHandler is the handler you created.
Did you try polling Thread.getState()?
Something like this:
android.os.Handler h = new Handler();
h.postDelayed(new Runnable() {
public void run () {
if (thread.getState() == Thread.State.TERMINATED) {
// your code here
return;
}
h.postDelayed(this, 1000);
}, 1000);
This sample should poll a thread state every second... (I didn't tested it)