I make an app that can count down. But it doesn't work and it just shows 100 in textview.
Here is my code:
public class MainActivity extends Activity {
private TextView textView;
private Button start;
Thread thread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView1);
start = (Button) findViewById(R.id.button1);
start.setOnClickListener(onStart);
thread = new Thread( //it's my thread
new Runnable() {
#Override
public void run() {
for (int i = 99; i > 0; i--) {
Log.i("Where am I?", "I'm in for loop .");
try {
textView.setText(String.valueOf(i));
} catch (Exception e) {
Log.e("Exception.getCause", String.valueOf(e.getCause()), e.getCause());
}
Log.i("INDEX", String.valueOf(i));
}
}
});
}
private View.OnClickListener onStart = new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Where am I?", "I in View.OnClickListener .");
thread.start();
}
};
}
Update your TextView using runOnUiThread as below...
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(String.valueOf(i));
}
});
Update:
For delay in count you can use Handler as below. Create an object of Handler and create a Thread.
private Handler mTimerHandler = new Handler();
private Runnable mTimerExecutor = new Runnable() {
#Override
public void run() {
//add your code here which should execute after the specified delay
}
};
Then pass that thread inside postDelayed() method Handler with the time which should be delayed to execute the thread as below...
mTimerHandler.postDelayed(mTimerExecutor, 1000);
And if you want to cancel the thread to execute, use removeCallbacks() method as below...
mTimerHandler.removeCallbacks(mTimerExecutor);
Catching for Exception inside the Thread is kind of misleading. As matter of fact, textView.setText(String.valueOf(i)); executed in a Thread different from the UI Thread should make you app crashes for CalledFromTheWrongThreadException. You should use an Handler to execute that line in the UI Thread's context
textView.setText(String.valueOf(i));
has to be used in UI thread only.
textView.setText(String.valueOf(i));
This is UI action, You can handle UI action only in a main thread.
You can send a message to the handle of activity.
You cannot use Thread class to interact with UI you should use AsyncTask or Handler classes.
Sample tutorial: http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html
Use AsyncTask instead.
Checkout:
http://www.vogella.com/tutorials/AndroidBackgroundProcessing/article.html
Related
I start a Thread in a Fragment and use an Interface call, to #Override a method in the Fragment starting the thread. This #Override stops a ProgressDialog and changes the Text of a TextView in the Fragment.
When I do the same in an Activity, there is no Problem but now when using a Fragment I got the "only Thread that creates a View can touch it's views" - Error. So I used getActivity().runOnUiThread(runnable) and posted the code to the MainThread, but why do I need to do this, since it works in a Activity without this? Did I made a mistake?
The Thread
//interface
private ConnectToDevice connectToDevice;
//C-Tor
public Thread_ConnectToDevice(BluetoothDevice device, ConnectToDevice connectToDevice ) {
this.mBluetoothDevice = device;
this.connectToDevice = connectToDevice;
}
//call
connectToDevice.connectionSuccess(false, null);
Fragment
//make Thread
thread_connectToDevice = new Thread_ConnectToDevice(mBluetoothDevice, Fragment_RoutineStartConnection_setPassword.this);
thread_connectToDevice.start();
//CallBack
//Thread Connect Success
#Override
public void connectionSuccess(final Boolean bSuccess,final BluetoothSocket mSocket) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if(bSuccess){
mProgessDialog.setTitle(R.string.tv_Fragmentsetpassword_Connected_CheckPW);
if(thread_connectedToDevice != null){
if(thread_connectedToDevice.isAlive()){
thread_connectedToDevice.interrupt();
}
}
thread_connectedToDevice = new Thread_ConnectedToDevice(mSocket, sTryingDonglePassword);
thread_connectedToDevice.start();
}else{
mProgessDialog.dismiss();
tv_Fragmentsetpassword_userhint
.setTextColor(getResources().getColor(R.color.Mercedes_RED, null));
tv_Fragmentsetpassword_userhint.setText(R.string.tv_Fragmentsetpassword_ConnectionFailed);
}
}
});
}
I have the feeling that I passed the wrong listener Instance to the Thread.
As asked this is the callback realized the same way but in a Activity:
Thread
//listener
private Finished_AskingForInformation listener;
//C-Tor
public Td_AskForInformation(
Finished_AskingForInformation listener) {
this.listener = listener;
}
//call
listener.AskingFinished();
Activity
//Create and start thread
td_askForInformation = new Td_AskForInformation(this);
td_askForInformation.start();
//CallBack
#Override
public void AskingFinished() {
mProgressDialog.dismiss();
}
I need a thread to start after 3 seconds of a button being idle, is there a simple way of doing it?
I'm building a counter app, the button triggers two counters, the total counter and the "tapping counter", the tapping counter helps keep track of the actual change of values, showing how many taps the user did, I need it to vanish after some seconds so the user can tap again.
for stuffs like that I usually use a Handler with a Runnable in order to do stuff after X milliseconds the user isn't doing a specific action.
First, create a runnable and a handler
final android.os.Handler handler = new android.os.Handler();
private Runnable runnable;
private final long DELAY = 3000; // how many milliseconds you want to wait
Then add the onClickListener:
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
Then, inside onClick event, remove callbacks and istantiate the handler again as follows:
if(runnable != null) {
// in this case the user already clicked once at least
handler.removeCallbacks(runnable);
}
runnable = new Runnable() {
#Override
public void run() {
//this code will run when user isn't clicking for the time you set before.
}
};
handler.postDelayed(runnable, DELAY);
Final result:
final android.os.Handler handler = new android.os.Handler();
private Runnable runnable;
private final long DELAY = 3000; // how many milliseconds you want to wait
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// all your previous stuffs
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(runnable != null) {
// in this case the user already clicked once at least
handler.removeCallbacks(runnable);
}
runnable = new Runnable() {
#Override
public void run() {
//this code will run when user isn't clicking for the time you set before.
}
};
handler.postDelayed(runnable, DELAY);
}
});
}
I hope this helps, for any question feel free to ask
Handler may work in this scenario, with a 3000 milisecond delay.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// do action
}
}, 3000);
At first, you create a Timer with a TimerTask(with your Thread) and schedule it to run after 3 seconds.
Every time the button is pressed, you reset the timer.
public class MyClass{
private Timer timer=new Timer()
private TimerTask task=new TimerTask(){
public void run(){
//your action
}
};
public void init(){
timer.schedule(task,3000);
}
public void onButtonClick(){
task.cancel();
timer.schedule(task,3000);
}
}
Is it possible to generate a TextView inside a for loop in the main activity? I have to run a thread from another Java class "multithread." When this class runs, I will know how many clients connected to, I will run the insider thread to generate TextViews according to the number of the clients, and display the received messages in these TextViews.
But I am obtaining an error. If you know any better way to run a thread inside the main activity, please let me know, thanks.
Here is the method:
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
for(int counter=0;counter<multicastthreadRun.ClientIpArrayList.size();counter++) {
TextView textView=new TextView(this);//i am obtaining error here
linearLayoutSecondaryTexts.addView(textView);
runOnUiThread(new Runnable() {
#Override
public void run() {
//in this case we can change the user interface
}
});
}//end of the for loop
}
});t.start();
new Runnable is an anonymous class and this is pointing to that anonymous class. To create a textview, you need to pass context (either activity or context) so in order to do that, use specific reference to class with className as
TextView textView=new TextView(YourContainerActivityClassName.this);
// e.g TextView textView=new TextView(MainActivity.this);
Note: since it's a click listener so seems like this is in an activity directly
and you cannot update the UI from worker threads so do it like
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
for(int counter=0;counter<multicastthreadRun.ClientIpArrayList.size();counter++) {
// use proper context
TextView textView=new TextView(YourActivityNamethis);//i am obtaining error here
runOnUiThread(new Runnable() {
#Override
public void run() {
// Update UI
linearLayoutSecondaryTexts.addView(textView);
}
});
}//end of the for loop
}
});t.start();
}
TextView textView = new TextView(this);//i am obtaining error here
TextView textView = new TextView(getBaseContext());// textview expect context object NOT runnable object.
And instead of using loop you can just use Recursion.
public void toggleButtonConnectToClientsFunction(View view) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
//Multithread here
multicastthreadRun.run();
makeTextView ( 0,multicastthreadRun.ClientIpArrayList.size());
}
});
t.start();
}
private void makeTextView(final int count, final int max){
if (count>= max)
return; // end of Loop
TextView textView = new TextView(getBaseContext());// Use can you this here as it will refer to your activity object.
runOnUiThread(new Runnable() {
#Override
public void run() {
//in this case we can change the user interface
linearLayoutSecondaryTexts.addView(textView);
makeTextView(count+1, max);
}
});
}
In your code TextView(this) will not work because it is inside on Thread.
You have to specify the context exactly. Check below code:
TextView tv = new TextView(YOUR_ACTIVITY.this);
tv.setText("What to do");
Thanks :)
I have tried so many ways of solving my problem, but still no success.I have a method, which returns me a string value and I am using it to update TextView on my screen like this:
outCPU.setText(getCpuInfo());
Which would be fine, but I need to update this TextView until back button was pressed.
I guess i have need a while loop which starts after activity has been created and stops after back button was pressed. This loop should be in a new thread, because:- I have to load the activity first and execute the loop in another thread so the executing won't affect main thread and loading of the activity.
As I've already said, I don't know how to do this properly even though i have spent few hours on it.
Could someone show me an example how to get this done? Thanks...!!
EDITED - WORKING:
private Handler mHandler;
private int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_systeminfo);
outCPU = (TextView) findViewById(R.id.outCPU);
outMEM = (TextView) findViewById(R.id.outMEM);
outTASKS = (TextView) findViewById(R.id.outTASKS);
i = 0;
mHandler = new Handler();
mHandler.post(mUpdate);
}
private Runnable mUpdate = new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
outMEM.setText(getMemInfo());
outTASKS.setText(getTasksInfo());
i++;
mHandler.postDelayed(this, 1000);
}
};
#Override
public void onBackPressed() {
mHandler.removeCallbacks(mUpdate);
super.onBackPressed();
Log.i("MSG", "Going back");
finish();
}
You can use AsyncTask to perform operations on UI Thread while being in a Thread. Or you can use 'my favorite' , the combination of Thread and Handler. To make sure the thread is stopped when back is pressed, you can use handler.removeCallBacks(Runnable) The following example could solve your problem:
//Global
Handler h = new Handler();
private static boolean flag = true;
public void updateTextView(){
// call thread here
h.post(thread);
}
// take this thread out side so that it can be stopped with handler
Thread thread = new Thread(){
public void run(){
while(flag)
outCPU.setText(getCpuInfo());
}
}
public void onBackPressed(){
flag = false;
h.removeCallBacks(thread);
super.onBackPressed();
}
Use a shared flag somewhere in your app:
private volatile boolean wasPressed = false;
In while loop, check this flag:
while (!wasPressed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
}
});
// sleep for a while
}
On button click listener, switch wasPressed to true.
I have a Splash Screen (Logo Activity) to show the company name for 3 seconds before app starts. I start Main Activity from a thread, here is the code:
public class Logo extends Activity {
Thread t;
public boolean dead = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.logo);
t = new Thread() {
public void run() {
try {
Intent i = new Intent(Logo.this, Main.class);
Thread.sleep(3000);
if (!dead) {
startActivity(i);
}
finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
The Main Activity is called from a worked thread, is this correct? What are the differents with this code (using runOnUiThread)?
...
if (!dead) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Intent i = new Intent(Logo.this, Main.class);
startActivity(i);
}
});
}
...
I see no difference with this code in debug mode (The same threads, the same operation, etc.). Which is correct?
Starting an intent I think is not an UI operation. runOnUI thread runs UI operation on UI thread. So you can use either of thread (runOnUI or normal). May be normal thread will be good in this situation. But I would like to suggest you use timer instead.
To be honest, I don't like the Thread.sleep. PLease take a look at my solution:
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// Do your work here like... startActivity...
}
}, SPLASH_DURATION); // SPLASH_DURATION IS IN MILLISECONDS LIKE 3000
Also you can block the user to prevent the back key like this:
#Override
public void onBackPressed() {
// do nothing! disable user interaction!
}
You should use AsyncTask in "doInBackground" background thread and than sleep your thread(this thread not UIThread) "PostExecute" run on UI Thread than start your new activity
private class mSplashViewer extends AsyncTask<Void,Void,Void>{
protected void doInBackground(Void params){
Thread.currentThread().sleep(3000);
return null;
}
protected void onPostExecute(){
startActivity(...);
}
}