In my app i am using soap webservice call , based on the webservice call reply i have to display some messages .,
But after the reply i could not able to do this from the spawned child thread
So how to get back to the main thread and display this after the reply i got
Hope this is clear.. help me how to achieve my requirement
{
Thread t1 = new Thread() {
public void run() {
String threadName = Thread.currentThread().getName();
// There will be delay in this statement while fetching a data from webservice
String returnfromWebservice = webservice(xmlDetails, "generateid");
Log.v("returnfromWebservice",returnfromWebservice);
if( ! returnfromWebservice.equalsIgnoreCase("nil")){
gotid = returnfromWebservice;
gotReply=true;
// dothis();// I could able to do this because this method contains widgets
// I am gettin the error : Only the original thread that created a view hierarchy can touch its views.
//I understand this is because childthread has no controls on widget
/**Suggest me how to get back to main thread*/
}
}};
t1.start();
dothis();// so i am doin here after the completion of it
}
public void dothis{
if(gotReply){
idtext.setText(gotid);
genId.setEnabled(false);
Toast.makeText(WelcomeScorer.this, "Generated ", 500).show();
}
else{
Toast.makeText(WelcomeScorer.this, "Try Once More ", 500).show();
idtext.setText(gotid);
}
}
I am new to android, Is there any best approach in android api to handle this situation ??
You should use the following code to touch your ui elements from another thread
youractivityname.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
}
});
If your thread is in same activity you can use this. Otherwise you should use your activity class object to run the above method.From your code you should call dothis(); after thread has done its job. From your it will call the dothis method immediately after thread has started it wont care whether thread has done its job or not.
The various methods are documented in this article. Using runOnUiThread is probably the simplest.
Related
I've built an Android application which calls a TCP socket related thread from six different activities. It works just and fine, but as I try to add a simple dialog witch asks the user's id/pw just before starting the thread(the retrieved data will be required in the thread), I'm having trouble. There is an adapter class which is actually called to start the threads, but it is also not an "Activity" which can implement a dialog.
Is there any way to solve this in some smarter method? Adding six same codes to create the dialog, and implementing additional six same handlers for each dialog will solve this, but I don't think that's not the right thing to do.
I tried to make the dialog an Activity(with a dialog theme), but it can't return any datas since the class which starts this dialog like activity is not an Activity(thus, startActivityForResult is invalid).
How can I solve this? Reforming the whole source is impossible, since it's over more than 20,000 line. Please help!
Threads which are not the UI/main thread cannot control UI elements like a dialog box. But there is a way to make a part of your code run on the main thread, and there you then can do such things.
You want to post something to the main handler like this:
new Handler().post(new Runnable{
public void run(){
//Be sure to pass your Activity class, not the Thread
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
//... setup dialog and show
}
});
Well, I finally figured out this easy issue.
To call a Dialog.show() on a non-UI Thread, I needed a Handler object created with the Looper.getMainLooper(). Then, just as #peedee explained, implement the things to do(UI related works) on the run() block.
Receiving the datas retrieved by the dialog wasn't difficult either. Adding some getter methods on my Dialog class, and adding an OnDismissListener before showing the dialog was all I required. (the OnDismissListener will react when the dialog's dismiss() function is called.)
Here's the code I wrote. Hope it might give help.
Handler mHandler = new Handler(Looper.getMainLooper());
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Log.e("TESTRUNNABLE", "RUNNABLE LOADED");
cDialog = new TestDialog(mContext);
cDialog.setTitle("GROUP USER LOGIN");
cDialog.setOnDismissListener(new OnDismissListener(){
#Override
public void onDismiss(DialogInterface dialog) {
// TODO Auto-generated method stub
nameStr = cDialog.getNameStr();
pwStr = cDialog.getPwStr();
Toast.makeText(mContext, nameStr + ", " + pwStr, 3000).show();
Log.e("DISMISSLISTENER", nameStr + ", " + pwStr);
}
});
cDialog.show();
}
}, 0);
long time watcher, first time writer :P
I got this problem:
I can't seem to change anything that has to do with the layout of android from my playSoundThread.
In this example, I use EventListeners. I already tried the simple way. I passed the ScrollView through, so that the thread can change it. But when it's happening, the thread stops immediately. And even when I use EventListeners, the same Problem occurs.
Changing a variable and posting log information works fine, but not layout Objects.
The first thing is, that I want to scroll a HorizontalScrollView from out the Thread's run() method.
the second case is, that, if the thread comes to it's end, I wanna fire an "i'm finished"-Event and change the image and function of an ImageButton
Here's the run()-method of the thread
public void run() {
if(this.playbackPosition < rhythm.tracks.get(0).sounds.size()) {
for (Track t : rhythm.tracks) {
if (t.sounds.get(this.playbackPosition).equals("1")) {
this.sp.play(t.SoundID, 1, 1, 1, 0, 1);
}
}
this.playbackPosition++;
if ( this.playbackPosition >= (this.scrollIndex*(192/this.zoom)) ){
this.scrollIndex++;
//Here I wanna fire the "Scroll" event
for(ScrollListener sl : scrollListeners){
sl.update(scrollPositions[scrollIndex]);
}
}
}
//This is the point where the playback is finished and the event to change a button is fired
else {
tmpListener.update();
}
}
}
The declaration of the OnPlaybackFinishedListener can be found in the class Player, which is the parent of the PlaySoundThread:
public void addOnPlaybackFinishedListener(){
tmpListener = new OnPlaybackFinishedListener() {
#Override
public void update() {
scheduledExecutorService.shutdown();
//this is a seconds Listener, which was implemented to test, if the problem still occurs with a little listener chain
shutdownListener.update();
}
};
}
public void addShutdownListener(OnExecutorShutdown sl){
this.shutdownListener = sl;
}
And here's the part of the MainActivity which is the parent class of Player and adds the shutdown listener and the ScrollListener:
awesomePlayer.addScrollListener(new ScrollListener(){
public void update(int position){
Log.i("ScrollListener update()","Running ScrollTo( "+position+", "+VIEW_rhythmscroll.getScrollY()+")");
VIEW_rhythmscroll.scrollTo(position, VIEW_rhythmscroll.getScrollY());
}
});
awesomePlayer.addOnPlaybackFinishedListener();
awesomePlayer.addShutdownListener(new OnExecutorShutdown() {
#Override
public void update() {
// TODO Auto-generated method stub
//This method changes the Pause Button to a Play Button with a new OnClickListener and a new Picture
BUTTON_STOP.performClick();
}
});
Can anyone help? Is there another way to avoid this problem? I'm developing on Android 2.2
Is it even possible to access UI elements from a thread?
Thanks in advance :)
You can't modify UI elements from a seperate thread, UI elements have to be modified from the main, UI Thread. There are a lot of topics on this, but you can update the UI by using an AsyncTask's onPostExecute(), onPreExecute(), or onProgressUpdate() methods, the Activity class's runOnUiThread(Runnable action), or by sending a Message to a Handler.
This question already has an answer here:
Updating UI / runOnUiThread / final variables: How to write lean code that does UI updating when called from another Thread
(1 answer)
Closed 9 years ago.
Good day,
I want to update an image button in my UI from another thread. below is my code that i run in my mains threads onCreate() method.
new Thread(new Runnable() {
public void run() {
ImageButton btn = (ImageButton) findViewById(R.id.connected_icon);
if (netConnection.IsConnected()) {
// Change icon to green
btn.setImageResource(R.drawable.green_small);
} else {
// Change icon to red
btn.setImageResource(R.drawable.red_small);
}
try {
// Sleep for a second before re_checking.
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
No when i run this i gen an error int he LogCat saying i cannot update the UI from annother thread.
I remember reading soem where once that this is the case so that you don't get multiple threads updating the same UI object at once. But how can i achieve this. i am sure there is a work around?
Thanks
You cannot directly acces UI components from the thread.
The correct way to do this is by creating a handler
final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
}
};
And send messages to UIThread with
Message msg = new Message();
//TODO: add stuff to message
mHandler.sendMessage(msg);
inside your Thread.
This or use an AsyncTask instead and do the updates from inside of pre, post or progressUpdate methods
UI Elements should be updated only from the UI thread. Use an async task to do background word, and modify the UI in onPostExecute, which runs on the UI thread
I want to ask user for some details while doing some work in doInBackground() of AsyncTask (showing to user some dialog with choices in UI-thread), and after users choice continue the job in doInBackground() with chosen parameters from dialog.
What is a best mechanism of transfer this parameter to doInBackground()? How I should pause (and continue) thread doing doInBackground() (maybe object.wait() and notify()?)? Should I use a Handler for this purpose?
I would ask user for input before actually starting background task. If this is not possible there are couple possibilities:
You can use lock object and do usual wait()/notify() stuff on it. You still need to pass data from UI thread to your background thread though
I would use queue to pass data from UI thread to background thread and let it handle all the locking.
Something like this (kind of pseudo-code)
class BackgroundTask extends AsyncTask<BlockingQueue<String>, ...> {
void doInBackground(BlockingQueue<String> queue) {
...
String userInput = queue.take(); // will block if queue is empty
...
}
}
// Somewhere on UI thread:
BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
BackgroundTask task = new BackgroundTask<BlockingQueue<String>,....>();
task.execute(queue);
....
....
String userInput = edit.getText().toString(); // reading user input
queue.put(userInput); // sending it to background thread. If thread is blocked it will continue execution
You can use a Callable, submit it to an Executor, the Executor will return FutureTask then you will wait in a while loop until FutureTask.isDone == true;
This here is an example http://programmingexamples.wikidot.com/futuretask
I hope my answer will solve your problem surely.
//DO ALL BELOW CODE IN doInBackground() method of AsyncTask
String userInput="";
YouActivity.this.runOnUiThread(new Runnable() {
public void run() {
//SHOW YOUR DIALOG HERE
}
});
while("".equals(userInput))
{
YouActivity.this.runOnUiThread(new Runnable() {
public void run() {
userInput=editText.getText().toString();//fetching user input from edit Text
}
});
}
Thanks :)
Note : I know there are many questions related to this, but still I am not convince, so asking.
I am getting cant create handler inside thread that has not called looper.prepare when I try to show the dialog.
Here is my code...
//this method is called from a different method based on some condition which is inturn called on click a button
private void download() {
thread = new Thread() {
public void run() {
/**** Downloads each tour's Tour.plist file ****/
try {
// do many heavy operations here, like download,
//calling web webvice and starting another activity
This comes at the end
Intent toAudio = new Intent(TourDescription.this,Audio.class);
startActivity(toAudio);
} catch (Exception e) {
}
}
};
thread.start();
}
Now before this actity gets called I am trying to show a dialog. I am trying to place that just before calling Intent.
Can any body please tell me how to do this, as I am not understanding how to solve this
you cannot show a dialog from a child thread.
A dialog can only be showed from within the UI thread/main Thread.
try this from inside the child thread
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO show dialog....
}
});