I have this method from a separate class wherein when the call ends, the color of my ImageView changes from red to white. Sample code below:
public void endOfCall(){
((Activity)mContext).runOnUiThread(new Runnable(){
#Override
public void run(){
TargetDetails.oncall.setVisibility(View.VISIBLE);
TargetDetails.endcall.setVisibility(View.GONE);
}
});
try{
call.endCall();
}catch (SipException se) {}
call.close();
//this is just a representation; not the actual code
if(true){
Thread.sleep(10000);
}
//new intent here
}
The problem starts when it goes to the 'if' condition where I put the Thread.sleep. It waits 10seconds before the code below gets executed
TargetDetails.oncall.setVisibility(View.VISIBLE);
TargetDetails.endcall.setVisibility(View.GONE);
I think I am missing something here regarding the Thread.sleep. I just wanna get rid of it but I'm not sure of any alternative aside from that. Help. Thanks.
Use Handler instead of putting thread to sleep.
So instead of your if(true) {.....} try this:
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override public void run() {
//new intent here
}
}, 10000);
Related
I'm trying to make a fighting screen where I have two sprites, and on top of them I have health bars with their health points written (ProgressBar with a TextView on top of it).
I also have a AnimationDrawable. And it is started inside of onWindowsFocusChanged(). I want to have the text in front of the progressBar change after the animation. So, for example, before the animation a bar has 150/150 written and after the animation I want it to change to, for example, 80/150. The thing is, whenever I try to call setText, the app crashes (I guess because onWindowFocusChanged is the last thing that's called). Is there a way to do this?
Here's a snippet of my code (number_one.start() is the starting of the animation):
private void health_bars(int points_one, int points_two){
healthBarOne.setMax(MAX_HEALTH);
healthBarOne.setProgress(points_one);
health_points_one.setText(points_one + "/" + MAX_HEALTH);
healthBarTwo.setMax(MAX_HEALTH);
healthBarTwo.setProgress(points_two);
health_points_two.setText(points_two + "/" + MAX_HEALTH);
}
public void onWindowFocusChanged(final boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus){
Thread th = new Thread(){
public void run(){
number_one.start();
try {
Thread.sleep(2000);
} catch(InterruptedException e){
}
health_bars(new_health_one, new_health_two);
try {
Thread.sleep(2000);
} catch(InterruptedException e){
}
finish();
}
};
th.start();
attackAnimation();
}
}
Thank you for your time!
EDIT:
Error Log
You cannot update UI elements from any other thread than UI. That is basically what the error is saying. To fix this, use runOnUiThread method in Android:
Thread th = new Thread(){
public void run(){
runOnUiThread(new Runnable() {
#Override
public void run() {
health_bars(new_health_one, new_health_two);
}
});
}
}
I've seen some similar questions and got some information but they stop shy of telling me enough to get it working.
What I'm trying to do is make a simple rhythm game where the player taps a button at regular intervals (ie. beats). I wanted to set up a way of signalling when to tap by having the button change colour, and since this would be a repeated task at regular intervals I want to use a timer object with a schedule method.
But when I try calling on this method it tells me that I can't change the UI in a non UI thread. I've tried a few ways to write a method in the main thread that I can call from the timer object but I get the same error every time. I'm assuming that I just have the wrong idea about what counts as being from the UI thread, so I was hoping someone could clear it up.
Here's a snippet of one way I tried it, just to show what my code looks like:
OnClickListener clickButton = new View.OnClickListener() {
public void onClick(View v) {
if (startBeat == 0){
startBeat = System.nanoTime();
timerStart.scheduleAtFixedRate((new TimerTask()
{
public void run()
{
flashButton();
}
}), 0, beatTime);
timerEnd.schedule(new TimerTask()
{
public void run()
{
unflashButton();
}
}, beatTolerance*2, beatTime);
return;
}
};
public void flashButton(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
}
public void unflashButton(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1));
}
To be clear, this is all contained within my MainActivity class along with the OnCreate class.
if you are in an activity all you need to do is use runOnUiThread() and then place the code to change the ui element in there
public void flashButton(){
runOnUiThread(new Runnable() {
#Override
public void run() {
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
}
});
}
You cannot, under any circumstances, touch a UI object from a non UI thread.
You can accomplish your intent using Handler.sendMessageDelayed
UI can only be touched by the main thread. You should post the actions you are performing on the ui thread via handler or via runOnUiThread
Try something similar to this
timerStart.scheduleAtFixedRate((new TimerTask()
{
public void run()
{
//replace MainActivity with your activity
//if inside a fragment use getActivity()
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
flashButton();
}
});
}
}), 0, beatTime);
If you are in an Activity you could surround flashButton() with an runOnUiThread.
...
runOnUiThread(new Runnable(){
public void run(){
flashButton();
}
});
...
use android.os.Handler Class. Change your code as follows:
private Handler handler=new Handler();
public void flashButton(){
handler.post(new Runnable(){
public void run(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
}
});
}
public void unflashButton(){
handler.post(new Runnable(){
public void run(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1));
}
});
}
As you can see in the title, I'm trying to not use runOnUiThread each time I need it. I'll explain what I mean later, but first, here is my current code (part of):
private void filePaste()
{
final File src = new File(FileClip); //Source file (as a string)
final File dest = new File(myPath.getText()+"/"+src.getName()); //Destination file
final ProgressDialog dlg = new ProgressDialog(AppContext);
final Thread copythread = new Thread(new Runnable() {
public void run() {
if(FileClip==null)
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_EmptyClip));
}
});
else
{
if(src.canRead()){
if(!src.isDirectory())
{
try{
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src), 8192);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
long pos = 0;
long read = 8192;
byte[] data = new byte[(int)read];
while(pos<src.length()){
int bytes = in.read(data, 0, (int)read);
if(bytes>-1) {
out.write(data,0,bytes);
in.skip(read);
in.mark((int)pos+bytes);
in.reset();
dlg.incrementProgressBy(bytes);
pos+=bytes;
}
}
Main.this.runOnUiThread(new Runnable() {
public void run(){
dlg.dismiss();
}
});
in.close();
out.close();
}catch(final Exception e)
{
Main.this.runOnUiThread(new Runnable() {
public void run(){
alert("filePaste():\n"+e);
}
});
}
if(Moving==true) {
boolean q = src.delete();
if(q==true)
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_MoveOK,src.getName()));
}
});
else
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_MoveNO,src.getName()),1);
}
});
Moving = false;
}
else {
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_CopyOK,src.getName()));
}
});
}
}
}
else
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_CopyNO,src.getName()));
}
});
FileClip = null;
Main.this.runOnUiThread(new Runnable() {
public void run(){
getDir(myPath.getText().toString());
}
});
}
}
});
dlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dlg.setTitle(Moving?getString(R.string.moving):getString(R.string.copying));
dlg.setMessage(src.getName());
dlg.setCancelable(true);
dlg.setButton(DialogInterface.BUTTON_NEGATIVE, getString(android.R.string.cancel), new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which) {
dlg.cancel();
}
});
dlg.setOnCancelListener(new DialogInterface.OnCancelListener()
{
#Override
public void onCancel(DialogInterface dialog) {
copythread.interrupt();
if(dest.exists())
dest.delete();
}
});
dlg.setMax((int)src.length());
dlg.show();
copythread.start();
}
What this code does is try to copy a given file (stored as a string in FileClip).
As you can see, the code is quite long, because the excessive use of runOnUiThread. I want to know how to move all of the
Main.this.runOnUiThread(new Thread(new Runnable()
public void run()
{
//Simple stuff for 6 lines
}
));
to a class or something. I was thinking of
public class runAtUI implements Runnable
But I stop at that point, I don't know how to make constructors. I hope you know what I mean with this; something like:
new runAtUI()
{
//This makes less lines IMO, and could be executed
}
*Note: I looked for topics about this but all saying the same, use the runOnUiThread. I know it's ok but for something short (like displaying a toast -using toast() with the same purpose- or an alert -again, but with alert()-) it's pointless.
PS: This is for a simple file manager that I am doing and will not be published on Google Play because of the lack of money, and I don't want to use ads either (breaking the "simplicity" in the name). Yes, I know that there are free and adsless (that word exists?) and better apps but I wanted to learn how to make one n_n;
Any information, idea or guide will be appreciated.
Edit #2: Thank you to all that answered quickly! The samples that you provided will work for now but I'd like it to be more flexible. Like eval("code as string") in javascript (without the code being a string).
I'll consider this question answered but leave it open to let people give some more ideas ;D
Edit #3: Okay, first, sorry for the long time no response. Second, I'm adding links to the current code as it is now, from 123 lines (this one) to 77 lines of code at pastebin. I'm also adding the code for uithread.
About the app: If you want it for testing, see how it is right now or anything, drop me a mail and I'll send it to you ;)
You could create a utility class to encapsulate the steps of creating a runnable to be run by the UI thread and invoke Toast. Here's a simple implementation:
public abstract class ToastUtils {
/**
* Displays a toast message, making sure that the toast is always invoked from the main (ui) thread.
* #param act Calling Activity
* #param text Toast text
* #param duration Toast duration
*/
public static void showToast(final Activity act, final String text, final int duration) {
act.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(act, text, duration).show();
}
});
}
}
Using this class you would do this to toast wherever necessary:
ToastUtils.showToast(this, "some text", Toast.LENGTH_SHORT);
You can create a Handler in activity:
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case R.string.cancel:
//show toast
break;
default:
break;
}
}
};
And use it from your thread like:
handler.sendEmptyMessage(R.string.cancel);
From http://developer.android.com/guide/components/processes-and-threads.html:
However, as the complexity of the operation grows, this kind of code
can get complicated and difficult to maintain. To handle more complex
interactions with a worker thread, you might consider using a Handler
in your worker thread, to process messages delivered from the UI
thread. Perhaps the best solution, though, is to extend the AsyncTask
class, which simplifies the execution of worker thread tasks that need
to interact with the UI.
... skipping ahead ...
You can call publishProgress() at anytime in doInBackground() to
execute onProgressUpdate() on the UI thread
It looks to me like this is what you want to do.
With regard to your other question (you should try to ask only one question per topic), copying files in Java is kind of a solved problem. Among threads on SO, I think this one has some pretty good answers: Standard concise way to copy a file in Java?
I have a OnClickListener, like this one:
submit.setOnClickListener(new OnClickListener() {
if(connected) {
final ProgressDialog pd = ProgressDialog.show(this, "", "Please Wait..", true);
new Thread() {
public void run() {
//DOES SOME CALCULATION INSIDE HERE
pd.dismiss();
}
}.start();
showPriceDialog(price);
}
else
Toast.makeText(this, "No Network!", Toast.LENGTH_LONG).show();
});
How can I know that the thread is finished? I know that there is a function isAlive() that I can use if I construct my thread like this: Thread t = new Thread(); t.isAlive(); But how can I know if my thread is still alive, the way I've constructed my code? I'am aware that this could be solved by using an AsyncTask.
Im not sure I follow what youre asking why not:
Thread t = new Thread() {
public void run() {
...
}
}
t.start();
Alternatively You could use the Activity's runOnUiThread() in the thread:
new Thread() {
public void run() {
runOnUiThread(new Runnable() {
public void run() {
//set text here
}
});
}
}
But to be honest with you both of these would not be any better than using an AsyncTask and I would highly recommend going that route.
EDIT Additionally you will not be able to dismiss a progress dialog from a separate thread.
So I have some simple code but it seems to not be working.. any suggestions?
I just want an image to show after a button is pressed then become invisible after 2 seconds.
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
firstImage.setVisibility(ImageView.VISIBLE);
// delay of some sort
firstImage.setVisibility(ImageView.INVISIBLE);
}
}
The image never shows, it always stays invisible, should I be implementing this in another way? I've tried handlers.. but it didn't work, unless I did it wrong.
Never make your UI thread sleep!
Do this:
final Handler handler = new Handler();
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
firstImage.setVisibility(ImageView.VISIBLE);
handler.postDelayed(new Runnable(){
public void run(){
firstImage.setVisibility(ImageView.INVISIBLE);
}
}, DELAY);
}
}
Where you would set DELAY as 2000 (ms).
Well, you will need to add a delay between the two lines. Use a thread or a timer to do this.
Start a thread on click of a button. In the run method, change the ImageView's visibility to VISIBLE, then put the thread to sleep for n secs, and then change then make it invisible.
To call the imageView's setvisibility method, you will need a hanlder here.
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
image.setVisibiliy(VISIBLE);
Thread.sleep(200);
image.setVisibility(INVISIBLE);
}
});
I know this question has already been answered, but I thought I would add an answer for people who like me, stumbled across this looking for a similar result where the delay was caused by a process rather than a "sleep"
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
firstImage.setVisibility(ImageView.VISIBLE);
// Run the operation on a new thread
new Thread(new Runnable(){
public void run(){
myMethod();
returnVisibility();
}
}).start();
}
}
private void myMethod() {
// Perform the operation you wish to do before restoring visibility
}
private void returnVisibility() {
// Restore visibility to the object being run on the main UI thread.
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
firstImage.setVisibility(ImageView.INVISIBLE);
}
});
}