CalledFromWrongThreadException when adding TextView - android

I have implemeted a custom camera and I want it to go, after a period of time into a standby state. The standby concsists from a stopPreview, a camera release and a view that tells the user to tap in order to exit the standby. Because I set the text within the new thread, I get the CalledFromWrongThreadException, but I don't know what the solution could be. I found other posts around, but none of them really worked.
Code:
private void initCamera()
{//more code
threadModifiedText = (TextView) findViewById(R.id.textView1);
Thread standbyThread = new Thread()
{
#Override
public void run()
{
try
{
while (timeCounter > 0)
{
if (!activeThread)
{
sleep(100);
if (timeCounter % 10 == 0)
{
threadHandler.sendEmptyMessage((int) timeCounter / 10);
}
timeCounter--;
}
}
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.stopPreview();
mCamera.release();
TextView standbytext = new TextView(SlicesActivity.this);
standbytext.setText("Tap to exit standby mode");
FrameLayout preview = (FrameLayout) findViewById(id.FrameLayout_camera_preview);
preview.addView(standbytext);
}
};
standbyThread.start();
//more code}
And
#Override
public void onUserInteraction()
{
Log.d("~~~~~~~~~", "apasat");
activeThread = true;
timerCounter = 300;
}
private Handler threadHandler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
// whenever the Thread notifies this handler we have
// only this behavior
threadModifiedText.setText("\ncounter is " + Integer.toString(msg.what));
}
};
Please guys, give me some suggestions. 10x

try to use
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO: update your UI here
}
});
in your thread to update UI

You cannot set text values inside any thread except the UI thread. Complete your background thread operations and set the text value after your operations are over in the UI thread.

Related

Wait for thread to finish and then move to next position

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!!!

Update UI from running thread

I want to write a download manager app, in the activity I add a progress bar which show the current progress to the user, now if user touch the back button and re-open the activity again this ProgressBar won't be updated.
To avoid from this problem I create a single thread with unique name for each download that keep progress runnable and check if that thread is running in onResume function, if it is then clone it to the current thread and re-run the new thread again but it won't update my UI either, Any ideas !?
#Override
public void onResume()
{
super.onResume();
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for (int i = 0; i < threadArray.length; i++)
if (threadArray[i].getName().equals(APPLICATION_ID))
{
mBackground = new Thread(threadArray[i]);
mBackground.start();
downloadProgressBar.setVisibility(View.VISIBLE);
Toast.makeText(showcaseActivity.this
, "Find that thread - okay", Toast.LENGTH_LONG).show();
}
}
private void updateProgressBar()
{
Runnable runnable = new updateProgress();
mBackground = new Thread(runnable);
mBackground.setName(APPLICATION_ID);
mBackground.start();
}
private class updateProgress implements Runnable
{
public void run()
{
while (Thread.currentThread() == mBackground)
try
{
Thread.sleep(1000);
Message setMessage = new Message();
setMessage.what = mDownloadReceiver.getProgressPercentage();
mHandler.sendMessage(setMessage);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
catch (Exception e)
{/* Do Nothing */}
}
}
private Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message getMessage)
{
downloadProgressBar.setIndeterminate(false);
downloadProgressBar.setProgress(getMessage.what);
if (getMessage.what == 100)
downloadProgressBar.setVisibility(View.GONE);
}
};
Download button code:
downloadBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
downloadProgressBar.setVisibility(View.VISIBLE);
downloadProgressBar.setIndeterminate(true);
downloadProgressBar.setMax(100);
Intent intent = new Intent(showcaseActivity.this, downloadManagers.class);
intent.putExtra("url", "http://test.com/t.zip");
intent.putExtra("receiver", mDownloadReceiver);
startService(intent);
updateProgressBar();
}
});
I'd strongly recommend reading the Android Developer blog post on Painless Threading. As it states, the easiest way to update your UI from another thread is using Activity.runOnUiThread.

how can I chnage a TextViews text from a thread?

I'm trying to write code to pull a server every second for updated messages. The messages then get displayed in a text view. If I do not change the text in the text view it runs fine. It will crash if I try to change the textview on the thread. IF i change it not on the thread works fine.
I'm assuming the thread cannot access the main threads memory? How can I set the text in the view with the text just loaded over the internet?
In the code below I have a thread that does a endless loop with a sleep. It calls a method called SendMessage. Send Message loads in text over the internet and at the end tries to update the View with it. It causes a exception when this happens.
code:
public class cChat extends cBase implements OnClickListener {
/** Called when the activity is first created. */
TextView mUsers;
TextView mComments;
int i=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
mUsers=( TextView) findViewById(R.id.viewusers);;
mComments=( TextView) findViewById(R.id.viewchats);;
Thread thread = new Thread()
{
#Override
public void run() {
try {
int t=0;
while(true)
{
SendMessage();
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
public void onClick(View v) {
} // end function
// send a uypdate message to chat server
// return reply in string
void SendMessage()
{
try {
URL url = new URL("http://50.63.66.138:1044/update");
System.out.println("make connection");
URLConnection conn = url.openConnection();
// set timeouts to 5 seconds
conn.setConnectTimeout(1000*5);
conn.setReadTimeout(5*1000);
conn.setDoOutput(true);
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// String line;
String strUsers=new String("");
String strComments=new String("");
String line=new String();
int state=0;
while ((line= rd.readLine() ) != null) {
switch(state){
case 0:
if ( line.contains("START USER"))
state=1;
if ( line.contains("START COMMENTS"))
state=2;
break;
case 1:
if ( line.contains("END USER"))
state=0;
else
{
strUsers+=line;
strUsers+="\n";
}
break;
case 2:
if ( line.contains("END COMMENTS"))
state=0;
else {
strComments+=line;
strComments+="\n";
}
break;
} // end switch
} // end loop
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
} catch (Exception e) {
i++; // use this to see if it goes here in debugger
// System.out.println("exception");
// System.out.println(e.getMessage());
}
} // end methed
}
use runOnUiThread as
YOUR_CURRENT_ACTIVITY.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
//....YOUR UI ELEMENTS
}
});
EDIT :
see doc runOnUiThread
You can use a handler to post tasks (Runnables) to the UI/Main Thread:
private Handler handler = new Handler();
//...
Thread thread = new Thread()
{
#Override
public void run() {
try {
int t=0;
while(true)
{
handler.post(new Runnable() {
#Override
public void run() {
SendMessage();
}
});
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
You can't touch an UI widget from a thread different than the one used to create it (the UI thread). But if you have a reference to the Activity, you can simply do:
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
mUsers.setText(strUsers);
mComments.setText(strComments);
}
});
which would require strUsers to be accessible by the anonymous class. For that you can simply do:
final String finalUseres = strUsers;
and use finalUsers within run().
Try using a Service to continuously pull/send data to server. This will reduce the load on your UI-Thread.
the Andoid UI toolkit is not thread-safe. So, you
must not manipulate your UI from a worker thread
To fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
you can also use AsyncTask.
see this tutorial on process and threads in android.

remove toast and also destroy or force stop thread

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

While Loop inside Thread not working?

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

Categories

Resources