I have a time consuming task (iterating through files and sending it's content to server) that I want to execute in background thread, in specific interwal (that's why I want to use Handler).
From UI thread I have a call like this:
LogsManager lm;
lm = new LogsManager(this);
lm.processLogFiles();
And in LogsManager class I have following piece of code:
public void processLogFiles(){
Handler mHandler = new Handler();
mHandler.postDelayed(logsRunable, 1000);
}
private Runnable logsRunable = new Runnable() {
#Override
public void run() {
File f = new File(Environment.getExternalStorageDirectory()+Constants.LOG_DIR);
File[] logFiles = f.listFiles();
for (int i = 0; i < logFiles.length; i++) {
readLogs(logFiles[i]); // executes some other methods inside
}
}
};
As you can see it's just method with Handler that calls Runnable. And, unfortunately it also blocks my UI thread. Isn't Handler supposed to start a new thread for Runnable? I use handlers in other parts of my app also, and they works just fine. Am I'm doing something wrong?
As stated in the docs, Handler:
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it
So if you're creating mHandler in UI thread, then it will run the tasks in UI thread - hence the problem.
All the post* methods in Handler run code on Handler's original thread (in your case the GUI thread). If you want a background thread, you need to explicitly start one (see below) or use AsyncTask, if you need to update the GUI.
Thread t = new Thread(logsRunable);
t.start();
I think you should use AsyncTask class for this purpose.
Scheduled the execution for the task after a specific delay, in your case it is 1000.
I also think AsyncTask is a good solution for your case.
Related
In my app (as long as it is open) I want to sync my data with my server.
My strategy is the following :
//create the handler on which we will use postdelayed
Handler handler = new Handler();
//create the first runnable.
//Will this run on UI thread at this stage ? as it is being called from the handler ?
Runnable runnable1 = new Runnable()
{
public void run()
{
Thread t = new Thread(runnable2);
}
};
//create the second runnable.
//This is for sure being called from a thread, so it will not run on UI thread ? NO ?
Runnable runnable2 = new Runnable()
{
public void run()
{
//connect to internet
//make the check periodical
handler.postdelayed(runnable1, 1000);
}
};
//call the postdelayed.
handler.postdelayed(runnable1, 1000);
In case I want the handler to stop its runnable task once the application is closed. What shall I do incase I have several activities and I do not know where is the user when he/clicks the home button. Should I include a check in all onDestroys() ?
Yes you're second Runnable will be ran on a new thread not the UI thread.
When you do new Handler(); this creates a handle to the current thread, if this code was in onCreate that thread would be the UI thread.
Therefore when you do handler.post it will post onto the UI thread (runnable1) , but when you start runnable2 you are explicitly creating a new thread to run this on.
It might not be the right strategy to create a new thread every 1 second (postDelayed ..1000) perhaps keep a reference to another background thread and post it a message every second to do something new.
To stop your repeated runnables you need to call removeCallbacks(runnable1) in onPause of any Activity (that I assume called postDelayed in onCreate)
I'm lost here. I need to read the files in a directory and make buttons from them when an app starts. I have to use a while loop, and I have to update the UI. I've tried for quite a while to run a runnable and have only the code inside the loop run in the UI thread. I'm relatively new to android, but this seemed simple enough.
This code is what I have right now. It throws no errors or warnings, but it doesn't do anything. I know the button making code works because the "add button" button makes buttons correctly. I have no idea why it isn't working.
(This runs in OnCreate)
Runnable aRunnable = new Runnable() {
public void run() {
Looper.prepare();
File f = new File(Environment.getExternalStorageDirectory() + "/myapp/");
File[] filearray = f.listFiles();
int amount = filearray.length;
final String[] files = new String[amount];
int count = 0;
while (count != amount) {
files[count] = filearray[count].toString();
count += 1;
}
int times = files.length;
int counter = 0;
while (counter != times) {
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
// Button making code
}
});
}
Looper.loop();
}
};
Thread thread = new Thread(aRunnable);
thread.start();
One problem with your existing code is that everything in the run() method gets run on a background thread, not the main (sometimes called the UI) thread.
This is where you're creating your handler object:
Handler handler = new Handler();
This is not correct. You need to create (instantiate) the Handler on the main thread, if using the default constructor. From the Handler docs:
public Handler () Added in API level 1
Default constructor associates this handler with the Looper for the
current thread. If this thread does not have a looper, this handler
won't be able to receive messages so an exception is thrown.
So, a simple fix is simply to move that line of code earlier, into a place that you know is run on the main thread. For example, in Activity#onCreate():
public void onCreate(Bundle b) {
super.onCreate(b);
handler = new Handler();
}
where handler is changed to be a member variable:
private Handler handler;
Also, just remove your Looper calls.
See this article for more on Handler.
Other Options
Another option would be to avoid using Handler at all, and get famliar with the AsyncTask class. I personally think that's easier for new developers to use. The vogella.com link I showed also has good information on AsyncTask.
Yet one more option would be to avoid Handler and use the runOnUiThread() method in your Activity to add your buttons.
it seems to me that you're trying to have a list of buttons based on some array. It seems that is a job for a ListView and a custom array adapter. I believe you should google some examples on it (there're billions around the internet, it's a fairly basic android pattern).
and while you're in the learning process, don't forget to check how to use for() in Java, all those while loops are just so ugly.
I'm recently getting involved in some concurrent programming specially with Java and Android.
I have some questions regarding Handlers.
1 - It is known that we need to associate a Handler with a thread, and it will run on the thread it was invoked on. However, in some examples on SO, the user is doing
public class MainActivity extends Activity
{
private Handler handler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState)
{
handler.postDelayed(runnable, 1000);
}
private Runnable runnable = new Runnable()
{
public void run()
{
//Do whatever
handler.postDelayed(this, 30000);
}
};
In this example, I assume we are doing the Handler thing on the UI Thread, RIGHT ?
Can I do a network operation here in place of //DO Whatever ? I don't think so, because we are on the main thread.
Is doing this pointless ? As one may use AsyncTask to replace this task ?
How can I apply this same example but not on the UI thread, rather a seperate thread ?
Do thread or Runnables have something similar to post delayed ?
Is it common to use the handler just for its postdelayed feature and not the main task handlers are made for, ie, being the middle man between the thread and the UI/Activity ?
Handlers are useful only when you want update UI. As you may know we cannot update UI from non UI Thread. If you are going to do some network stuff in background thread, and then update UI, you have to use Handler class or AsyncTask or you can do like this:
(from non UI Thread)
SomeView.post(new Runnable() {
//updating UI
});
If whatever you are doing is "heavy" you should be doing it in a Thread. If you do not explicitly start it in its own thread, then it will run on the main (UI) thread which may be noticeable as jittery or slow to respond interface by your users.
Interestingly when you are using a thread it is often useful to also use a Handler as a means of communication between the work thread that you are starting and the main thread.
A typical Thread/Handler interaction might look something like this:
Handler h = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 0){
updateUI();
}else{
showErrorDialog();
}
}};
Thread t = new Thread() {
#Override
public void run(){
doSomeWork();
if(succeed){
//we can't update the UI from here so we'll signal our handler and it will do it for us.
h.sendEmptyMessage(0);
}else{
h.sendEmptyMessage(1);
}
} };
In general though, the take home is that you should use a Thread any time you are doing some work that could be long running or very intensive (i.e. anything network, file IO, heavy arithmatic, etc).
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);