I'm developing my first app for Android and its supposed to be a game. Everything is fine but there's one thing I just can't wrap my head around.
In my game's "main" activity (not the first activity which starts when the app starts) I want to have a method which starts a thread which changes a buttons background color/image (go with color because I haven't made any images just yet) for one second then turns it back. I wan't the method to also have an integer parameter which makes it perform this n times. I want to be able to call like changeButtons(5); and it turns button x background blue for 1 second then waits 1 second five times.
So practically I'm trying to make a "main" thread which runs during the game and inside that thread I'm going to run this method whenever certain conditions are true (a thread which calls a thread).
So I have 2 questions. The first one is "Is this possible? " and If so can someone show me how to do it (not all of it of course but help me get started at least)? Especially I want to know if I can change a buttons background color in a thread and if so can someone show me how to write/get me started that thread?
The second question is a follow-up, if you can do this, can you have a like a boolean b which turns to true if someone presses a button and the thread can "notice" that change? For example, if the thread is running and Obama presses button x and b turns "true" in the method OnClick(View v) can I, inside my main thead have an if(b == true){Obama.moon();} and Obama will moon?
Sure you can.
In android you can use the Handler class (example available) to post actions to the event queue. You can do something like this:
final Handler handler = new Handler();
final Runnable updateRunner = new Runnable() {
public void run() {
// we are now in the event handling so to speak,
// so go ahead and update gui, set color of button for instance
}
};
new Thread(new Runnable() {
public void run() {
while (condition) {
SystemClock.sleep(1000);
handler.post(updateRunner);
}
}
}).start();
This will trigger the run in updateRunner each second.
Regarding your follow up, it can be done as well (of course :) ). You can for instance implement an observable pattern to the class that handles the button x. When pressed, notify the observers with something like observers.updateChange(b)
where you previously had a thatClassOverThere.registerObserver(this) in your main thread.
Related
Everyone knows that when you are manipulating with Database you should do that in another Thread. But I don't understand is that really necessary when you are just inserting one item for example, or when it is happening when user opens Activity or Fragment for example and data is just loading from Database you user would wait for loading ending whatever.
Maybe it even stops app a bit while creating new Thread ect.
So what do you think is that "must be" to create new Threads?
A thread should be used in a long running process that would block the UI from updating. If it's more than a second or two you might want to put it into a background thread and notify the user with a dialog or spinner or something. If you lock the UI thread for more than 5 seconds the user will be prompted with a kill or wait option by the OS.
To have a good user experience heavy works should run in another thread, in this way there aren't any lags or blocks and the user experience is better.
The time taken to create a new thread is a lot less than the time taken to performe a query or an http request or other heavy works. Maybe on your phone this time is short but on low level phone it can take more time. After 5s Android shows to the user an allert to ask if user wants kill the app or wait, this isn't good.
Another point, it's true that the user must wait data to use it BUT if you performe a request in main thread the view will blocked, if you do it in another thread thed view is smooth, you can show easy a progress bar and if user want return back the app still responsive.
I can understand that send messages beetwen threads isn't easy like do it in main thread, but if you use a bus, like OTTO Bus (http://square.github.io/otto/) and extend the bus class in this way
public class AndroidBus extends Bus{
private final Handler mainThread = new Handler(Looper.getMainLooper());
#Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
super.post(event);
} else {
mainThread.post(new Runnable() {
#Override
public void run() {
post(event);
}
});
}
}
}
In this way u can easly send messages beetwen threads
Well I just want to press a button and a countdown appears in it however when I press the button the program stops and finally shows the number 1 but doesn't show 3 or 2.
btnTurno.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
btnTurno.setText("3");
SystemClock.sleep(1000);
btnTurno.setText("2");
SystemClock.sleep(1000);
btnTurno.setText("1");
}
});
What I'm doing wrong?
First of all, Sleep should be called as Thread.sleep(x);
But on the other hand , sleep is NOT recommended since it will block the user interaction with the application.
If you want to make a countdown ( as it looks like what you are doing ), you should look at this
http://developer.android.com/reference/android/os/CountDownTimer.html
onClick is being executed in single handler message on GUI thread, so each time you change text, it overwrites previous value, so system is not able to redraw view.
Also you should not call sleep() on main gui thread, that will cause ANR - application is notresponding
Setting the text and drawing the text are separate operations that both happen on the same thread. You're setting the text three times before the framework gets the chance to draw anything, so all you see is the last change.
For this to work, you'd need to do your text updates and sleeps on a separate thread. However, you can't make UI calls directly on a different thread, so you need to post your messages.
One approach would be to create an AsyncTask, and use your code above but call publishProgress() where you're currently calling setText(). The publishProgress() call in the async thread results in onProgressUpdate() running in the UI thread; from there, you can call setText() to update the UI.
Edit: the CountDownTimer approach mentioned in a different answer is better.
How do I properly do that?
I have a stopwatch and I'm saving it's state in onSaveInstance and restoring it's state in onRestoreInstance...
Now I've following problem: if I stop the thread in onSaveInstance and the screen get's locked or turned off, onRestoreInstance is not called and the stopwatch is not continuing...
If I don't stop it, the stopwatch is running in background on and on even when the screen is off or the activity is not active anymore...
So what's the usual way to handle such a thing?
PS:
I even have a working solution, a local variable to save the running state in the onStop event and restarting the thread in the onStart event... But I still want to know if there's a "default" solution using the android system itself....
Ok. I better now understand what you're doing. I thought you were using the thread to count. Right now it sounds like you're using it to update the UI.
Instead, what you probably should be doing is using a self-calling Handler. Handlers are nifty little classes that can run asynchronously. They're used all over the place in Android because of their diversity.
static final int UPDATE_INTERVAL = 1000; // in milliseconds. Will update every 1 second
Handler clockHander = new Handler();
Runnable UpdateClock extends Runnable {
View clock;
public UpdateClock(View clock) {
// Do what you need to update the clock
clock.invalidate(); // tell the clock to redraw.
clockHandler.postDelayed(this, UPDATE_INTERVAL); // call the handler again
}
}
UpdateClock runnableInstance;
public void start() {
// start the countdown
clockHandler.post(this); // tell the handler to update
}
#Override
public void onCreate(Bundle icicle) {
// create your UI including the clock view
View myClockView = getClockView(); // custom method. Just need to get the view and pass it to the runnable.
runnableInstance = new UpdateClock(myClockView);
}
#Override
public void onPause() {
clockHandler.removeCallbacksAndMessages(null); // removes all messages from the handler. I.E. stops it
}
What this will do is post messages to the Handler which will run. It posts every 1 second in this case. There is a slight delay because Handlers are message queues that run when available. They also run on the thread that they're created on, so if you create it on the UI thread you will be able to update the UI without any fancy tricks. You remove the messages in the onPause() to stop updating the UI. The clock can continue to run in the background, but you won't be showing it to the user anymore.
I just got into Android programming, but I don't think onRestoreInstance will be called in that situation because you're not switching from one activity to another. I think your best bet is to call onPause which will then call onSaveInstance if you need it to, but use onResume which might or might not call onRestoreInstance.
In my app, I've been asked to add an auto update function. What I'm trying to do is have a timer event so that if the user hasn't pressed the update button in the last 60 seconds, do a 'refreshButton.performClick();'.
I've been searching but I can't find an example where the timer interacts with the UI. I keep getting errors like 'only the original thread that created a view hierarchy'.
If the user does press the button, I want to reset the timer.
Is this even possible?
You only can interact with aView from the UI thread.
You can make something like this in your timer task;
Define this variable in your class:
Handler handler = new Handler();
In your timer task call:
handler.post(new Runnable(){
public void run(){
refreshButton.performClick();
}
});
I think you are going in the wrong direction. Instead of trying to press the button, just set a timer to call the same method that is called once the button is pressed, it will make it way simpler, and will not involve the UI for no reason.
You can use AlaramManager class and a background service to run your code on every 60 second.
Here is an example see AlarmService_Service.java
I want to force android to wait AND continue processing something at the same time. I have seen the Thread wait function, but that just makes things hang for a while not actually letting the app do anything. Subsequent processes are simply queued up waiting their turn.
I want to force the timing of a process. This is kind of a combination between having a thread with a wait AND an asynctask
insight appreciated
public class yourActivity extends Activity{
final WebView yourWebview; //this is the webview
Context mContext = this;
public void onCreate(Bundle B){
setContentView(R.id.somethingtoshow);//this will be shown while webview working
Runnable yourRun = new Runnable(){
public void run(){
yourWebview = new WebView(mContext);
//do whatever you want with it
//loadUrl and whatever you want
//when your done
runOnUiThread(new Runnable(){
public void run(){
setContentView(yourWebView);
}
});
}
};
Thread T= new Thread(yourRun);
T.start();
}
}
'Waiting' means to put the thread in a suspended state - do you mean having the app simply do nothing until the process is completed?
You never want to make the main event thread hang or wait, that will make the user think the app is frozen. To do what you are wanting, you will probably spawn an async thread that loads the page from the main activity. The activity will continue to display whatever you had it doing last, and will not hang up or freeze while the async is going in the background. However, the user will still be able to press buttons, and might mess you up.
So to get the app to appear unfrozen and allow a process to occur in the background, you will want to enter into some loading screen or limit the user's options on the main layout. This will allow activity to continue occurring but allow the user a smooth experience.