I have a very simple UI and i need to constantly run a check process, so I am trying to use a Thread with a while loop.
When I run the loop with nothing but a Thread.sleep(1000) command, it works fine, but as soon as I put in a display.setText(), the program runs for a second on the emulator then quits. I cannot even see the error message since it exits so fast.
I then took the display.setText() command outside the thread and just put it directly inside onCreate, and it works fine (so there is no problem with the actual command).
here is my code, and help will be greatly appreciated.
Thank you!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
on=(Button) findViewById(R.id.bon);
off=(Button) findViewById(R.id.boff);
display=(TextView) findViewById(R.id.tvdisplay);
display2=(TextView) findViewById(R.id.tvdisplay2);
display3=(TextView) findViewById(R.id.tvdisplay3);
stopper=(Button) findViewById(R.id.stops);
stopper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(boo=true)
{
boo=false;
display3.setText("System Off");
}
else{
boo=true;
}
}
});
Thread x = new Thread() {
public void run() {
while (boo) {
display3.setText("System On");
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
display3.setText("System On");
display3.setText("System On");
x.start();
}
You can't update the UI from a non-UI thread. Use a Handler. Something like this could work:
// inside onCreate:
final Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
display3.setText("System On");
}
};
Thread x = new Thread() {
public void run() {
while (boo) {
handler.invokeLater(updater);
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
You could also avoid a Handler for this simple case and just use
while (boo) {
runOnUiThread(updater);
// ...
Alternatively, you could use an AsyncTask instead of your own Thread class and override the onProgressUpdate method.
Not 100% certain, but I think it is a case of not being able to modify UI controls from a thread that did not create them?
When you are not in your UI thread, instead of display3.setText("test") use:
display3.post(new Runnable() {
public void run() {
display3.setText("test");
{
});
You should encapsulate this code in an AsyncTask instead. Like so:
private class MyTask extends AsyncTask<Void, Void, Void> {
private Activity activity;
MyTask(Activity activity){
this.activity = activity;
}
protected Long doInBackground() {
while (true){
activity.runOnUiThread(new Runnable(){
public void run(){
display3.setText("System On");
}
});
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
Then just launch the task from your onCreate method.
In non-UI thread,you can't update UI.In new Thread,you can use some methods to notice to update UI.
use Handler
use AsyncTask
use LocalBroadcast
if the process is the observer pattern,can use RxJava
Related
i am trying to display a Toast on the screen and when Toast fades off then move to the next question. I have tried with Thread but cannot seem to manage.
My code:
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getUserSelection()){
position = position + 3;
if (position < questionsArray.size()) {
curName = questionsArray.get(position).getName();
curArray = questionsArray.get(position).getAnswers();
curIscorrect = questionsArray.get(position).getIscorrect();
setupQuestionView(curName, curArray, curIscorrect);
} else {
StringGenerator.showToast(QuestionsActivity.this, "Your score : " + score + "/" + (questionsArray.size() / 3));
}
}else {
StringGenerator.showToast(QuestionsActivity.this, getString(R.string.noanswerselected));
}
}
});
and the getUserSelectionMethod:
private boolean getUserSelection() {
correct = (RadioButton)findViewById(group.getCheckedRadioButtonId());
if (correct == null){
return false;
}else {
correctAnswerText = correct.getText().toString();
if (map.get(correctAnswerText).equals(Constants.CORRECTANSWER)) {
score++;
setCorrectMessage();
return true;
} else {
setWrongMessage();
return true;
}
}
}
private void setCorrectMessage() {
correctToast = new Toast(QuestionsActivity.this);
correctToastView = getLayoutInflater().inflate(R.layout.correct, (ViewGroup) findViewById(R.id.correctRootLayout));
correctText = (TextView)correctToastView.findViewById(R.id.correctTextView);
correctText.setText(getString(R.string.correctAnswer));
correctToast.setDuration(Toast.LENGTH_SHORT);
correctToast.setView(correctToastView);
correctToast.show();
correctThread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
correctToast.cancel();
}
});
correctThread.start();
}
private void setWrongMessage() {
wrongToast = new Toast(QuestionsActivity.this);
wrongToastView = getLayoutInflater().inflate(R.layout.wrong, (ViewGroup) findViewById(R.id.wrongRootLayout));
wrongText = (TextView)wrongToastView.findViewById(R.id.wrongTextView);
wrongText.setText(getString(R.string.wrongAnswer));
wrongToast.setDuration(Toast.LENGTH_SHORT);
wrongToast.setView(wrongToastView);
wrongToast.show();
wrongThread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
wrongToast.cancel();
}
});
wrongThread.start();
}
Any suggestion on how to do this?
You can determine the toast visibility:
toast.getView().getWindowToken()
If the result is null, than your toast isn't visible anymore, and than you can run any code you want.
as stated in this answer you can start a thread that waits the duration of the Toast:
Thread thread = new Thread(){
#Override
public void run() {
try {
Thread.sleep(3500); // 3.5seconds!
// Do the stuff you want to be done after the Toast disappeared
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Toast.LENGTH_SHORT and Toast.LENGTH_LONG are only flags so you have to either hard code the duration or keep them in a constant. The durations are 3.5s (long) and 2s (short).
If you want to manipulate some of your views, you cannot do this in another thread than the "main" UI thread. So you have to implement a kind of callback/polling mechanism to get notified when the SleepThread has finished.
Check this answer to read about a couple of ways to do this. Probably the easiest of them to understand and implement is this:
After you started your Thread you can check if it is still alive and running by calling thread.isAlive(). In this way you can do a while loop that runs while the thread is running:
// start your thread
while(thread.isAlive()){}
// continue the work. The other thread has finished.
Please note that this is NOT the most elegant way to do this! Check the other possibilities in the answer I've mentioned above for more elegant solutions (especially the last one with the listeners is very interesting and worth reading!)
That's because the Thread class is purely executed in the background and you need to manipulate the view in the Main thread. To solve your issue just replace the Thread with AsynTask.
AsyncTask<Void,Void,Void> a = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
correctToast.cancel();
}
};
a.execute();
If you look at my code you can see my onPostExecute, this method is called in the Main Thread.
My Error was because i was trying to acess UI Elements through another Thread so modifying the code like this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
QuestionsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
moveToNextQuestion();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
did the trick. I hope my answer helps someone!!!
i want the AsyncTask to wait till it finishes. so i wrote the below code and i used .get() method as follows and as shown below in the code
mATDisableBT = new ATDisableBT();
but at run time the .get() doesnt force ATDisableBT to wait, becuase in the logcat i receive mixed order of messages issued from ATDisableBT and ATEnableBT
which means .get() on ATDisableBT did not force it to wait
how to force the AsyncTask to wait
code:
//preparatory step 1
if (this.mBTAdapter.isEnabled()) {
mATDisableBT = new ATDisableBT();
try {
mATDisableBT.execute().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//enable BT.
this.mATEnableBT = new ATEnableBT();
this.mATEnableBT.execute();
You can do this way:
doInBackground of AsyncTask
#Override
protected Void doInBackground(String... params) {
Log.i("doInBackground", "1");
synchronized (this) {
try {
mAsyncTask.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.i("doInBackground", "2");
return null;
}
Outside this function from where you have to nstrong textotify AsyncTask to release from wait state:
new CountDownTimer(2000, 2000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
synchronized (mAsyncTask) {
mAsyncTask.notify();
}
}
}.start();
Here I have notified AsyncTask by CountDownTimer after 2 seconds.
Hope this will help you.
You should execute AsyncTask on UI thread, so using get() - which will block it makes no sense - it might get you ANR error.
If you are on HONEYCOMB and up, then AsyncTasks are executed on single executor thread, serially - so your mATEnableBT should get executed after mATDisableBT. For more see here:
http://developer.android.com/reference/android/os/AsyncTask.html#execute(Params...)
You might also switch from AsyncTask to Executors. AsyncTask is implemented using executors. By creating single threaded executor you make sure tasks will get executed serially:
ExecutorService executor = Executors.newSingleThreadExecutor();
//...
executor.submit(new Runnable() {
#Override
public void run() {
// your mATDisableBT code
}
});
executor.submit(new Runnable() {
#Override
public void run() {
// your mATEnableBT code
}
});
Hi currently i have the following code which utilizes Asycn Task and Timer.
My async task is basically trying to send a HTTP GET method from a URL where the response from the server could varies depending on connection and load.
What i would like to do is to have a timed async task. Where, it will schedule an AsyncTask every X second BUT if there is currently an Async Task in progress i would have to kill it first. Then start a new one.
Here is the code that i have at the moment:
private static boolean running = false;
Timer myTimer;
protected void onCreate(Bundle savedInstanceState) {
/* REST OF CODE OMITTED */
MyTimerTask myTask = new MyTimerTask();
myTimer = new Timer();
myTimer.schedule(myTask, 0, 10000);
}
/* REST OF CODE OMITTED */
private class MyTimerTask extends TimerTask {
public void run() {
if(!running){
Log.i("TAG", "NEW TIMER STARTED.");
RetrieveChatMessage task = new RetrieveChatMessage();
task.execute();
running = true;
}else{
running = false;
}
}
}
private class RetrieveChatMessage extends AsyncTask<String, Void, ArrayList<Chat>> {
#Override
protected ArrayList<Chat> doInBackground(String... params) {
// TODO Auto-generated method stub
ArrayList<Chat> cList = null;
String jResult = null;
Log.i("TAG", "RETRIEVING CHAT MESSAGE");
try {
jResult = ((new HttpRetriever())).getChatList(mAccount.email, mAccount.passwd);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(jResult != null){
Log.i("TAG", "JSON DATA: " + jResult);
cList = (new ChatHandlers()).getChatList(jResult);
}else{
cList = null;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("TAG", "JSON Exception " + e.toString());
}
return cList;
}
#Override
protected void onPostExecute(final ArrayList<Chat> result) {
Log.i("TAG", "ON POST EXECUTE");
if(result != null){
// Do something here
}
}
}
To be honest the code above works with slight issues:
1. It seems to execute the Async randomly, instead of every 10 seconds.
2. When i go to another activity, somewhat it prevents other Async task from doing its job (Which is also trying to retrieve JSON response from server).
I am not too worried about the later problem (and that is not the question i am asking). I just would like to know how to have a proper timed Async Task. Can anyone point me to a direction.
Thank you.
EDIT #1:
after reading #thepoosh comment's i tried the following (i put it in onCreate):
scheduleTaskExecutor= Executors.newScheduledThreadPool(5);
scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
public void run() {
// Parsing RSS feed:
// myFeedParser.doSomething();
Log.w("THUMBQOO", "NEW TASK STARTED");
retrieveChat();
}
}, 0, 15, TimeUnit.SECONDS);
Result: i have a consistent execution of Task. However, it seems that retrieveChat(); is never be called after the first execution.
Actually AsyncTask is not used for long operations .Check Here
You should use a Thread that uses a interface to notify UI or you can simply use a Handler which is the most Preffered way in android. Simply you can do a task repeatedly for every 10 seconds by
handler.postDelayed(new Runnable() {
#Override
public void run() {
// do work
handler.postDelayed(10000);
}
}, 10000);
Declare a Handler object to maintain future task executor...
private Handler mTimerHandler = new Handler();
Write a thread which will execute your future task...
private Runnable mTimerExecutor = new Runnable() {
#Override
public void run() {
//write your code what you want to do after the specified time elapsed
if(!running){
RetrieveChatMessage task = new RetrieveChatMessage();
task.execute();
running = true;
}else{
running = false;
}
}
};
Call your future tast executor with time using hanlder...
mTimerHandler.postDelayed(mTimerExecutor, 10000);
You can cancle your future task executor any time by this...
mTimerHandler.removeCallbacks(mTimerExecutor);
I am not sure if this is a very good way of accomplishing this (my answer here below) :
Use a Handler, create a HandlerThread and keep posting messages to this handler.
For the handlers "handleMessage" method, you can do your task and again send a message back to the MessageQueue.
HandlerThread thread = new HandlerThread(<name>);
thread.start();
Looper looper = thread.getLooper();
CustomHandler handler = new CustomHandler(looper);
// The CustomHandler class
class CustomHandler extends Handler {
public CustomHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
//Do your operation here
handler.sendEmptyMessageDelayed(msg, <delayTime>);
}
}
I'm trying to send a toast notification of an error in a thread. The thread is started in a service that is called from the main thread. I've tried several things with View.post and some weird handler stuff, but nothing seems to work. An excerpt of the thread is as follows:
public int onStartCommand(Intent intent, int flags, int startId)
{
new Thread(new Runnable(){
public void run() {
boolean bol = true;
while (bol)
{
try
{
//Some socket code...
}
catch (Exception e)
{
//Where I want the toast code.
}
}
}
}).start();
return START_STICKY;
}
Try following inside the thread in the service:
Handler h = new Handler(context.getMainLooper());
// Although you need to pass an appropriate context
h.post(new Runnable() {
#Override
public void run() {
Toast.makeText(context,message,Toast.LENGTH_LONG).show();
}
});
Taken from answer given by #Alex Gitelman here on Android: How can i show a toast from a thread running in a remote service? . This might help somebody as it helped me.
Toast can be shown only from UI Thread (Main Thread). To show Toast from some other threads you have to use Handler.
Threads, Handlers and AsyncTask
Yes you should use a Handler, and bind you Activity to your Service
Once the Handler is set, here is what you should do,
Message msg = Message.obtain(null, MyActivity.TOAST);
Bundle bundle = new Bundle();
bundle.putString(MyActivity.TOAST_MSG, "Toast message");
msg.setData(bundle);
try {
myActivityMessenger.send(msg);
} catch (RemoteException e) {
if (D) Log.w(TAG, "Unable to send() the toast message back to the UI.");
e.printStackTrace();
}
myActivityMessenger is set with the Handler of your MyActivity and sent to the Service when you bind MyActivity to it.
However displaying a Toast with a Service as context should work (but it's not the best way), so maybe it's because you try to make it from a new Thread. What is your code for making the Toast ?
new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
_dialog.dismiss();
Toast.makeText(LatestNewsActivity.this, "NO Internet Connection Available", Toast.LENGTH_LONG).show();
}
});
}
}.start();
hi i am working on custom toast , and i am able to do that, but after when i move to next activity the thread is running or active of back activity , so what should i do for removing that thread or stop this thread.
my code is given below :
public void customToast(int x, int y, String str) {
if (Util.tipson == true) {
toast = new Toast(getApplicationContext());
toast.setDuration(Toast.LENGTH_SHORT);
toast.setGravity(Gravity.TOP, x, y);
LayoutInflater li = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
toastView = li.inflate(R.layout.toastlayout, null);
toast.setView(toastView);
TextView text = (TextView) toastView.findViewById(R.id.text);
text.setText(str);
// toast.show();
fireLongToast();
}
}
private void fireLongToast() {
t = new Thread() {
public void run() {
int count = 0;
try {
while (true && count < 40) {
try {
toast.show();
sleep(100);
count++;
} catch (Exception e) {
// TODO: handle exception
}
// do some logic that breaks out of the while loop
}
toast = null;
toastView = null;
} catch (Exception e) {
Log.e("LongToast", "", e);
}
}
};
t.start();
}
You Need to stop your thread by yourself. Since java doesn't allow you to use stop() function.
Write class for your Thread as this
public class YourThread extends Thread {
private volatile boolean stopped = false;
public void run() {
int count = 0;
try {
while (true && count < 40 && !stopped) {
try {
toast.show();
sleep(100);
count++;
} catch (Exception e) {
// TODO: handle exception
}
// do some logic that breaks out of the while loop
}
toast = null;
toastView = null;
} catch (Exception e) {
Log.e("LongToast", "", e);
}
}
public void stopThread() {
stopped = true;
}
}
Now when your Activity which has the Thread Finishes stop Your thread
#Override
protected void onDestroy() {
if(isFinishing())
yourThreadVariable.stopThread();
}
Dont know for sure, but you can call the function join of thread in onDestroy of your activity.
To stop the thread you can just use interrupt(). But for better solution I would say not to use Thread. Just create a Handler with Runnable and manage your Runnable using Handler, that would be a nice way as Android has given Handler for managing one or more Runnables.
Creating a Runnable
Runnable runnable = new Runnable() {
#Override
public void run() {
// put your code stuff here
}
};
To start Runnable use
handler.postDelayed(runnable, your_time_in_millis);
To stop Runnable use
handler.removeCallbacks(runnable);
Does finishing the activity have any effect?
I would like to suggest Lalit Poptani method too and implement this:
protected void onStop(){
handler.removeCallbacks(runnable);
super.onStop();
}
The documentation for the method:
onStop,Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed.
http://developer.android.com/reference/android/app/Activity.html