I have implemnted progressbar in my small game like below
gameProgressBar =(ProgressBar)findViewById(R.id.GameProcess);
thrd = new Thread(progressBarThread);
thrd.start();
}
//Progress bar function
private Runnable progressBarThread = new Runnable(){
public void run() {
// TODO Auto-generated method stub
while (GameProgressCount<60){ //60 = 1 minute
try{
myHandle.sendMessage(myHandle.obtainMessage());
Thread.sleep(1000);
}
catch(Throwable t){
}
}
thrd.stop();
}
Handler myHandle = new Handler(){
#Override
public void handleMessage(Message msg) {
GameProgressCount++;
gameProgressBar.setProgress(GameProgressCount);
}
};
My question is that when i click on back/home button of the device, app is getting minimized (or goes previous screen) but the Progress bar thread would be running in the background. is it possible to pause the thread and resume when i minimize/open the app screen.
Thanks
You can pause the Thread in the OnPause method of the Activity and you can resume the Thread on OnResume method of the Activity which is pretty stright forward. Now if you wanted to Keep the GameProgressCount intact and wanted to Resume back from where it has left then you can use SharedPreference to store the value, when you resume back use the same value to start with.
Related
I have an app with a title screen. When the app first starts, I have an onCreate method that contains the following code:
setContentView(R.layout.title_screen);
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
setContentView(R.layout.main_screen);
}
}, 2000);
When I run my app and press the back button while on the main_screen layout, it closes the app (as it should). However, when I reopen the app, it displays the title_screen layout for two seconds again even though the app is already running. How can I prevent this?
This will prevent the delay appearing again when resumed:
private static boolean flag = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!flag){
setContentView(R.layout.title_screen);
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
setContentView(R.layout.main_screen);
}
}, 2000);
flag = true;
} else {
setContentView(R.layout.main_screen);
}
}
Btw, if your app was on background and it is calling onCreate again while being resumed, it means that it is killed by the OS. Therefore it is normal to have the initial delay again.
What I would do is to implement two different activities first one showing title_screen and the second which is started after 2s should show your main screen.
After looking at your code I can see that you ALWAYS start with title_screen then after 2s, you change to main_screen. Therefore, when you press back, that means you finish your activity. When you re-open your app, onCreated is called again, and it run every line of code as the previous opening.Of course, there's no difference in 2 times you open your app. To overcome it, I recommend to use SharedPreference to store the flag to check main_screen or title_screen.
I'm trying to make a simple airplane game to build my skills and have some fun. But I've hit a roadblock with Threads, Loopers, and message queues when trying to pass a message from an onTouch event of a TextView to the Thread drawing my airplanes. I'm going to try to include only the essential bits of code below and use "..." to indicate omitted lines.
I'm drawing in a separate, good old-fashioned android thread. Here's the constructor of the Thread:
public class BenThread extends Thread {
...
public BenThread(SurfaceHolder surfaceHolder, Context context,
BenSurfaceView surfaceView) {
this.surfaceHolder = surfaceHolder;
this.context = context;
this.surfaceView = surfaceView;
this.isRunning = false;
Bitmap planeImage = BitmapFactory.decodeResource(
context.getResources(), R.drawable.fighters);
airplane = new Airplane(50, 50, 2, 0, planeImage);
}
Before I show the run method, note that there's a SurfaceView that creates and starts the Thread when the SurfaceChanged() is called. In the onCreate() of my main Activity, I create a final instance of my custom SurfaceView:
final BenSurfaceView surfaceView = (BenSurfaceView) findViewById(R.id.surfaceView);
In the UI layout, there a TextView sitting at bottom center with an OnTouchListener hooked up. In onTouch(), for MotionEvent.ACTION_DOWN, the following line is called:
surfaceView.thread.handler.sendEmptyMessage(1);
Back to the thread class, the handler for this empty message is created in the run method, along with the Looper creation:
public void run() {
super.run();
Looper.prepare(); // Creates a Message Queue for the thread
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new IdleHandler() {
#Override
public boolean queueIdle() {
Looper.myLooper().quit();
return false;
}
});
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.i("HANDLING", "SOMETHING");
}
};
Looper.loop();
while (isRunning) {
currentTime = System.currentTimeMillis();
// spin in a while loop for a while
while ((currentTime - previousTime) < REFRESH_RATE) {
currentTime = System.currentTimeMillis();
}
airplane.move();
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
surfaceView.draw(canvas);
airplane.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
Now if I run as is, I get a nice little animation of airplanes moving across the screen.
But, when I click the Button at the bottom, I see from the log that I sent a message to a dead thread. Well, I guess I killed it in the IdleHandler. So now let me comment out the quit method:
// Looper.myLooper().quit();
Now my app looks considerably less exciting:
But, when I click the Button at the bottom and look at the log, there is proof that my message has been handled! So the big question is, how can I run the message loop and still see my animation?
After you call Looper.loop(), it should not return until the thread is ready to stop. Having your game loop after the Looper.loop() call doesn't make sense. At that point the thread is "dead" in the sense that the Looper is no longer listening for messages.
If you want your thread to run in while (isRunning), do that. If you want it to be message-driven, do that. Don't try to do both in the same thread. (And please don't spin on the CPU -- eats up battery quickly on a mobile device.)
You can find some notes about game loops, and about SurfaceView and threading, in appendices A and B of this article. There are various examples of animated rendering using Handler in Grafika. For example, the "record GL app" activity uses Choreographer to send a message to the render thread whenever it's time to draw.
It is because of the IdleHandler(). It is executed immediately quitting you looper. I commented your code:
public void run() {
super.run();
Looper.prepare();
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new IdleHandler() {
// This is executed immediately when the looper is idle.
// So this looper is quitted
// and thread starts to execute "while" loop
#Override
public boolean queueIdle() {
Looper.myLooper().quit();
return false;
}
});
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.i("HANDLING", "SOMETHING");
}
};
Looper.loop(); // Take into account that this function is blocking
// This "while" loop is executed after the looper is quitted from IdleHandler
// So why your game is running
// When you click your button it tries to send message to quitted looper
// and you get the corresponding error message
while (isRunning) {
currentTime = System.currentTimeMillis();
// spin in a while loop for a while
while ((currentTime - previousTime) < REFRESH_RATE) {
currentTime = System.currentTimeMillis();
}
airplane.move();
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
surfaceView.draw(canvas);
airplane.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
When you commented the IdleHandler the thread executes Looper.loop() (it is blocking) method so the while loop is not being reached.
After the clarification from #fadden and #armansimonyah13, I dropped the misguided attempt to send messages between threads. In the main Activity, rather than sending a message to the thread like so:
surfaceView.thread.handler.sendEmptyMessage(1);
and trying to handle it in the thread, I simply update public data in the thread (from within the TextView's onTouch handler):
surfaceView.thread.airplane.setVelocity(8);
Now when you click the TextView at the bottom, the planes speed up. That's the kind of UI-thread to rendering-thread interactivity I was going for.
By the way, now the run loop looks like:
#Override
public void run(){
while (isRunning) {
airplane.move();
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
surfaceView.draw(canvas);
airplane.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I am following this tutorial to have a loading screen in my program. The tutorial says my activity should Sleep() using the Sleep() command, however it does not recognize Sleep() as a function and provides me with an error, asking if I would like to create a method called Sleep().
Here is the code sample:
public class LoadingScreenActivity extends Activity {
//Introduce an delay
private final int WAIT_TIME = 2500;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
//Simulating a long running task
this.Sleep(1000);
System.out.println("Going to Profile Data");
/* Create an Intent that will start the ProfileData-Activity. */
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
}, WAIT_TIME);
}
}
You can use one of the folllowing methods:
Thread.sleep(timeInMills);
or
SystemClock.sleep(timeInMills);
SystemClock.sleep(milliseconds) is a utility function very similar to Thread.sleep(milliseconds), but it ignores InterruptedException. Use this function for delays if you do not use Thread.interrupt(), as it will preserve the interrupted state of the thread.
The function is Thread.sleep(long).
Note, however, that you should not perform a sleep on the UI thread.
The code you posted is horrible. Please don't use that on an actual device. You will get an "Application Not Responding" error if you run something similar to this.
If you're using Handlers, keep in mind that a Handler is created on the thread where it runs. So calling new Handler().post(... on the UI thread will execute the runnable on the UI thread, including this "long running operation". The advantage is that you can create a Handler to the UI Thread which you can use later, as shown below.
To put the long running operation into a background thread, you need to create a Thread around the runnable, as shown below. Now if you want to update the UI once the long running operation is complete, you need to post that to the UI Thread, using a Handler.
Note that this functionality is a perfect fit for an AsyncTask which will make this look a lot cleaner than the pattern below. However, I included this to show how Handlers, Threads and Runnables relate.
public class LoadingScreenActivity extends Activity {
//Introduce a delay
private final int WAIT_TIME = 2500;
private Handler uiHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHandler = new Handler(); // anything posted to this handler will run on the UI Thread
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
Runnable onUi = new Runnable() {
#Override
public void run() {
// this will run on the main UI thread
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
};
Runnable background = new Runnable() {
#Override
public void run() {
// This is the delay
Thread.Sleep( WAIT_TIME );
// This will run on a background thread
//Simulating a long running task
Thread.Sleep(1000);
System.out.println("Going to Profile Data");
uiHandler.post( onUi );
}
};
new Thread( background ).start();
}
use Thread.sleep(1000);
1000 is the number of milliseconds that the program will pause.
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
Keep in mind: Using this code is not recommended, because it is a delay of time but without control and may need more or less time.
i have an activity or screen which contains mainly 3 views (ex.textview1,textview2,textview3) and a progress bar.
While progress bar running or loading if i click on either of textview1,textview2,textview3,
corresponding next activity or screen is opening.
But i want like while progress bar running relevant screen should disable(not tappable) or should not move to next screen if i click on any of these views.
please reply with an example
Just create a boolean for when the you have something in progress and then check for it in you onClickListener.
boolean isRunning;
#Override
public void onClick(View v) {
if(isRunning)
return;
//handle code normally
}
You can use AsyncTask class to do this
FYI, AsyncTask is known as Painless Threading in Android.
onCreate() {
...
MyTask task = new MyTask();
task.execute();
}
class MyTask extends AsyncTask
{
onPreExecute() {
// disable your views here
}
doInBackground() {
// do your loading here in background
}
onPostExecute() {
// enable your views to start activities
}
}
I have a problem and that is my SplashScreen I have. It is built as an intro and after 3 seconds it shows the main menu of the program.
Anyway, if I press down Back or Home button during the time the SplashScreen shows, it closes, but the activity I have chosen to follow after the SplashScreen will still run after the three seconds.
My code: *****UPDATED CODE*****
Handler ur = new Handler();
myRun = new Runnable() {
public void run() {
mainIntent = new Intent(SplashScreen.this,MyApp.class);
SplashScreen.this.startActivity(mainIntent);
SplashScreen.this.finish();
overridePendingTransition(R.anim.fadein,
R.anim.fadeout);
}
};
ur.postDelayed(myRun, SPLASH_DISPLAY_TIME);
}
protected void onStop() {
super.onStop();
ur.removeCallbacks(myRun);
}
Even if I have an onStop() in this SplashScreen, the next activity will still run after the SPLASH_DISPLAY_TIME.
Since I changed the code I got Force Close after I pressed the Home button and the SplashScreen disappeared, also, I cannot launch my second activity.
Try to do it this way:
private static final int SPLASH_DISPLAY_TIME = 3000;
Handler ur = new Handler();
Runnable yourRunnable = new Runnable() {
public void run() {
mainIntent = new Intent(SplashScreen.this,MyApp.class);
SplashScreen.this.startActivity(mainIntent);
SplashScreen.this.finish();
overridePendingTransition(R.anim.fadein,
R.anim.fadeout);
}
};
ur.postDelayed(yourRunnable, SPLASH_DISPLAY_TIME);
Then, somewhere on onDestroy or whatever method you use to detect when your splashscreen activity get closed:
// somewhere
ur.removeCallbacks(yourRunnable);