performClick() not working because it's in a different thread - android

So essentially I want to simulate a button click in my android app, using a timer.
When the timer goes off, I do find the button then try using performClick() which crashes and closes the app.
The log of course made the problem quite clear: "Only the original thread that created a view hierarchy can touch its views." Which makes total sense. Duh!
But I assume that since it's all my app there is a way to properly do this?

You can use runOnUiThread() in a background Thread in order to update the UI Thread:
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
//Run your functions here
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}

Related

Which view operations are allowed on non-UI thread?

This post says (in reference to the Android Doc) that any method on a view has to be called from the UI thread. However, I have not ran into any problem yet, though I set the OnClickListeners of Buttons in a non-UI-thread. Is this a situation of "You realy should not do this, even though you can." or is there a subset of methods that can actually be called from non-UI-threads?
If the latter is true, which operations are part of the subset?
EDIT
Example code:
Thread setUpActivity = new Thread(new Runnable() {
#Override
public void run() {
while (serviceConnection.getAppController() == null){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
btAddTag.setOnClickListener(onAddTag);
btGo.setOnClickListener(onGo);
runOnUiThread(new Runnable() {
#Override
public void run() {
setUpSpinner();
}
});
}
});
setUpActivity.start();
A quick answer would be:
You shouldn't do write operations on UI components from outside of the UI thread. This is because the UI components are not thread safe. And even if you might get away with a minor change on a device or emulator, you might get in trouble on other devices or in different situations.
Write operations would be:
set text, sizes, colors, etc.
I guess setting just a click listener won't get you into problems if you are not doing UI updates in the callback method(onClick..). But as a good practice I would advice not to do that(set the click listener on a non UI thread).
You can set listeners on non UI thread. Even if you really do not want it on non UI thread but on UI thread try using post method on view which will call on UI thread.
Usage :
view.post(new Runnable() {
public void run() {
// your action here on UI thread.
}
});

ProgressBar running faster after each onclick in android

I am Stuck here with this application in android. In my application i am trying to implement a progressbar which shows timer for certain seconds. When the Button is clicked the timer should refresh and again start from 0 in progressBar. For this I am using Thread.
The Problem is, When I Click the button the Thread calls the timer function and each time the thread is getting faster and faster. I couldn't resolve it and not having any idea what is going in background.
This is my code for Timerfunction
public void setTimer()
{
prog=0;
progress.setProgress(prog);
if(flag){
t= new Thread(new Runnable(){
public void run()
{
while(prog<100)
{
prog+=1;
handle.post(new Runnable(){
public void run()
{
progress.setProgress(prog);
if(prog==progress.getMax()&& flag){
call_fun();
}
}
});
try
{
Thread.sleep(time);
}
catch(InterruptedException e)
{
Log.i("Error", null);
}
}
}
});
t.start();
}
}
I called this function in another function called RandomGeneration. If the button is clicked the randomgeneration is called and the set timer is activated everytime. But the progressbar is running faster after every click. It is constantly running in the same specific time. For example if it runs for 3 seconds in the first click, its running 2 seconds in the second click and getting faster considerably.
Can anyone please try to find what is happening in this code.
Thanks in advance..!!
From what I see a new Thread is being created everytime you click the button.
Maybe try to check if t is already running and if so update it's logic to set progress to 0?
Also, what does if(flag) do?

How to change android screen during function

I am trying to change the screen of an app during a function is running.
public void StartRecording(View view)
{
start_button.setEnabled(false);
stop_button.setEnabled(true);
recording = true;
while(recording==true)
{
// Here is a code that changes many views on the screen
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
function StartRecording() is called by clicking the start_button in the xml file.
recording is set to false when clicking the stop_button.
The views on the screen should change, wait a second, change again, wait a second and so on.
But what happens is that the function waits until the loop is finished and then shows only the final screen change. What am I doing wrong?
Thanks ahead : )
Edit:
I tried using Handler and it has the same result..
private final Handler mHandler = new Handler(Looper.getMainLooper())
{
public void handleMessage(Message msg)
{
tv.setText((String) msg.obj);
}
};
tv is a textView. Instead of using tv.setText just above the try{} in the code above, I sent a message to mHandler to change the text, and it still changes it only after the whole startRecording function is over.
Now, what am I doing wrong? :/
What am I doing wrong
you are calling sleep wait the UI Thread, that is responsible for drawing your views and handle events. If you want to schedule 10 different redrawing of your views, you can use and Handler and its postDelayed method

how to stop a running thread with button toggle (android app)

I finally got my app working, i just have one issue which i would like to correct.
I have a button which controls a thread that runs a couple function in the background. The functions in the background eventually stop the thread whenever a certain value is reached. What i am having issues doing is pressing that same button again to just stop the thread manually. Currently I can only start the thread and wait for itself to finish. I am able to do other things in the app, so the thread is running on its own, i just want to kill it manually.
public void onMonitorClick(final View view){
if (isBLEEnabled()) {
if (!isDeviceConnected()) {
// do nothing
} else if (monitorvis == 0) {
showMonitor();
DebugLogger.v(TAG, "show monitor");
//monitorStop = 4;
Kill.runThread(); // I want a function here that would kill the
// thread below, or is there something that
// can be modified in runThread()?
// I did try Thread.Iteruppted() without luck
shutdownExecutor();
} else if (monitorvis == 1) {
hideMonitor();
DebugLogger.v(TAG, "hide monitor");
monitorStop = 0;
runThread(); //The running thread that works great on its own
}
}
else {
showBLEDialog();
}
}
private void runThread() {
new Thread() {
int i;
public void run() {
while (monitorStop != 3) { //This is where the thread stops itself
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
((ProximityService.ProximityBinder) getService()).getRssi();
rssilevel = ((ProximityService.ProximityBinder) getService()).getRssiValue();
mRSSI.setText(String.valueOf(rssilevel) + "dB");
detectRange(rssilevel);
}
});
Thread.sleep(750);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
On first look, you could simply set monitorStop = 3, which would cause the thread to eventually stop after it's timeout completes.
The problem with this, is that I presume if you push the button again or your code modifies monitorStop at some point in the future, then the thead you wanted dead, might stay alive. ie: monitorStop will need to stay equal to three for at least 750ms to assure the thread will comlete it's loop and die.
The correct way to do this would be to create your thread as a new class with it's own monitorStop parameter. When you create the thread, you would keep a reference to it and modify the thread's monitorStop parameter. This way the thread would finish without interruption. If you wanted to create a new thread, then this would not affect the old thread from finishing appropriately.

Android: Rotating Button on a thread

Could someone provide a sample implementation for rotating a button on a thread ? As of now I am rotating my button on the UI thread using the following code:
Animation ranim = (Animation) AnimationUtils.loadAnimation(getBaseContext(),
R.anim.rotation);
buttonRotate.setAnimation(ranim);
following should work for you.
Thread thread = new Thread()
{
#Override
public void run() {
try {
Animation ranim = (Animation) AnimationUtils.loadAnimation(getBaseContext(),
R.anim.rotation);
buttonRotate.setAnimation(ranim);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
you might eventually have to create an AsyncTask which can run independently without disturbing UI Thread.
in your UI thread define
Handler mainHandler = new Handler();
then inside your thread, use this:
mainHandler.post(new Runnable()
{
public void run()
{
//your piece of code
}
});
This has served me well so far in several cases, hope it does for you too! :D
EDIT:
mainHandler.post(new Runnable()
{
public void run()
{
while(someBoolean==true)
{
//your piece of code
}
}
});
if you'd define 'someBoolean' inside your class, just like you did with the handler, the thread is supposed to get it, I believe.
this way, after processing your data, simply set someBoolean to false, and the rotating stops.
Unfortunately I don't have access to my IDE at the moment, so I am going to list the steps for you rather that put buggy code up here.
1) Implement "AnimationListener" in the same class that extends Activity.
2) Set a click listener on your button.
3) Create an AsyncTask class.
4) Override doInBackground (of AsyncTask) and place your resource intensive logic there.
5) In onAnimationStart (of AnimationListener), implement the logic to call your AsyncTask, i.e. new MyTask().execute();
6) Define the animation and set it to your button.
This is how it should go: You click the button, onAnimationStart is called, your AsyncTask logic and animation both start. This way you can have your button rotate at the same that that your background thread is performing resource intensive operations - i.e. concurrently.
And just for fun, you may want to disable your button from being clicked again before the background task has finished.
Sorry for the lack of code, but this should be pretty straight forward from here.

Categories

Resources