I am created a Stopwatch app with using Chronometer and ViewModel the app is working well until the configuration change. when the rotation of the screen the Stopwatch is reset into 00:00.
this is part of StopwatchTabFrag.java.
stopwatchTabViewModel.buttonIcon.observe(getViewLifecycleOwner(), new Observer<Integer>() {
#Override
public void onChanged(Integer imgId) {
switch (imgId){
//when the icon is changed to pause (or) when user clicks play icon then Stopwatch is start.
case R.drawable.ic_round_pause_circle_filled_24:
binding.stop.setVisibility(View.VISIBLE);
binding.startPause.setImageResource(imgId);
stopwatchTabViewModel.startStopwatch(stopwatchChronometer);
break;
//when the icon is changed to start (or) when user clicks pause icon then Stopwatch is pause.
case R.drawable.ic_round_play_arrow_24:
binding.startPause.setImageResource(imgId);
stopwatchTabViewModel.pauseStopwatch(stopwatchChronometer);
break;
case R.drawable.ic_round_stop_24:
binding.stop.setVisibility(View.GONE);
stopwatchTabViewModel.stopStopwatch(stopwatchChronometer);
}
}
});
I am using Observer to whenever changing the particular button icon it was execute this particular task.
this is part of StopwatchTabViewModel.java.
public void startStopwatch(Chronometer chronometer){
if (!isRunning.getValue()){
chronometer.setBase(SystemClock.elapsedRealtime()-pauseOfset.getValue());
chronometer.start();
_isRunning.setValue(true);
}
}
public void pauseStopwatch(Chronometer chronometer){
if (isRunning.getValue()){
chronometer.stop();
_pauseOfset.setValue(SystemClock.elapsedRealtime()-chronometer.getBase());
_isRunning.setValue(false);
}
}
public void stopStopwatch(Chronometer chronometer){
chronometer.setBase(SystemClock.elapsedRealtime());
_pauseOfset.setValue(0L);
chronometer.stop();
//Reset the icon to Start
_buttonIcon.setValue(R.drawable.ic_round_play_arrow_24);
}
I implemented the Stopwatch task methods in ViewModel class. I don't know if this is correct or wrong.
I am waiting for your answers.
add this line to your Activitys declaration in manifest:
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
it will prevent Activity destroy on rotation (thus also your chrono), you have to handle rotation in onConfigurationChanged method call by yourself (you probably won't need to do anything in your case)
HERE you have some info about configuration changing.
Related
How can i detect a long press on the whole activity? since onLongClickListener is only for individual views.I want to run a method everytime the user longpress the screen
You can override your activity's dispatchTouchEvent() method. You also need a gesture detector in order to determine which motion events are 'long presses'. Put this into your activity:
final GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
public void onLongPress(MotionEvent e) {
// The code for when a long-press happens
}
});
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
return super.dispatchTouchEvent(event);
}
Please note that I did not test the above code.
A long press is actually multiple registers of the key. So you could do a while loop on the input and as long as input is not NULL run the method you want. If I understood you correctly this should do the trick...
i'm new of libgdx and this is my first app, but i have the problem with screen switch.
i have set main class like this:
public class MyClass extends Game {
MenuClass menuClass;
ActionGame actionGame;
#Override
public void create() {
menuClass = new MenuClass(this);
actionGame = new ActionGame(this);
setScreen(actionGame);
}
}
and method of ActionGame class like this:
....
#Override
public void pause() {
game.setScreen(game.menuClass);
}
#Override
public void resume() {
this.show();
this.render(Gdx.graphics.getDeltaTime());
}
....
and method of menuClass.java like this, when touch Play button:
....
#Override
public void resume() {
game.actionGame.resume();
}
....
When i touch play button i wish that actionGame class return in action render, but the render don't start.
I have try with setScreen, but this restart my screen, this not good.
Help
Thanks
You're using resume incorrectly. It is something that is always called when your app is brought back to screen. You should never call resume() on any of your classes yourself. It is called by Libgdx when your app is brought back to the foreground.
It is correct that you should switch to the menu screen in the pause method, because gamers expect the game to automatically go to a menu or pause screen when the app goes off screen. But you do not want to be automatically switching back to the game when the app comes back on screen.
The resume method would only be used for reloading stuff that you unloaded in pause (which you probably don't need to do), or to restart music, or something like that.
Your Play button definitely should not be calling resume. It should be calling setScreen(actionGame);. And there should be nothing in any of your resume methods as you have currently designed it.
I want to play an audio file in the background of my app. Easy enough. I want the music to persist and NOT stop or pause while switching between activities in my app. Also fairly easy and accomplished simply by doing this in the onCreate method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mp = MediaPlayer.create(MainActivity.this, R.raw.lostmexicancity);
mp.setLooping(true);
mp.start();
}
The problem? Getting the music to stop when I press the HOME button.
Killing the sound when the user presses the back button seems easy. Here's what I have for that and works great:
public void onPause() {
if(this.isFinishing()){ //BACK was pressed from this activity
mp.stop();
}
super.onPause(); }
Not complicated, but this does not catch presses of the HOME button. If the Home button is pressed, the music keeps playing even while the user no longer sees my app.
I have seen answers that involve setting permission in the manifest to Get Tasks which I shouldn't have to do and appears dangerous to users. Besides that, the solution didn't even work. I've seen solutions that involve using a service, but none of those work either because the home button STILL plays the music just like before because there doesn't seem to be a way to catch it and it doesn't 'finish' the app (not to mention that every time someone suggest using a service for this task multiple people come in and state that this is not a proper use for services)
It seems the only way to kill the music when the Home button is pressed is to use a non-conditional stop() within onPause, but that's no good because that's called when I swap activities with intents, causing the music to end between activities which is no good.
I have trouble imagining that such a common function like background music is this hard, but I've seen post after post with the same issue as me and no proper answers other than ones that would kill the music between activities within the app.
How do all the other apps on the Google play store accomplish this and yet there appears to be no clear answer online? I could just stop and start the music with each onPause(), but that would cause unprofessional gaps in audio not to mention it would start the background audio from the beginning over and over again which is unacceptable.
I'm a bit new to Android Programming (few months) and today, I faced the same problem you did (maybe you still do?)
I made it work as the following :
Lets say I have MainActivity, and in MainActivity I have Btn2 which leads to SecondActivity, and Btn3 which leads to ThirdActivity.
I declared at the beginning of MainActivity :
public static boolean shouldPlay = false;
I then implemented my onStop() method :
public void onStop() {
super.onStop();
if (!shouldPlay) { // it won't pause music if shouldPlay is true
player.pause();
player = null;
}
}
If the boolean shouldPlay is set to true, then my onStop() won't be called entirely and my music won't turn off. I then have to decide when I set it to true. When I switch from MainActivity to SecondActivity, I do it through an Intent and that's when I'll set shouldPlay to true :
Button Btn2 = (Button) findViewById(R.id.Btn2);
Btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
shouldPlay = true;
startActivity(intent);
}
});
And the same is done for Btn3.
Now, the last thing we want to be looking for is that if I was to go back to MainActivity after visiting SecondActivity or ThirdActivity, shouldPlay would then have been set to true. The first thing I tried was to set it to false as soon as Second and ThirdActivity are called (in their onCreate()) but it want to work, maybe because the onStop() from Main and onCreate() from others are called simultaneously (frankly I don't really get life cycle for now).
What worked is simply to set shouldPlay to false every time we launch onCreate() of Main :
shouldPlay = false;
This works properly for me.
Let me know if it does for you,
Cheers,
bRo.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_HOME){
Log.d("Jorgesys", "Home button pressed!!!");
}
return super.onKeyDown(keyCode, event);
}
but hey! This no longer works as of 4.0 + , Read this: Capture Home Key Event
Try with Back button:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK ) {
Log.d("Jorgesys", "Back button pressed!!!");
}
return super.onKeyDown(keyCode, event);
}
To stop the media player, you are using the method:
isFinishing(): if the activity is finishing, returns true; else
returns false, but you are only pausing the activity not finishing the
activity.
public void onPause() {
if(this.isFinishing()){ //INCORRECT, Here you are pausing you activity not finishing.
mp.stop();
}
super.onPause();
}
so change to:
public void onPause() {
if(mp.isPlaying())
{
mp.stop();
}
super.onPause();
}
When your activity is on pause, evaluates if your MediaPlayer is playing, if this is true then stops the audio.
I'm making a little game and in it I have to check if a value is zero every second. When it is zero the game should stop and show a dialog instead.
As from now the game never ever shoud work until the app is reinstalled.
So, I have an timer with an timertask which executes a runOnUiThread.
Timer:
private void update(){
Timer timer = new Timer();
timer.schedule(new TimerTask(){
#Override
public void run() {
onChange();
}
},0,(1000* getResources().getInteger(R.integer.remove_speed_inSecond)));
}
runOnUiThread: (with try/catch to catch the exeption at this point but i want to fix and not just ignore it.)
private void onChange(){
runOnUiThread(new Runnable() {
#Override
public void run() {
try{
checkupifexpire();
}
catch (Exception ex) {
}
}
});
}
The Method where i show the dialog:
private void checkupifexpire() {
if(eat == 0 || drink == 0 || wash == 0 || care == 0){
dialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
dialog.setOnCancelListener(new DialogInterface.OnCancelListener()
{
#Override
public void onCancel(DialogInterface dialog)
{
GameEngine.this.finish();
}
});
dialog.setContentView(R.layout.activity_rip);
dialog.show();
}
}
Always when I press the back button or just the home button then the App crashes.
Any Idea how to fix this?
So, the logcat tells us that is crashes on line 306 of GameEngine.java, in the method checkupifexpire, which looks like it is the dialog.show() line.
I'm not 100% sure, but from what you've said, it would seem to me that when back or home is pressed, the app will lose its UI thread. This means that checkuponexpire cannot do what it does.
To solve your crash problem, there are three obvious options:
You could use onPause in your main activity to catch when the app loses the screen. At this point you need to either stop the timer, or switch it to using Toast to communicate information.
Only use Toast in checkuponexpire
Decide that when the back or home is pressed the game is over anyway and cancel the Timer.
To Actually get the dialog, it may also be helpful to change the context you use to create the dialog with. Although it should be used sparingly, it may be that getApplicationContext() is what you need here (possibly this.getApplicationContext()).
Thanks to Neil Townsend and WELLCZECH. :)
My problem was the Lifecycles.
Mostly i had the App running in the onCreat() and had no onStart() method.
Just didn't know that thies methods were as much important as they are.
Also i didn't need a dialog shown. Instead i just have to start a new activity and cancel the old one.
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
}
}