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.
Related
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 a thread that will do some processing, then has runnable code which will display the results on the screen. The issue is that if the user presses the back arrow while the runnable is between two lines of display code, the next line will crash as the activity no longer exists.
The below code accomplishes the goal, but I hate having if statements before each line. Is there a better way?
#Override
public void onBackPressed() {
super.onBackPressed();
imgThread.interrupt();
}
private void processImage(){
final Handler mHandler = new Handler(Looper.getMainLooper());
progress = new ProgressDialog(this);
progress.setMessage("TEXT");
progress.setIndeterminate(true);
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progress.show();
imgThread = new Thread(){
#Override
public void run() {
//Process the image a bit
mHandler.post(new Runnable() {
#Override
public void run() {
if(!imgThread.isInterrupted())
imageView.setImageBitmap(mDisplayBitmap);
if(!imgThread.isInterrupted())
progress.setMessage("TEXT TEXT");
if(!imgThread.isInterrupted())
progress.show();
}
});
//More processing
mHandler.post(new Runnable() {
#Override
public void run() {
if(!imgThread.isInterrupted())
addScreenListener();
if(!imgThread.isInterrupted())
determineHelpToast("TEXT TEXT TEXT", Toast.LENGTH_LONG);
if(!imgThread.isInterrupted())
progress.dismiss();
}
});
}
}; imgThread.start();
}
The really safe way to do this is to modify your Runnable so that it never references the Android Context (Activity, etc.).
The easiest way to do this is to communicate changes to the Activity via an event bus.
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
public class TestingActivity extends Activity implements View.OnClickListener
{
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1);
ScheduledFuture now = null;
public void onCreate(Bundle savedInstanceState)
{
//oncreate
}
public void rollthedice()
{
//rollthedice
}
public void onClick(View view)
{
Runnable runner = new Runnable()
{
public void run()
{
rollthedice();
}
};
if(view.equals(continuous))
{
if(now == null)
now = scheduler.scheduleAtFixedRate(runner, 0, 250, TimeUnit.MILLISECONDS);
else
return;
}
if(view.equals(stop))
{
if(now != null)
{
now.cancel(true);
now = null;
}
else
return;
}
if(view.equals(roll))
rollthedice();
if(view.equals(exit))
System.exit(0);
}
I used it in a Java application and it worked fine, i put it into android project and it doesnt work i want the continuous button to run rollthedice() continuously and the stop button to stop it then continuous to start it again and stop back and forth
Are you sure the onCLick is executed?
Did you call
continuous.setOnClickListener(this);
stop.setOnClickListener(this);
etc?
Because you need to add it some while loop with a flag, try this:
public void run()
{
while (runningFlag){
//do something here
}
}
At the start you need to set the flag to true and then start the thread, and when you want it to stop set the flag to false.
You can have a while loop and set the condition to true to stop it (because of the !). You should also highly consider having the rolling in a separate thread. If you do you may or may not need a handler.
boolean mPaused = false;
while(!mPaused) {
doSomething();
}
//to stop it set mPaused = true
//to resume call the method again
Handler
//called by
Message msg0 = new Message();
msg0.obj = "someting";
handler.sendMessage(msg0);
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.obj.equals("something")) {
doSomething();
}
}
};