Control a textView - android

my application keeps force closing. But Eclipse shows no error or warnings
package com.example.pkg;
import android.os.Bundle;
import android.widget.TextView;
import android.app.Activity;
public class subActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sub);
Thread r = new Thread(new Runnable(){
public void run()
{ final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");
}
});
r.start();
}
}
Another Activity calls this Activity. That one has the TextView displayed. All I want to do is to change this string resource called R.string.rline1 that is being displayed on the TextView. Please tell me how to do this if there is another way

First thing, you must need to update GUI stuffs inside UI thread else it will never work. Second thing you know how many times you are creating the instance of your text view and setting it again again, you are inside the thread and you havn't set any flag to stop your thread once you are done. E.g for UI thread :
Runnable update_gui = new Runnable() {
#Override
public void run() {
final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");
}
};runOnUiThread(update_gui);

You are trying to update your UI (with tv.setText(s+"Works !");) in a thread. You cannot do that. You must update your UI in the main thread. Just delete this useless Thread:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sub);
TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");
}
Note: Eclipse doesn't show errors, you must open your logcat (by default in the DDMS perspective in Eclipse.)
Next time, post your logcat error when you have troubles.

Replace below code
Thread r = new Thread(new Runnable(){
public void run()
{ **final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");**
}
});
r.start();
with
final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");

Related

Threading Error

I get some error. I really couldn't solve it today :( I get error after set ID data to lblID in FillData() method. It sets ID data properly but lblTitle and lblPrice always returns error like "Only the original thread that created a view hierarchy can touch its views" and program stops running.
Note : This is not my original code. I just minimized it to be more understandable and of course it gives same error like below code. Anyway in FillData() method i get data from wcf service and it returns data properly. i tried runonuithread but it didn't make any sense. Also if i write the code outside of the thread it doesn't fill the controls. Because it's originally gets the data from wcf service.
public class MainActivity extends AppCompatActivity {
LinearLayout lytData;
TextView lblTitle, lblID, lblPrice;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lytData = (TextView)findViewById(R.id.lytNewData);
lblID = (TextView)findViewById(R.id.lblID);
lblTitle = (TextView)findViewById(R.id.lblTitle);
lblPrice = (TextView)findViewById(R.id.lblPrice);
new Thread() {
public void run() {
FillData();
}
}.start();
lytData.setOnTouchListener(new OnCustomTouchListener (context) {
#Override
public void ToLeft() {
new Thread() {
public void run() {
FillData();
}
}.start();
}
#Override
public void ToRight() {
new Thread() {
public void run() {
FillData();
}
}.start();
}
});
}
void FillData() {
lblID.setText("aaa");
lblTitle.setText("aaa");
lblPrice.setText("aaa");
}
The problem is you're trying to update the UI in another thread, but the UI can only be updated in the UI thread. If you're simply updated the UI as your code is showing then you should remove the calls from FillData from the secondary thread, use a secondary thread if you're doing heavy loading inside FillData() otherwise you're better off updating the UI directly in the UI thread:
So instead of doing this:
new Thread() {
public void run() {
FillData();
pd.cancel();
}
}.start();
Just simply call FillData(); outside the new thread.
You can also call runOnUiThread to bring the update to the ui thread:
getActivity().runOnUiThread(new Runnable() {
public void run() {
FillData();
}
});
If your code inside FillData is mixed with heavy load code, then you can bring the runOnUiThread method to inside the FillData and move only the UI update code to runOnUiThread.
If you still want to keep your code the way it is you can "post" changes from your secondary thread like this:
viewElement.post(new Runnable() {
public void run() {
//update UI
}
});
}
viewElement is any UI element that extends from View.

Thread is able to change ui if started from inside activity lifecycle methods. why?

I was testing this code to check if app crashes for changing ui component from background thread. but it didn't.
Here in the code added below. I started a new thread in onCreate() method of MainActivity and It should have crashed as per the android docs which says
In the class, the Runnable.run() method contains the code that's
executed. Usually, anything is allowable in a Runnable. Remember,
though, that the Runnable won't be running on the UI thread, so it
can't directly modify UI objects such as View objects.
So I was expecting it to crash. Which it didn't. See code -
public class MainActivity extends AppCompatActivity {
TextView txt;
Thread thread;
Runnable runnable = new Runnable() {
#Override
public void run() {
txt.setText("bro");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = (TextView) findViewById(R.id.name_txt);
thread = new Thread(runnable);
thread.start();
}
}
While if i try changing ui while starting thread from onClicklistener() as below it does crash. which is expected.
public class MainActivity extends AppCompatActivity {
TextView txt;
Thread thread;
Runnable runnable = new Runnable() {
#Override
public void run() {
txt.setText("bro");
}
};
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
thread.start();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = (TextView) findViewById(R.id.name_txt);
thread = new Thread(runnable);
txt.setOnClickListener(listener);
}
}
Now, that the second code snippet crashes, which is expected and the first one doesn't.
Please explain why is this happening, as I'm creating a new worker thread each time but just at different places. Official docs reference will be appreciated.
I found the reason behind this behavior as pointed out by #krish in the comments on my question. The reason is that, the thread was able to make changes in the TextView object only till it was not visible on UI screen i.e not rendered. It is only after the view rendering, that any thread except the Main thread may not make changes to any UI components. I Tried using view observer to see if the view was rendered before the changes or not. which showed that changes were made before the view rendering.
Here is the code that i tried.
public class MainActivity extends AppCompatActivity {
TextView txt;
Thread thread;
Runnable runnable = new Runnable() {
#Override
public void run() {
txt.setText("bro");
Log.d("ThreadTest", "The Text was changed.");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = (TextView) findViewById(R.id.name_txt);
thread = new Thread(runnable);
txt.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Log.d("ThreadTest", "The TextView was rendered");
}
});
}
#Override
protected void onResume() {
super.onResume();
thread.start();
}
}
Using the code above. You'll see in the output:
The Text was changed.
The TextView was rendered
Which means text was changed before view rendering. if you try to start thread to makes changes in onGlobalLayout method. App crashes as it should.
The UI is not thread-safe see processes-and-threads, so you were just lucky you did not hit one of the many landmines waiting for you.
If you don't like relying on luck then:
You should be using:
runOnUiThread(runnable);
instead of:
thread = new Thread(runnable);
AsyncTask enables proper and easy use of the UI thread.

Threads cannot start in android

I have a problem with my Thread, the Thread doesn't start, I don't have any idea why it doesn't run.
This is my code,
public class MainActivity extends AppCompatActivity {
TextView tv;
int seg=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.reloj);
}
boolean on=false;
public void inicia(View view){
if(!on){
tiempo.start();
on=true;
}
}
Thread tiempo=new Thread(){
public void run(){
try{
while(true){
Thread.sleep(1000);
seg++;
tv.setText(seg+"");
}
}catch (InterruptedException e){
}
}
};
}
prints this error
Only the original thread that created a view hierarchy can touch its views.
Well first off I'm assuming you set an onClick in you xml to set inicia to be the click handler for the button. Otherwise, that's part of your problem.
You thread is in an infinite loop. The while loop would only exit if an interrupt occurred for some reason, and there's nothing that would do that. If you want to post accio every second, the post needs to be inside the while loop.
while(true){
Thread.sleep(1000);
}
The thread is sleeping all the time.
Ok lets try,
Thread will be created from the main looprer thread. So, Your textview will be updated only by mainlooper thread,. When you create the thread, it will start become another thread. it is not related with MainLooper thread, You have to use Handler class to update the textView or use Asynctask or runOnUiThread method to update your text view.
runOnUiThread(new Runnable() {
#Override
public void run() {
textview.settext("");
}
});

Android App stops after TextView text is changed

I have made an android app, which has two TextViews. When I change the text using setText() then the app stops.
I have read other answers on StackOverflow and have implemented them in my program, but the problem still persists.
Here is my onCreate() code:
TextView ec, vc;
Thread t;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ec = (TextView) findViewById(R.id.ce);
vc = (TextView) findViewById(R.id.cv);
t = new Thread(new Runnable() {#Override public void run() {loop();}});
t.start();
}
Here is my loop() code:
public void loop()
{
try{Thread.sleep(7000);}catch(Exception e){}
ec.setText("");
vc.setText("");
try{Thread.sleep(53000);}catch(Exception e){}
t.stop();
}
I want to empty the text of both the TextViews after 7 seconds.
But when I run my app, after 7 seconds, it stops.
Other answers on StackOverflow say that I should put setContentView(R.layout.activity_main); before I initiate the ec and vc variables. It is already there, but still the app stops.
Please help me.
You can use the View.postDelayed method to run a Runnable on the UIThread after a certain time.
UI Elements can only be changed from the UI (Main) thread, therefore it breaks down. Try using:
activity.runOnUiThread(new Runnable() {
public void run() {
//Do something on UiThread
}
});
But you'll make the UI thread sleep, which means it'll freeze up any way. So, bad practice.
try that
public void loop()
{
try{Thread.sleep(7000);}catch(Exception e){}
activity.runOnUiThread(new Runnable() {
public void run() {
ec.setText("");
vc.setText("");
}
});
try{Thread.sleep(53000);}catch(Exception e){}
t.stop();
}

Why does Handler::postDelay make UI frozen

I have this code. I don't know why postDelay make UI frozen in this case. I want the Runnable will run after 100 miliseconds deley and run in 4000 miliseconds.
package com.delaythread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class MyNeedActivity extends Activity implements OnClickListener {
private ProgressBar progressBar;
private final Handler handler = new Handler() {
#Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
progressBar.setVisibility(ProgressBar.INVISIBLE);
}
};
#Override
public void onClick(final View v) {
if(v.getId() == R.id.button1) {
/* This call doesn't make ProgressBar frozen.
final Thread t = new Thread(new MyRunnable());
t.start();
progressBar.setVisibility(ProgressBar.VISIBLE);
*/
// This makes ProgressBar frozen in 4000 miliseconds.
final boolean b = handler.postDelayed(new MyRunnable(), 100);
if(b) {
progressBar.setVisibility(ProgressBar.VISIBLE);
}
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button)findViewById(R.id.button1)).setOnClickListener(this);
progressBar = (ProgressBar)findViewById(R.id.progressBar1);
}
private class MyRunnable implements Runnable {
#Override
public void run() {
sleep();
}
private void sleep() {
try {
Thread.sleep(4000);
handler.sendEmptyMessage(0);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
}
Update: Actually what I want is AsyncTask executes after a delay time, so I do as this answer Java/android how to start an AsyncTask after 3 seconds of delay?. He said I should use Handler and Runnable.
The following should suit your need according to the post
private final Handler handler = new Handler() {
#Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
//start Asyntask here. progress show/hide should be done in asynctaswk itself.
}
};
#Override
public void onClick(final View v) {
if(v.getId() == R.id.button1) {
final boolean b = handler.postDelayed(new MyRunnable() , 1000);
}
}
private class MyRunnable implements Runnable {
#Override
public void run() {
handler.sendmessage(0);
}
}
}
You probably want to run your MyRunnable on other thread than main UI one, so you need to start a regular thread for this, like
new Thread(new MyRunnable()).start();
instead of using Handler for this, which queues your runnable to be executed on main UI thread.
BTW, for this purpose Timer with TimerTask would suit better.
The Android Reference for the class Handler points out:
"[...] When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it [...]"
So your Handler, created on instantiation of the Activity, should be running on the UI thread causing it to block when your Runnable is executed.
Try creating a new Thread class in which your Handler is instantiated. Then pass the Runnable to it from your onClick() method. To pass messages back (such as updating the progress bar) you can use another Handler that is running on the UI thread.
You could also save yourself a lot of pain by taking a look at the AsyncTask class.
PS:
Delaying the execution could be done in the AsyncTaskdoInBackground() via a Thread.sleep(100) call. To delay execution on UI thread level you could do the same in AsyncTask.onPreExecute().
As far as I understand it you ask your MyRunnable to run on the GUI thread (of which there is only one); but the only this it does is sleep, effectively causing the GUI thread to freeze waiting for it.
You shouldn't do complicated calcultaions (or, sleep) in the GUI thread.
You may want to read the documentation on threads and the UI thread for a more elaborate description.
Your progress bar isn't updating because you aren't updating it! Try using an AsyncTask, (it runs on a different thread but allows you to update UI elements) and setting the state of the progress bar from within the onProgress method in the Async task.
OR
Just follow this example on the Android Progress Bar page
Try this:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Code to be executed after desired seconds
}
}, seconds*1000);
This would freeze the UI for given number of seconds and the execute the code inside the run()

Categories

Resources