Im writing a script which consists of a thread with a wait. If the thread get executed, it doesn't update the screen. In the script i change a picture to another picture, but it doesn't show it until I press the button again. So the main question is: After setting an different Image Resource, i need to update the screen.
Here is the code:
public void Start(View view) {
Runnable r = new Runnable() {
#Override
public void run() {
int i =0;
while(i<12) {
synchronized (this) {
try {
Setfoto(i);
Thread.sleep(1000);
Log.i(TAG, "Begonnen met loop");
Log.i(TAG, "i = " + i);
i = i +1;
} catch (Exception e) {}
}
}
}
};
Thread buckysThread = new Thread(r);
buckysThread.start();
}
public void Setfoto(int nummer) {
if (nummer == 1) {
een.setImageResource(R.drawable.eerster);
Log.i(TAG, "Foto 1 wordt rood");
} if(nummer ==2) {
twee.setImageResource(R.drawable.eerster);
Log.i(TAG, "Foto 2 wordt rood");
} if(nummer ==3) {
drie.setImageResource(R.drawable.tweer);
Log.i(TAG, "Foto 3 wordt rood");
}
}
You'll need to have some sort of way to run code on the UI thread, which is responsible for updating the contents of the screen and manipulating views.
Activity.runOnUiThread(Runnable) can be called. Any code placed in there will be run on the UI thread.
You can use runOnUiThread, AsyncTask or Thread-Handler to implement your task
Activity.runOnUiThread
runOnUiThread(new Runnable() {
public void run() {
//Do something on UiThread
}
});
Thread-Handler
Communicating with the UI Thread
AsyncTask
AsyncTask Tutorial
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);
}
});
}
}
In my application I have adapter and in this adapter I should call socket.
I want call socket in another thread and not call in MainThread.
I write socket code, but I don't know how can I call this in another thread.
My socket code :
mSocket.on("finish", new Emitter.Listener() {
#Override
public void call(final Object... args) {
try {
Constants.currentActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("socketLogs", args[0] + "");
try {
startTimer();
final FinishResponse finishResponse = new Gson().fromJson(args[0].toString(), FinishResponse.class);
countDownerLayout.setVisibility(View.GONE);
winnerLay.setVisibility(View.VISIBLE);
bidCount.setVisibility(View.GONE);
offerCount.setVisibility(View.GONE);
price.setVisibility(View.GONE);
timeView.setVisibility(View.GONE);
userPic.setVisibility(View.GONE);
winnerLay.setBackgroundColor(ContextCompat.getColor(context, R.color.white));
//if (finishResponse.getRes().getWinnerAvatar() != null && !finishResponse.getRes().getWinnerAvatar().equals("")) {
Glide.with(context)
.load(Constants.SERVER + finishResponse.getRes().getWinnerAvatar())
.placeholder(R.mipmap.ic_launcher)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(User);
/* } else {
User.setImageDrawable(ContextCompat.getDrawable(context, R.mipmap.ic_launcher_round));
}*/
edtUserName.setText(finishResponse.getRes().getWinnerName());
edtUserName.setTextColor(ContextCompat.getColor(context, R.color.black));
txtStartPrice.setText("Sell");
txtStartPrice.setBackgroundColor(ContextCompat.getColor(context, R.color.TextColorGreen));
txtStartPrice.setTextColor(ContextCompat.getColor(context, R.color.white));
try {
String[] splitDate = finishResponse.getRes().getEnd().split(" ");
String[] dateSpliet = splitDate[0].split("-");
TimeUtils timeUtils = new TimeUtils(Integer.parseInt(dateSpliet[0]), Integer.parseInt(dateSpliet[1]), Integer.parseInt(dateSpliet[2]));
txtPrice.setText(splitDate[1] + " " + timeUtils.getIranianDate());
} catch (Exception e) {
}
} catch (JsonSyntaxException e) {
}
}
});
} catch (Exception e) {
}
}
});
I write above code in getView method from Adapter.
But I want write above code in another thread , and not run in MainThread.
How can I do it?
Just create new Thread for this
Runnable runnable = new Runnable() {
#Override
public void run() {
// do stuff
}
};
new Thread(runnable).start();
I would give some recommendations concerning your code. First, it is bad to call Socket in adapter in getView. You should Call it in fragment or Activity (if you don't use MVP or some other architecture).
Next big problem is that you have current activity saved in constants
Constants.currentActivity
It will cause memory leaks, you activity will live even if you close it, and your app will have many problems with such approach.
I am making an app to do something in webview automatically.
I want to make a pause between two lines inside (for-loop) until page finished loading without using Thread.sleep because it freezing my application.
this is my code:
webview.loadUrl("http://**********");
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
for(int i=1;i<10;i++){
evaluateJavascript( "document.getElementById('select').value=" + i)
evaluateJavascript("document.getElementById('Search').click();")
//wait until finished loading
while( isloading() ){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
evaluateJavascript( "document.getElementById('any_select').value=5")
.
.
.
.
}
public boolean isloading(){
boolean isloading;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webview.evaluateJavascript("(function() { return document.getElementById(\"Loading\").style.display; })();", new ValueCallback<String>() {
#Override
public void onReceiveValue(String s) {
if(s.equals("none")){
isloading=false;
}else{
isloading=true;
}
}
});
}
if(isloading=true)return true;
if(isloading=false)return false;
}
If you don't want to use Thread.sleep then the alternative is to use AsyncTask in your application.
You can do your loading task in doInBackground() method of AsyncTask and call it using new AsyncTaskClass.execute();
You can go through it from here : http://developer.android.com/reference/android/os/AsyncTask.html
You can do something similar (instead of AsyncTask):
Edit:
Timer timer = new Timer();
while( isloading() ){
try {
timer.schedule( new TimerTask(){
public void run() {
//
}
}, delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
If you want to achieve, what i understand, that once your second line is called you want to stop there and when after 1000 ms you want to continue. You can do one thing, copy all the code after your second line and put that in run method of below code:
new Handler().postDelayed(new Runnable()
{
#Override
public void run() {
}
}, 1000);
It will execute you code after 1000ms
If you want to execute sequentially actions happening on UIThread and in backgrounds threads you should be looking for the Bolt Library by Parse/Facebook.
It apply Javascript promises to Android application.
You can go through it from here : https://github.com/BoltsFramework/Bolts-Android
I have the below code:
new Thread(new Runnable(){
public void run(){
try {
pos = Calculo.Calcular();
mostrarFrases(pos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
where mostrarFrases is:
void mostrarFrases(int pos){
Mostrar = (TextView) findViewById(R.id.Texto);
Mostrar.setText(Frases[pos*2+1], 0, Frases[pos*2+1].length);
}
It works if i haven't any thread but without it does not work. I need thread because i need to wait until Calculo.Calcular() finish its work.
Rule: You cannot manipulate UI elements outside the UI thread.
Here is the proper way to do things:
//Asuming that your activiy is named MainActivity
new Thread(new Runnable() {
public void run() {
try {
pos = Calculo.Calcular();
//Manipulate your UI elements as following
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
mostrarFrases(pos);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
You're not allowed to touch Views on any thread other than the UI thread.
To solve this, try the following:
void mostrarFrases(final int pos){
runOnUiThread(new Runnable() {
public void run() {
Mostrar = (TextView) findViewById(R.id.Texto);
Mostrar.setText(Frases[pos*2+1], 0, Frases[pos*2+1].length);
}});
}
You should not manipulate UI elements on any thread except the main UI thread.
So, in your case you got two choices: either use runOnUIThread(Runnable), or use AsyncTask and do UI manipulations in onPostExecute().
I'd go with AsyncTask - it is intended for this kind of scenarios.
UI manipulation must be done in main/ui thread. You have two options for this case:
You have a reference to your Activity object.
myActivity.runOnUiThread(...);
Bind a handler to the main thread and:
// Main thread
Handler handler = new Handler();
// Another thread
handler.post(new Runnable(){...});
I have an android application (written in java) which has two buttons (connect and request data).
When each button is clicked, a task is performed and a progress dialog appears to display how much the task has completed.
In order to show the progress dialog, when each button is clicked, the task is run on a thread.
The connect button just has one task - run on the thread. However, the request data button executes two tasks - the first task on the thread similar to the connect button but also a second task, refreshInfo() which must be run after the first task on the thread, progThread is finished.
private Button connectButton;
private Button requestDataButton;
private ProgressDialog connectionDialog;
private ProgressDialog requestDataDialog;
private ProgressThread progThread;
private int currentDialog;
public void connectClick(View view) //When the connect button is clicked
{
performAction(1); //Run the thread to perform the action
}
public void requestDownloadClick(View view) //When the request data button is clicked
{
performAction(2); //Run the thread to perform the action
refreshInfo(); //Do something else
}
private void performAction(int type)
{
currentDialog = type;
showDialog(type);
try
{
progThread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
The key method here is performAction(int type). I basically don't want this method to complete until progThread has finished running.
As you can see, I've tried progThread.join() to prevent the method from continuing until progThread has finished running, however as progThread involves displaying a Progress Dialog, running progThread.join() seems to prevent the Progress Dialog from showing, as currently when you click the button, the first task is performing but the dialog only flashes up at the end.
Can anyone think of a way to run the thread, showing the Progress Dialog as normal and then running the second method (if there is one).
I've included the thread code below incase it is needed.
private class ProgressThread extends Thread
{
final static int DONE = 0;
final static int RUNNING = 1; // Class constants defining state of the thread
private Handler progressHandler;
int mState;
int total;
ProgressThread(Handler _handler) // Constructor with an argument that specifies Handler on main thread to which messages will be sent by this thread.
{
progressHandler = _handler;
}
public void run() // Invoked automatically when the Thread starts.
{
mState = RUNNING;
updateProgressBar();
connectButton = (Button) findViewById(R.id.btnConnect);
requestDataButton = (Button) findViewById(R.id.btnRequestDownload);
while (mState == RUNNING)
{
if (currentDialog == 1)
{
try
{
doSomething();
if (something)
{
setState(DONE);
total = 100;
updateProgressBar();
removeDialog(1);
connectButton.setEnabled(false);
}
else
{
total = total + 20;
if (something has reached a limit)
{
setState(DONE);
total = 0;
updateProgressBar();
removeDialog(1);
}
}
updateProgressBar();
}
catch (Exception e)
{
}
}
if (currentDialog == 2)
{
try
{
doSomething();
total = 10;
updateProgressBar();
doSomething();
total = 70;
updateProgressBar();
if (something) //If the download info has not been got
{
setState(DONE);
total = 0;
updateProgressBar();
removeDialog(2);
runOnUiThread(new Runnable()
{
public void run()
{
connectButton.setEnabled(true);
requestDataButton.setEnabled(true);
}
});
}
else
{
total = 100;
updateProgressBar();
setState(DONE);
removeDialog(2);
runOnUiThread(new Runnable()
{
public void run()
{
requestDataButton.setEnabled(false);
}
});
}
}
catch (Exception e)
{
removeDialog(2);
setState(DONE);
runOnUiThread(new Runnable()
{
public void run()
{
connectButton.setEnabled(true);
requestDataButton.setEnabled(true);
}
});
}
}
}
}
// Set current state of thread (use state=ProgressThread.DONE to stop thread)
public void setState(int state)
{
mState = state;
}
public void updateProgressBar()
{
Message msg = progressHandler.obtainMessage(); // Send message (with current value of total as data) to Handler on UI thread so that it can update the progress bar
Bundle b = new Bundle();
b.putInt("total", total);
msg.setData(b);
progressHandler.sendMessage(msg);
}
}
final Handler handler = new Handler() // Handler on the main (UI) thread that will receive messages from the second thread and update the progress.
{
public void handleMessage(Message msg)
{
int total = msg.getData().getInt("total"); // Get the current value of the variable total from the message data and update the progress bar
switch (currentDialog)
{
case 1 :
connectionDialog.setProgress(total);
break;
case 2 :
requestDataDialog.setProgress(total);
break;
}
}
};
protected Dialog onCreateDialog(int id)
{
switch (currentDialog)
{
case 1 :
connectionDialog = new ProgressDialog(this);
connectionDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
connectionDialog.setMax(100);
connectionDialog.setProgress(0);
connectionDialog.setMessage("Connecting To The Device");
progThread = new ProgressThread(handler);
progThread.start();
return connectionDialog;
case 2 :
requestDataDialog = new ProgressDialog(this);
requestDataDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
requestDataDialog.setMax(100);
requestDataDialog.setProgress(0);
requestDataDialog.setMessage("Requesting Download Data");
progThread = new ProgressThread(handler);
progThread.start();
return requestDataDialog;
default :
return null;
}
}
Android API provides an AsyncTask class which has two methods doInBackground and onPostExecute. You'll have to override both of them, do whatever you have to do in doInBackground and when the job is done onPostExecute callback will be run.
There's also an onProgressUpdate callback which is exactly what you need.
Look at AsyncTask class. It should be able to do what you want.
http://developer.android.com/reference/android/os/AsyncTask.html
Seems other answers have you covered. AsyncTask is the way to go.
However if you want to push through with your Thread implementation, just start() the next thread at the end of the first thread's run method.
Sounds like you need to use a CountdownLatch of size 1