I am having troubles with Threading ;)
I have done an script about my class as follow:
class Test{
TextToSpeech mTts = new TextToSpeech();
boolean volatile mVarGlobal = false;
class T1 extends Thread{
public void run(){
doSomething(){
mVarGlobal = false;
// network working...Take a while
mTts.speak(...) //Speech information received from Network
mVarGlobal = true;
}
}
T1 t = new T1();
t.start();
class CheckVarGlobal extends Thread{
public void run(){
if(!mVarGlobal) {
text2Speech.speak("something");
}
postAtTime(this, 3000);
}
}
CheckVarGlobal c = new CheckVarGlobal ();
c.start();
}
As you can see I have 2 Threads running, one which is getting network information and a second one which is cheking if the information from network has been received. The boolean variable mVarGlobal will be true, and then the Thread which is checking "CheckVarGlobal" will stop as the condition (!mVarGlobal) is false.
The problem is that once i get the information in the 1st Thread from network and speech the information, 2nd Thread still is running and speeching "something". I guess the 2nd Thread has not realize that CheckVarGlobal is true... I have typed the variable as volatile as it is used from 2 threads.
Any idea why is it happening, and how to solve it?
Thanks a lot,
Best.
David.
Dayerman... Here is some EXPERIMENTAL code with two handlers.
Edit. I have edited the code to comply with best practices, using a switch in a single handler:
private Handler myHandler= new Handler(){
#Override
public void handleMessage(Message msg){
switch(msg.what){
case 0:
if (!isDoneThinking){
editTextConfusedText.setText("Still Thinking "+new Integer(thinkSeconds).toString());
thinkSeconds++;
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0),1000);
}
else {
thinkSeconds= 0; // reset timer
}
break;
case 1:
isDoneThinking= true;
onThreadedMessage(msg);
break;
default:
super.handleMessage(msg);
break;
}
}
};
public void onThreadMessage(Message msg){
Bundle b= msg.getData();
String encryptedText="";
if (b != null){
encryptedText= b.getString("encryptedText");
}
editTextConfusedText.setText(encryptedText);
Log.d(TAG,encryptedText);
}
Usage:
buttonConfuseText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
final String inString= editTextPlainText.getText().toString();
isDoneThinking= false;
myHandler.sendEmptyMessage(0); // <=== START TIMER
Thread thread= new Thread( new Runnable() { // <== START THREADED RUNNABLE
public void run() {
String outString= encrypt(password,inString);
Message msg= myHandler.obtainMessage(1);
Bundle b= new Bundle();
b.putString("encryptedText",outString);
msg.setData(b);
myHandler.sendMessage(msg);
Log.d(TAG,outString);
}
});
thread.setDaemon(true);
thread.start();
}
};
Your are checking the variable in if condition rather than while condition.That means whenever it comes to thread 2 that time only it is checking.Better to use while condition in thread2.
Related
Start a thread in a service and try to update the UI in the thread by using handler. Can I just define a handler in the child thread using getMainLooper?
MainActivity.java:
public class MainActivity extends Activity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
btn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
it=new Intent(getApplicationContext(), Myservice.class);
startService(it);
}
});
}
Handler mhandler= new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case 1:
edt.setText("Service");
break;
}
}
};
}
Myservice.java:
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
Handler handler=new Handler(getMainLooper());
Message msg = Message.obtain(handler, 1);
handler.sendMessage(msg);
}
});
thread.start();
return super.onStartCommand(intent, flags, startId);
}
The Handler handler=new Handler(getMainLooper()); in the Service code is probably a different handler instance than the Activity handler( Handler mhandler= new Handler()). How about passing the handler from the Activity to the service.See my new Answer.
for e.g. Suppose there's a class called MYService :
public Myservice extends Service {
private Handler acitivityHandler;
public MyService(Handler handler) {
this.activityHandler = handler;
}
}
And from your activity when invoking the service pass-in the activity's handler instance
instead of relying on the main looper.
Handler mhandler= new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case 1:
edt.setText("Service");
break;
}
}
};
MyService myService = new MyService(mhandler);
That should work ideally.
Instead of accessing the UI elements from a (non-UI/main thread) access them from the Handler defined in your main activity.
From the (non-UI/main thread) just keep posting events to the handler to make UI updates.
//Inside the Thread's run method
public void run() {
if(uiNeedsToBeUpdated) {
handler.sendMessage(updateData);
}
}
In your MainActivity code (assuming you've a handler defined as a class member in your main activity), in the handler's handleMessage(), update the UI based on the progress made in the background task.
public void handleMessage (Message msg) {
switch(msg.getData().getInt("update")) {
//assuming you've bundled up int from the sending end
case 0 : { // background processing started, update UI
editText.setText("started");
break;
}
case 1 : { // background processing in progress, update UI
editText.setText("In progress");
break;
}
case 2: { //background processing finished , update UI
editText.setText("Done");
break;
}
}
}
Also you can use an Asyntask instead of a handler (http://examples.javacodegeeks.com/android/core/os/asynctask/android-asynctask-example/). Using an asynctask is easier as compared to a handler as it makes the programmer's life a little bit easier comparatively. Hope this info helps.
Can some please suggest an alternative to using two different handlers in the one activity, or let me know that this method is OK?
Details:
I'm in the process of developing some code for use with Microchips ADK Android starter kit. Everything is running smoothly, however, I have an issue where there are two different handlers running in the code, it works but I have noticed that it is not recommended.
The first handler I use to create a time delay, and use the post command to launch the result. The second handler is used in Microchip's sample code that they supplied to communicate with their USB accessory framework files. I prefer to only tinker with the Microchip code rather than rewriting it.
Similar code:
public class MainActivity extends Activity
{ ...
final Handler mHandler = new Handler(); // handler for startTimeDelay
...
protected void onCreate(Bundle savedInstanceState)
{ super.onCreate(savedInstanceState);
...
Button btnSetTimeDelay = (Button) findViewById(R.id.btnChangeTimeDelay);
btnSetTimeDelay.setOnClickListener
( new View.OnClickListener()
{ public void onClick(View v)
{
setBackgroundColorLinearLayout(color.holo_red_dark); //red background
displayLockIsOpen(false); // display closed lock message
startTimeDelay(); // wait to open the lock
}
}
);
} // onCreate
...
final Runnable mUpdateResults = new Runnable()
{ public void run()
{ setBackgroundColorLinearLayout(color.holo_green_dark); //green background
displayLockIsOpen(true); // display open lock message
}
};
protected void startTimeDelay()
{ Thread t = new Thread()
{ #override
public void run()
{ SystemClock.sleep(global_delay);
mHandler.post(mUpdateResults); // run mUpdateResults code
};
};
t.start();
} // startTimeDelay
// USB accessory handler from Microchip, for ADK
private Handler handler = new Handler()
{ #override
public void handleMessage(Message msg)
{
...
switch(msg.what)
{ case USBAccessoryWhat:
...lots of code here from Microchip
} // switch msg.what
} // handleMessage
}; // Handler
} // MainActivity
You can create a single Handler itself both for startTimeDelay and USB accessory.
From the code of android.
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Its says when you have a callback(Runnable) it will call handleCallback which will call your Runnable.run Method, else handleMessage will be called.
So you can have a single handler.
Thanks Vivek for your answer. I've also found that I can remove the line:
final Handler mHandler = new Handler(); // handler for startTimeDelay
and rename
mHandler.post(mUpdateResults); // run mUpdateResults code
to
handler.post(mUpdateResults); // run mUpdateResults code
The fact that Microchip's code overrides handleMessage has no effect on the .post method and it works normally. Giving me the below code.
public class MainActivity extends Activity
{ ...
// final Handler mHandler = new Handler(); // handler for startTimeDelay, not needed
...
protected void onCreate(Bundle savedInstanceState)
{ super.onCreate(savedInstanceState);
...
Button btnSetTimeDelay = (Button) findViewById(R.id.btnChangeTimeDelay);
btnSetTimeDelay.setOnClickListener
( new View.OnClickListener()
{ public void onClick(View v)
{
setBackgroundColorLinearLayout(color.holo_red_dark); //red background
displayLockIsOpen(false); // display closed lock message
startTimeDelay(); // wait to close the lock
}
}
);
} // onCreate
...
final Runnable mUpdateResults = new Runnable()
{ public void run()
{ setBackgroundColorLinearLayout(color.holo_green_dark); //green background
displayLockIsOpen(true); // display open lock message
}
};
protected void startTimeDelay()
{ Thread t = new Thread()
{ #override
public void run()
{ SystemClock.sleep(global_delay);
handler.post(mUpdateResults); // run mUpdateResults code
// changed from mHandler to handler, defined below
};
};
t.start();
} // startTimeDelay
// USB accessory handler from Microchip, for ADK
private Handler handler = new Handler()
{ #override
public void handleMessage(Message msg)
{
...
switch(msg.what)
{ case USBAccessoryWhat:
...lots of code here from Microchip
} // switch msg.what
} // handleMessage
}; // Handler
} // MainActivity
For me this was simple as I didn't need to rewrite any code, but I'm not sure whether its better practise or not. Your code would atleast direct the code reader to one location for the handler whereas in my version the running of mUpdateResults is not explicitly visible in the handler routine.
I have been reading up about threads in my java book and I wanted to try making updates with two consecutive threads at the same time.
OF course though threads can't update the UI. I have used handlers a little bit but only by passing messengers from one class to another to capture location from a service to an activity.
But this must be simpler than that.
I assume I should use AsyncTask but i want to count 1-10 in each field and I don't want to keep dipping in and out of the asynctask class.
Any pointers appreciated
Stephen
UPDATE
So I did a little more experimenting. I wrote a handler method to handle any messages sent to it. It checks which field it should be updating and then performs a setText on said field. Here is the code
Handler myHandler = new Handler(){
public void handleMessage(Message msg){
msg = Message.obtain();
Bundle bundle = msg.getData();
String fieldName = bundle.getString("fieldName");
int count = bundle.getInt("count");
if(fieldName=="text1"){
text1.setText(count);
}else{
text2.setText(count);
}
}
};
I then have some code in the onCreate of my activity which launches two threads and each thread passes a messages with my int count to the handler. It also passes in a TextView name so my handler knows which textview it should be updating. Here is the code...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text1 = (TextView)findViewById(R.id.text1);
text2 = (TextView)findViewById(R.id.text2);
new Thread(){
public void run(){
for(int i=1;i<10;i++){
message = Message.obtain(myHandler);
Bundle bundle = new Bundle();
bundle.putCharSequence("fieldName", "text1");
message.setData(bundle);
myHandler.sendMessageDelayed(message, 1000);
}
}
}.start();
new Thread(){
public void run(){
for(int i=1;i<10;i++){
message = Message.obtain(myHandler);
Bundle bundle = new Bundle();
bundle.putCharSequence("fieldName", "text2");
message.setData(bundle);
myHandler.sendMessageDelayed(message, 1000);
}
}
}.start();
}
But I am getting an error on the setText
05-17 17:13:00.013: ERROR/AndroidRuntime(966): android.content.res.Resources$NotFoundException: String resource ID #0x0
Any ideas?
Here's what you can do. You are on the right track about using AsyncTask, so extend the class and put your counting in the progress update function. You should have something like this:
private class BackgroundTask extends AsyncTask<Void, Void, Void> {
int i;
protected void onPreExecute() {
i = 0;
}
#Override
protected Void doInBackground(Void... arg0) {
i++;
publishProgress(i);
}
protected void onProgressUpdate(Integer... progress) {
TextView tv1 = (TextView) Main.this.findViewById(R.id.textView1)
TextView tv2 = (TextView) Main.this.findViewById(R.id.textView2)
tv1.setText(i);
tv2.setText(i);
}
protected void onPostExecute(Void result) {
i = null;
}
}
where Main is your activity and textView1 and textView2 are your text views that you are going to update.
If you really want to run two additional threads, that can be done with handlers. Simply create ONE handler for your activity and switch on what. Then launch two threads and when each thread completes send a message to the handler using the appropriate what value. Then update the appropriate text view in the handler as you are back in the UI thread in the handler:
private Handler myHandler= new Handler(){
#Override
public void handleMessage(Message msg){
switch(msg.what){
case 0:
this.removeMessages(0);
Toast.makeText(Main.this,"Message0", Toast.LENGTH_SHORT).show();
break;
case 1:
this.removeMessages(1);
Toast.makeText(Main.this,"Message1", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
break;
}
}
};
Simply replace the toast with your UI update code. You can launch a thread as in:
// DISPLAY ON CLICK HANDLER
threadButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Thread thread= new Thread( new Runnable() {
public void run() {
try { // DO NOT TOUCH THE UI HERE
Thread.sleep(1000); // mimic time consuming task
}
catch(Exception e){
}
myHandler.sendEmptyMessage(0);
}
});
thread.setDaemon(true);
thread.start();
}
});
If you just want to count from i= 1-10 seconds, you do not even need to use threads, just use postMessageDelayed by looping and calling:
myHandler.sendEmptyMessageDelayed(0, 1000); // what 0, 1 second
You can pass (preferably immutable) data in the messages as in:
Message msg= Message.obtainMessage(0);
Bundle b= new Bundle();
b.putString("stringData",outString);
msg.setData(b);
handler.sendMessage(msg);
and retrieve it as in:
Bundle b= msg.getData();
String data="";
if (b != null){
data= b.getString("stringData");
}
If you only need one additional thread, I would use asyncTask.
i got thread exception in android , what i intend to do is, while clicking a button i started a thread going to dynamically invoke the handler ,handler update the text view with integer value , while reaching integer 10, i going to stop the thread and have to show an alert ,but it will cause an error, what i possibly doing is shown below
public class sample extends Activity implements Runnable{
public Camcorder()
{
try{
counterThread = new Thread(this);
}catch(Exception ee)
{
}
}
public void run()
{
try{
while(counterFlag)
{
System.out.println("The time starts at : "+counter);
Thread.sleep(1000);
calculate(counter);
counter++;
}
}catch(Exception ee){
System.out.println("Err in ee : "+ee);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
c=this.getApplicationContext();
requestWindowFeature(Window.FEATURE_NO_TITLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.main);
authalert3 = new AlertDialog.Builder(this);
authalert3.setTitle("Save Video");
authalert3.setMessage("Do you want to save this Video?");
authalert3.setPositiveButton("Yes", null);
Button test = (Button) findViewById(R.id.widget33);
test.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
counter = 0;
counterFlag = true;
counterThread.start();
}
});
public void calculate(int counter2) {
// TODO Auto-generated method stub
if(counter2<60){
if(counter2<10)
{
smin="0"+counter2;
}
else{
smin=""+counter2;
}
}
else{
hours++;
counter=0;
smin="00";
if(hours<10){
shours="0"+hours;
}
else{
shours=""+hours;
}
}
handler.sendEmptyMessage(0);
}
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
String tes=shours+":"+smin;
time.setText(tes);
test();
};
};
public void test(){
duration=1;
if(duration==hours){
counterFlag = false;
videoPath=camcorderView.stopRecording();
authalert3.create().show();
counterThread.stop();
}
}
the error is thrown at counterThread.stop();
Anyone suggest me , how to solve this error.
You don't stop threads by calling counterThread.stop. This method is deprecated. In your case, by setting counterFlag = false; your thread should be stopping itself.
You will also be getting an exception if you click twice on your button: you cannot call start on a Thread that has already been started. You must create a new instance of that Thread and start that new instance (stop the old instance before if necessary).
You can see that SO answer for some sample code on how to create/stop threads: Android thread in service issue. I suggest that you also read some tutorial on Java Threads (this is not specific to Android).
Additionally I think that you don't need a thread at all, you are doing nothing complicated and thus you could simply use the handler to do all the work:
private static final int MSG_REFRESH_UI = 0;
private static final int MSG_UPDATE_COUNTER = 1;
private int counter = 0;
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
if (msg.what==MSG_REFRESH_UI) {
String tes=shours+":"+smin;
time.setText(tes);
test();
} else if (msg.what==MSG_UPDATE_COUNTER) {
counter++;
if (counter<10) {
calculate(counter);
handler.sendEmptyMessageDelayed(MSG_UPDATE_COUNTER, 1000);
handler.sendEmptyMessage(MSG_REFRESH_UI);
}
}
};
};
public void onResume() {
handler.sendEmptyMessage(MSG_UPDATE_COUNTER);
}
public void calculate(int counter2) {
if (counter2<10) {
smin = "0"+counter2;
} else if (counter2<60) {
smin = ""+counter2;
} else{
hours++;
counter=0;
smin="00";
if(hours<10){
shours="0"+hours;
} else {
shours=""+hours;
}
}
}
This will stop the thread at 10
while(counterFlag)
{
System.out.println("The time starts at : "+counter);
Thread.sleep(1000);
calculate(counter);
counter++;
if(counter == 10) counterFlag = false;
}
I just want to continously update text in an android app. However my App crashes every time.
This is my code:
package org.pgvw.main;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class InertialView extends Activity {
TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tv = new TextView(this);
tv.setText("Time: ");
new Thread(new Runnable() {
public void run() {
while(true) {
try {
Thread.currentThread().sleep(100);
tv.setText("Time: " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
setContentView(tv);
}
}
Can anyone spot the mistake?
Greetings and thx!
Consider that you do not need to launch any additional threads to update the UI every x milliseconds. The additional overhead of an added thread is justified IF you have a time intensive task. In the following example the timer is launched on a button click. Note that this code does not create a new thread.
private Handler myHandler= new Handler(){
#Override
public void handleMessage(Message msg){
switch(msg.what){
case 0:
if (!isDoneThinking){
editTextConfusedText.setText("Still Thinking "+new Integer(thinkSeconds).toString());
thinkSeconds++;
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0),1000); // <== Loop on delayed messages every second
}
else {
thinkSeconds= 0; // reset timer
}
break;
default:
super.handleMessage(msg);
break;
}
}
};
We launch the timer in onClick. We simply send an empty message with a what value of "0".
buttonConfuseText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
isDoneThinking= false;
myHandler.sendEmptyMessage(0); <== starts timer with what value of "0"
}
};
The timer is unconstrained and will continue to count until the flag isDoneThinking is set to true.
You cannot update GUI from another thread. You can use runOnUiThread or handler to update the GUI.
for example:
new Thread(new Runnable() {
public void run() {
while(true) {
try {
Thread.currentThread().sleep(100);
runOnUiThread(new Runnable() {
public void run() {
tv.setText("Time: " + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
BTW - The use of Thread.currentThread().sleep(100); can be shorted to Thread.sleep(100) since it's a static method. see Jon Skeet's answer regarding that
Or use AsyncTask. It was designed to do background tasks and properly update the UI. Your design will be more scalable this way.