Here's what I'm trying to do first. I'm trying to launch a MapView, which grabs the user's location and loads an overlay with data that changes based upon the user's location.
Code overview:
I have a MapView that grabs the current user's location on creation.
The locationOverlay I'm using calls out a Runnable on first fix:
locationOverlay.runOnFirstFix(centerAroundFix);
This Runnable, centerAroundFix, starts an aSyncTask. As soon as I call the 'new aSyncTask', this error is thrown:
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
The asynctask's job is to fetch data, create the overlay, and add the overlay. Creating and executing the asynctask works fine outside of the Runnable.
You have to create the Handler in the UIThread. For example as class member:
public class Activity extends Activity{
private Handler handler = new Handler();
}
Not sure how I didn't see this already...
Can't create handler inside thread which has not called Looper.prepare()
I'm pretty sure this is a duplicate question.
Edit: works. Here's my code. Wrapped the updateLocation() call with "mHandler.post":
private Handler mHandler = new Handler(Looper.getMainLooper());
private Runnable centerAroundFix = new Runnable() {
public void run() {
/* Jump to current location and set zoom accordingly */
map.getController().animateTo(locationOverlay.getMyLocation());
map.getController().setZoom(12);
/* This is a different thread. I need to call this from a thread that has a 'Looper' prepared. */
mHandler.post(new Runnable() {
public void run() {
updateLocation();
}
});
}
};
Related
I'm developing an android app, i have a separate class that extends Thread class, here i call a service and fetch data, now i need to know when this thread is completed and on completion its shows me a Toast.
Like
"Successful"
Is there any method like onPostExecute() in AsyncTask Thread?
Thanks
Display a toast is different that modify Views component because toast can be displayed from every thread while views need to be accessed only from the main thread.
So, if you need just to display a Thread just call Toast.makeToast(...).show() wherever you are.
Anyway, you can send messages from a backgrund thread to the main thread using the Handler class:
http://developer.android.com/reference/android/os/Handler.html
http://developer.android.com/guide/faq/commontasks.html#threading
i hope you are using thread like this..
.....
new Thread(new Runnable() {
public void run() {
YourMetod(); //you want to execute first
finishedHandler.sendEmptyMessage(0);//when first method is executed completly you need to call this
}
}).start();
....
create a handler in your class
like this
private Handler finishedHandler = new Handler() {
#Override public void handleMessage(Message msg) {
//create your toast here
}
};
try this hope help
Folks,
Here is a simplified code for my background thread:
public class MyThread extends Thread {
private Handler _handler;
public void run() {
Looper.prepare();
this._handler = new Handler();
Looper.loop();
}
public void DoSomething() {
if (!this.isAlive()) {
this.start();
}
this._handler.post(blah);
}
}
The problem I have is that the background thread may not have yet created the handler object when post() call is made. Essentially, I need a wait loop for the handler object to be initialized. What is generated accepted method of doing this under Android?
Thank you in advance for your help.
Regards,
Peter
You can set a flag after you initialize the Handler and wait for this flag before calling post.
An easy way to wait for a flag in a concurrent system is with a CountDownLatch. It would start at 1 and decrement after the Handler is initialized. Check out the details here:
http://download.oracle.com/javase/1,5,0/docs/api/java/util/concurrent/CountDownLatch.html
Well I've seen a wide variety of failures while trying to get this to work. I have a thread that is started via an Activity. The thread needs to create/display progress dialogs and dismiss them.
When I tried to directly display the ProgressDialog I got an error that my Looper wasn't prepared. I looked up with a Looper was an implemented it. However, I had to call Looper.loop for the progress dialog to show up. After it showed up the application froze on that point never to continue past the Looper.loop call.
I couldn't get it to work so looked for a whole new way using a HandlerThread and a Handler. I create a HandlerThread and start it. I get the looper from the thread and create a Handler with it. My ProgressDialog or Toasts won't show up at all.
Is there an easier way to go about doing this?
U can have an
private Handler stopProgressHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
setProgressBarIndeterminateVisibility(false);
}
};
private Handler startProgressHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
setProgressBarIndeterminateVisibility(true);
}
};
so that when u start the thread start the progressbar and after thread is completed u can stop the progressbar.
public void closeProgressbar(){
//bluetoothconnector.onDestroy();
stopProgressHandler.sendEmptyMessage(0);
}
public void openProgressbar(){
//bluetoothconnector.onDestroy();
startProgressHandler.sendEmptyMessage(0);
}
This will help to call the progressbar to start and stop.. This will be one of the solution..
Not sure about ProgressDialog, but all UI related stuff in Android, as far as I know, required to be updated in UI Thread. There's actually an easy helper class for implementing async task: http://developer.android.com/reference/android/os/AsyncTask.html
Alternatively, you can create a Handler (which would be on UI Thread) and create the dialog using that:
Handler uiHandler;
//Activity onCreate
onCreate(...){
uiHandler = new Handler();
}
// Somewhere in your other thread,
uiHandler.postRunnable(new Runnable(){
#Override
public void run(){
// Create or update dialog
...
}
});
The last answer is wrong....
it should be:
setProgressBarIndeterminateVisibility(Boolean.TRUE | Boolean.FALSE);
In my OnCreate method I have created a thread that listens to incoming message!
In OnCreate() {
//Some code
myThread = new Thread() {
#Override
public void run() {
receiveMyMessages();
}
};
myThread.start();
// Some code related to sending out by pressing button etc.
}
Then, receiveMyMessage() functions…
Public void receiveMyMessage()
{
//Receive the message and put it in String str;
str = receivedAllTheMessage();
// << here I want to be able to update this str to a textView. But, How?
}
I checked this article but it did not work for me, no luck!
Any updates to the UI in an Android application must happen in the UI thread. If you spawn a thread to do work in the background you must marshal the results back to the UI thread before you touch a View. You can use the Handler class to perform the marshaling:
public class TestActivity extends Activity {
// Handler gets created on the UI-thread
private Handler mHandler = new Handler();
// This gets executed in a non-UI thread:
public void receiveMyMessage() {
final String str = receivedAllTheMessage();
mHandler.post(new Runnable() {
#Override
public void run() {
// This gets executed on the UI thread so it can safely modify Views
mTextView.setText(str);
}
});
}
The AsyncTask class simplifies a lot of the details for you and is also something you could look into. For example, I believe it provides you with a thread pool to help mitigate some of the cost associated with spawning a new thread each time you want to do background work.
Android supports message-passing concurrency using handlers and sendMessage(msg). (It is also possible to use handlers for shared-memory concurrency.) One tip is to call thread.setDaemon(true) if you wish the thread to die when the app dies. The other tip is to have only one handler and use message.what and a switch statement in the message handler to route messages.
Code and Code
I have an app with a two threads - main and data loader. When data loader finishes it posts a Runnable object to the main thread (as described in the DevGuide), but it never gets delivered and run.
Here's the basic code:
class MyApp extends Application
{
public void onCreate()
{
LoaderThread t = new LoaderThread();
t.start();
}
private class LoaderThread extends Thread
{
public void run()
{
SystemClock.sleep(2000);
boolean res = m_handler.post(m_runnable);
if(res)
Log.d(TAG, "Posted Runnable");
}
}
private final Handler m_handler = new Handler();
private final Runnable m_runnable = new Runnable() {
public void run()
{
Log.d(TAG, "Hey, i'm runnable!");
}
}
}
Also it maybe important to note that I ran this code as a unit-test derived from an ApplicationTestCase:
class MyAppTest : public ApplicationTestCase
{
public MyAppTest()
{
super(MyApp.class);
}
public void testLoading()
{
createApplication();
// few asserts follow here...
}
}
So this fails. Runnable never gets run() called, although the log indicates that it has been posted successfully.
I also tried to send simple messages instead of posting runnable (m_handler.sendEmptyMessage(1) for example) - they never get delivered to handler's callback in the main thread.
What do I miss here?
Thanks in advance :)
A Handler requires a Looper in order to work. The Looper provides a message queue required by the Handler.
All instances of Activity have a Looper as one is used to process UI Events, but you can create your instance of Looper elsewhere.
Have a look in your Log output to see if Android is complaining about the absence of a Looper.
If it is, you might be able to fix by add the following to the top of your onCreate() method:
Looper.prepare();
m_handler = new Handler();
Looper.run();
And remove the initialisation of m_handler from later in your code.
Handler only works in an Activity AFAIK. You are attempting to use it in an Application.
An alternative to calling Looper.prepare() is to call new Handler(Looper.getMainLooper()). The problem with calling Looper.prepare() is that it will throw an exception when there is already a looper on your thread. Chances are you are writing code that has to run under different environments and this solution will handle more cases.
See:
AsyncTask and Looper.prepare() error