I am making Android 4.4 project. I've got NetworkOnMainThreadException.
Below is my process.
Service(sticky) -> Handler(per 5 minutes) -> Runnable -> HttpPost
Isn't Runnable a separate thread? Shoud I use AsyncTask in Runnable?
Runnable is a simple interface, that, as per the Java documentation, "should be implemented by any class whose instances are intended to be executed by a thread." (Emphasis mine.)
For instance, defining a Runnable as follows will simply execute it in the same thread as it's created:
new Runnable() {
#Override
public void run() {
Log.d("Runnable", "Hello, world!");
}
}.run();
Observe that all you're actually doing here is creating a class and executing its public method run(). There's no magic here that makes it run in a separate thread. Of course there isn't; Runnable is just an interface of three lines of code!
Compare this to implementing a Thread (which implements Runnable):
new Thread() {
#Override
public void run() {
Log.d("Runnable", "Hello, world!");
}
}.start();
The primary difference here is that Thread's start() method takes care of the logic for spawning a new thread and executing the Runnable's run() inside it.
Android's AsyncTask further facilitates thread execution and callbacks onto the main thread, but the concept is the same.
Runnable just per se is not a Thread. You can use a Runnable to be run inside a Thread, but these are different concepts. You can use an AsyncTask or just define a Thread and use .start() over it.
Related
I have some code that interacts with the Android Facebook SDK, Asynchronously. Unfortunately this means when it returns it is in a background thread.
Cocos-2dx prefers me to interact with it in the Main Thread, especially when doing things like telling the Director to switch scenes (As it involves Open GL)
Is there any way to get some code to run on the Main thread ?
As long as you have a Context, you can do something like this:
Handler mainHandler = new Handler(context.getMainLooper());
And to run code on UI thread:
mainHandler.post(new Runnable() {
#Override
public void run() {
// run code
}
});
As suggested by kaka:
You could also use the static Looper.getMainLooper() which
Returns the application's main looper, which lives in the main thread of the application.
runOnUiThread(new Runnable() {
#Override
public void run() {
//execute code on main thread
}
});
In C++:
Director::getInstance()->getScheduler()->performFunctionInCocosThread([]{
// execute code on main thread
});
You can run code in the main thread in this 2 ways: (with Java 8's lambdas)
If you have an activity instance:
activity.runOnUiThread(() -> {
// do your work on main thread
});
Otherwise use an Handler object and post a Runnable.
You can use the postDelayed version if you need some delay before executing the code.
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
// do your work on main thread
});
I'm wondering when should I use handler.post(runnable); and when should I use
new Thread(runnable).start();
It is mentioned in developers documentation for Handler:
Causes the Runnable r to be added to the message queue. The runnable
will be run on the thread to which this handler is attached.
Does this mean if I write in the onCreate() of Activity class:
Handler handler = new Handler();
handler.post(runnable);
then runnable will be called in a separate thread or in the Activity's thread?
You should use Handler.post() whenever you want to do operations on the UI thread.
So let's say you want to change a TextView's text in the callback. Because the callback is not running on the UI thread, you should use Handler.post().
In Android, as in many other UI frameworks, UI elements (widgets) can be only modified from UI thread.
Also note that the terms "UI thread" and "main thread" are often used interchangeably.
Edit: an example of the long-running task:
mHandler = new Handler();
new Thread(new Runnable() {
#Override
public void run () {
// Perform long-running task here
// (like audio buffering).
// You may want to update a progress
// bar every second, so use a handler:
mHandler.post(new Runnable() {
#Override
public void run () {
// make operation on the UI - for example
// on a progress bar.
}
});
}
}).start();
Of course, if the task you want to perform is really long and there is a risk that user might switch to some another app in the meantime, you should consider using a Service.
To answer you specific question:
Does this mean if in the onCreate of Activity class I write:
Handler handler = new Handler() hanlder.post(runnable); then, runnable
will be called in a separate thread or on the Activity's thread?
No it won't be. The Runnable will be called on the Main Thread itself.
Handler is simply used for posting a message to the thread to which it is attached (where its is created).
It does not create a thread on its own.
In your example, you created a Handler in the main Thread (that where Activity.OnCreate() is called) and hence any message posted on such a Handler will be run on the Main Thread only.
Example is jacked:
mHandler = new Handler();
new Thread(new Runnable(){
#Override
public void run () {
mHandler.post(new Runnable() {
#Override
public void run () {
mUiView.setX(x);
}
});
}
}).start();
Alternatively you can skip the handler and use the post method on the view directly:
new Thread(new Runnable(){
#Override
public void run () {
mUiView.post(new Runnable() {
#Override
public void run () {
mUiView.setX(x);
}
});
}
}).start();
This is a good post that outlines the difference: What exactly does the post method do?
use handler.post() when you want to post the code (usually from background thread) to the main thread. Yea, POST,just like you, post a letter to someone. With the help of handler the code will be executed ASAP i.e. almost immediately.
In order to execute some IO operations in my app I wrote a thread, there's nothing on its run method but it has several other methods, like void write(String filename, String data) and void create(String filename), all of which work like a charm. My question is, I used to think this thread was running on the background or something like this but since after removing the .run() statement on my main activity calling said methods still works, how can I have a thread running and waiting for a message from the activity without blocking the app? And second question, since the methods are still working does it mean they are being executed on the main UI thread when I call them from my main activity?
You should use the start() method, instead of the run().
With run() you are running the given Runnable in the calling thread.
With start() you are starting a new thread that handles this Runnable
For the methods to run on the said thread you will have to have to call your methods from the thread and not from any other thread.
class WorkerThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Then use WorkerThread.mHandler.postRunnable or sendMesssage for the work to be done on another thread.
In order to make a que for processing stuff when delivered, you need to make use of android's native stuff which is the best option available:
HandlerThread
Looper
Handler
Message
For examples, read this and this.
Coming from the basic Java world I know there's a way to spawn a thread by creating a new Runnable and passing it to a new Thread and calling start on it. Something like:
Runnable r = new Runnable() {
#Override
public void run(){
}
}
new Thread( r ).start()
Now joining the Android world it seems the Android eco system provides a few other ways to spawn a thread. One of them is Activity.runOnUiThread (for having stuff done on the UI) and Handler.post( runnable ).
What I am wondering about is what's the Android preferable way of spawning a new thread. I do see a lot cases such as:
Handler handler = new Handler()
handler.post( r )
Is there a good reason to use Handler to spawn a thread as opposed to creating a new Thread old way?
Thanks.
Yev
Check out the AysncTask framework. It seems like that's how Google wants you to handle threads...although you can use standard java threading.
The Handler in the way you've demonstrated doesn't actually spawn a new thread. Handlers are not threads, but are rather a means of IPC to let one thread tell another thread to run code. You still spawn off threads in the same old way, but the Handler helps those threads communicate better.
Say, for example, you have a Thread that you've spawned off in the background in the usual way:
Runnable r = new Runnable() {
#Override
public void run(){
}
}
new Thread( r ).start()
It runs in the background doing processing, but it needs to update the UI with it's progress, so it calls back to the Activity:
onProgress(int progress) {
// update UI
}
If you run that code as is, it will throw an exception, because only the UI thread is allowed to update the UI. Handlers can solve that problem like so:
public void onProgress(int results) {
mHandler.post(new UIUpdater(results));
}
private class UIUpdater implements Runnable {
UIUpdater(int results) {
//construct whatever...
}
#Override
public void run() {
//Update UI
}
}
Alternately, you can have Android manage Threads and Handlers for you through the AsyncTask framework
Handler is not supposed to spawn thread , but to post new task to UI thread. IMO the way to spawn thread is the java way, through runnable or extended thread directly. The android guys wrapped an Executor around the Async task and exposed some method that run directly in UI thread, and one to run your task in background.
I am currently developing an Android app where I need to perform a method inside a thread. I have the following code in order to create the thread and perform the
new Thread(new Runnable() {
#Override
public void run() {
new DownloadSync(getApplicationContext());
}
}).start();
When I try to run this code it displays the error message in the log cat:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.Prepare().
How can I fix this problem?
Use AsyncTask. Your situation is the reason for its existence. Also, read up on Painless Threading (which is mostly using AsyncTask).
The issue with your code is that something is trying to use a Handler internally in your new Thread, but nothing has told the Looper to prepare.
I had an earlier answer that was not very helpful - I've removed it and kept the relevant bit:
Make sure your DownLoadSync object only communicates with the main UI thread via a handler (if you want to avoid using an AsyncTask)
Declare a runnable and a handler as shown:
final Runnable updateMainUIThread = new Runnable() {
public void run() {
Toast.makeText(getBaseContext(), "Communicating with the main thread!!", Toast.LENGTH_LONG).show();
}
};
private final Handler handler = new Handler();`
And use it like this:
handler.post(updateMainUIThread);