I am trying to update my UI from the GLThread with a handler. I have read that everything in "handleMessage" will be performed in the UI Thread but I still get this exception:
05-31 09:22:55.653: E/AndroidRuntime(26273): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Here is my handler:
public class VideoPlayerCallback implements Handler.Callback {
public static final int PLAY = 0;
public static final int STOP = 1;
public boolean handleMessage(Message msg) {
if(msg.what == VideoPlayerCallback.PLAY) {
ARVideoTemplate videoTemp = (ARVideoTemplate) msg.obj;
String uriPath = "android.resource://" + getPackageName() +"/raw/"+videoTemp.getFileName();
updateVideo(uriPath); // UI Actions
return true;
}
else if(msg.what == VideoPlayerCallback.STOP){
updateVideo(null); // UI Actions
return true;
}
return false;
}
}
Then something like this to put this handler to my GLRenderer:
Handler player = new Handler(new VideoPlayerCallback());
((ARGLSurfaceView) mGLSurfaceView).setVideoView(player);
And the call from GLRenderer:
Message msg = Message.obtain(mVideoPlayer);
msg.obj = video;
msg.what = VideoPlayerCallback.PLAY;
this.mVideoPlayer.dispatchMessage(msg);
What should I change to access the ui thread properly?
Thank you in advance!
I don't know about that callback-subclassing you are doing, but a handler should work fine, just two things to do:
You create the handler on the thread that it should post code to.
You use the handler.post()-method to post he source to the UI thread, like this:
handler.post(new Runnable() {
#Override
public void run() {
drawStuffToScreen();
}
});
I have found my fault. I have to call
this.mVideoPlayer.sendMessage(msg);
instead of dispatchMessage(msg). Then my handler runs on the UI thread.
Related
I am trying to blink the camera led at the different speed.
so to do this I am using seekbar to change the blinking speed.
When I first change the value of seekbar it starts blinking
private fun startFlashLightBlink(context: Context,blinkSpeed: Int) {
isBlinkFlashLight=true
flashLightBlinkThread = Thread{
Looper.prepare()
while (isBlinkFlashLight){
val blinkInterval:Long=blinkSpeed*100L
//getMainLooper() handler is associated "with the Looper for the current thread" ... which is currently the main(UI) thread
val handler = Handler()
var runnable:Runnable = Runnable{
toggleFlashLight()
}
handler.postDelayed(runnable,blinkInterval)
}
Looper.loop()
}
flashLightBlinkThread?.start()
}
But it freezes the main UI so now I am not able to change the value using seekbar And gets ANR message.
What should I do? I can't use the asynkTask.
Service is also not a good option. I think.
Try not using the separate Thread and Looper. Handler is enough for what you want to do. Cycle it like this:
private static final long POST_DELAY = 100;
private final Handler handler = new Handler();
private final Runnable cycleRunnable = new Runnable() {
public void run() {
if (isCycling) {
// make your cycle body here
handler.postDelayed(cycleRunnable, POST_DELAY);
}
}
};
private boolean isCycling = false;
public void startCycle() {
if (!isCycling) {
isCycling = true;
handler.postDelayed(cycleRunnable, POST_DELAY);
}
}
public void stopCycle() {
if (isCycling) {
isCycling = false;
handler.removeCallbacks(cycleRunnable);
}
}
Can anyone point me in the right direction here please ?
I have an activity which spawns two threads, a thread for handling messages, using a Looper
public static class MiddleThread extends Handler{
static public Handler handler;
public void run() {
Looper.prepare();
Log.d("MiddleThread", "Looper is prepared !");
handler = new Handler() {
public void handleMessage(Message msg)
{
Bundle bundle = msg.getData();
String exitString = bundle.getString("endmessage");
if(exitString.equals(("ExitOK")))
{
boolean searchFinished = true;
Looper looper = Looper.myLooper();
looper.quit();
} else
{
int fileCount = bundle.getInt("filecount");
String fileName = bundle.getString("filename");
Log.d("MiddleThread", "File Number " + fileCount + " is " + fileName);
}
}
};
Log.d("MiddleThread", "nandler should be initialised");
Looper.loop();
}
... then it spawns the main Worker Thread, which is passed a handler from the UI Thread, and the handler from the above thread.
public class BasicSearch {
public Handler handlerUi, handlerMiddleThread;
public Message messageUi, messageMiddleThread;
public int fileCount = 0;
public BasicSearch(Handler ui, Handler mt) {
handlerUi = ui;
handlerMiddleThread = mt;
}
public void listFiles()
{
File searchPath = Environment.getExternalStorageDirectory();
messageUi = handlerUi.obtainMessage();
messageMiddleThread = handlerMiddleThread.obtainMessage();
walk(searchPath);
Bundle b = new Bundle();
b.putString("endmessage", "ExitOK");
messageMiddleThread.setData(b);
handlerMiddleThread.dispatchMessage(messageMiddleThread);
}
private void walk(File path) {
File[] list = path.listFiles();
for(File f : list)
{
if(f.isDirectory())
{
walk(new File(f.getAbsolutePath()));
} else {
processFile(f);
}
}
}
private void processFile(File f) {
Bundle b = new Bundle();
fileCount++;
b.putString("filename", f.getName());
b.putInt("filecount", fileCount);
messageMiddleThread.setData(b);
Log.d("BasicSearch", "Data is set, to send to MiddleThread");
handlerMiddleThread.dispatchMessage(messageMiddleThread);
Log.d("BasicSearch", "Message sent");
}
}
Whatever happens, when it tries to dispatchMessage, handlerMiddleThread reverts to being null. I even have the following code in my activity, to try and ensure that it isn't null, but it still ends up being null when I get to send the message.
startMiddleThread();
while(true)
{
if(MiddleThread.handler != null)
break;
}
startSearchThread();
This is a test project, as I wanted to be able to get the Handler/Looper concept properly understood before continuing on with my project.
I have successfully managed to use a Handler in my UI Threads before, but my current project has too much processing going on in the UI, and I want to have a secondary thread handling the output from the searchThread, and just receive a message in UI thread when the thread is complete.
So I think I see what you're trying to do and let me suggest a slightly easier way:
To start your background thread and get a handler to it:
HandlerThread bgThread = new HandlerThread();
bgThread.start();
Handler bgHandler = new Handler(bgThread.getLooper());
Then you can send whatever messages you want to your bgHandler. Note that you need to call start on a HandlerThread before creating the bgThread (otherwise getLooper() will return null).
That being said I think I know whats wrong with your code as you posted it. First, MiddleThread extends Handler (which doesn't have a run() method!) not Thread. Second, the run() method on MiddleThread is never called, so Handler is never instantiated. Even if your just mistyped Handler in your code above and you're actually extending Thread, you still need to call start on MiddleThread in order for anything in run() to be executed. Really though, what you're doing is waaay more complicated that it needs to be, and you almost certainly want to just do what I mentioned above.
I have a activity (myActivity) and a thread (MyThread) , both with a handler which allow me to send message between the UI thread and myCustomThread.
Now i would like to call periodically (10sec) the ALIVE message of the MyThread thread from MyActivity. How can i achieve that ?
MyActivity :
public void onResume()
{
super.onResume();
this.thread = new MyThread(activityHandler);
this.threadHandler = this.thread.gethandler();
threadMessage = this.threadHandler.obtainMessage();
threadMessage.what = AUTH;
this.threadHandler.sendMessage(threadMessage);
}
MyThread :
#Override
public void run()
{
Looper.prepare();
this.threadHandler = initHandler();
this.message = this.activityHandler.obtainMessage();
this.message.what = CONNECTED;
activityHandler.sendMessage(this.message);
Looper.loop();
}
private Handler initHandler()
{
return new Handler() {
public void handleMessage(Message msg)
{
switch(msg.what)
{
case AUTH :
{
auth();
break;
}
case ALIVE :
{
sendAlive();
break;
}
}
}
};
}
Thanks for your help
The correct solution really depends on what you are trying to put together...
This is a walk through for performing an action on a timer as well as how to use a delayed post (the preferred way of executing on a schedule because it doesn't use a thread for the timer). It is a good write up and they include the why.
Hope this helps.
I finally find a solution with sendEmptyMessageDelayed(ALIVE,10000)
Long story short, i call once ALIVE from my UI thread and at the end of the sendAlive() method i'm sending a delayedMessage to the thread itself to re-call ALIVE after X milliseconds.
With this solution no need of a new Thread or timer.
I am developing on Android but the question might be just as valid on any other Java platform.
I have developed a multi-threaded app. Lets say I have a first class that needs to do a time-intensive task, thus this work is done in another Thread.
When it's done that same Thread will return the time-intensive task result to another (3rd) class.
This last class will do something and return it's result to the first-starting class.
I have noticed though that the first class will be waiting the whole time, maybe because this is some kind of loop ?
Also I'd like the Thread-class to stop itself, as in when it has passed it's result to the third class it should simply stop. The third class has to do it's work without being "encapsulated" in the second class (the Thread one).
Anyone knows how to accomplish this ?
right now the experience is that the first one seems to be waiting (hanging) till the second and the third one are done :(
If you want to use threads rather than an AsyncTask you could do something like this:
private static final int STEP_ONE_COMPLETE = 0;
private static final int STEP_TWO_COMPLETE = 1;
...
private doBackgroundUpdate1(){
Thread backgroundThread = new Thread() {
#Override
public void run() {
// do first step
// finished first step
Message msg = Message.obtain();
msg.what = STEP_ONE_COMPLETE;
handler.sendMessage(msg);
}
}
backgroundThread.start();
}
private doBackgroundUpdate2(){
Thread backgroundThread = new Thread() {
#Override
public void run() {
// do second step
// finished second step
Message msg = Message.obtain();
msg.what = STEP_TWO_COMPLETE;
handler.sendMessage(msg);
}
}
backgroundThread.start();
}
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case STEP_ONE_COMPLETE:
doBackgroundUpdate2();
break;
case STEP_TWO_COMPLETE:
// do final steps;
break;
}
}
}
You would kick it off by calling doBackgroundUpdate1(), when this is complete it sends a message to the handler which kicks off doBackgroundUpdate2() etc.
Tiger ,
TiGer wrote:
When it's done that same Thread will
return the time-intensive task result
to another (3rd) class
Since thread runs asynchronously so your non-thread class can't be synced with your thread
Though to perform some action on an Activity you need an AsyncTask not A Thread
TiGer wrote:
maybe because this is some kind of
loop ?
Tiger do read more about Threads and concurrency
So the only answer I have for you now is ASYNCTASK
EDIT:
Also I'd like the Thread-class to stop
itself
Read this post's how-do-you-kill-a-thread-in-java
In ordinary Java, you would do this:
class MyTask implements Runnable {
void run() {
for (int i = 0; i < Integer.MAX; i++) {
if (i = Integer.MAX -1) {
System.out.println("done");
}
}
}
}
class MyMain {
public static void main(String[] argv) {
for (int i = 0; i < 10; i++) {
Thread t = new Thread(new MyTask());
t.start();
}
System.out.println("bye");
}
}
... that kicks off 10 threads. Notice that if you accidentally invoke t.run() instead of t.start(), your runnable executes in the main thread. Probably you'll see 'bye' printed before 10 'done'. Notice that the threads 'stop' when the the run() method of the Runnable you gave to them finishes.
I hope that helps you get your head around what it is you've got to co-ordinate.
The tricky part with concurrency is getting threads to communicate with each other or share access to objects.
I believe Android provides some mechanism for this in the form of the Handler which is described in the developer guide under designing for responsiveness.
An excellent book on the subject of concurrency in Java is Java Concurency in Practice.
if you want use AsyncTask rather then thread in android
I have resolve it using ASyncTask and Handler in Android the aim is that one task is execute after compilation of one task hear is code that show First load animation on view after compilation of that process it will goes on another page
class gotoparent extends AsyncTask<String,String,String>
{
#Override
protected String doInBackground(String... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Animation animation= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.rotete);
lin2.startAnimation(animation);
}
});
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent i=new Intent(getApplicationContext(),ParentsCornor.class);
startActivity(i);
}
}, 1200);
}
}
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);
}
};