I have two activities in my project- Splash and AActivity. Splash is the main activity and is working fine. But if i change the orientation while Splash activity is running, the UI of splash activity goes off but it opens the AActivity after 10 sec.
code for splash activity is -
public class Splash extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
Thread timer = new Thread(){
public void run() {
try{
sleep(10000);
}catch(InterruptedException e){
e.printStackTrace();
}finally{
Intent AActivityIntent = new Intent("com.example.ex.AACTIVITY");
startActivity(AActivityIntent);
}
}};
timer.start();
}
#Override
protected void onPause() {
super.onPause();
finish();
}
}
I want to retain the UI of splash activity for 10 seconds even if orientation is changed. After 10 sec splash activity should be finished. How to do it ???
I suggest you doing the following:
public class Splash extends Activity {
private Thread timer;
private volatile long timeLeft;
private long timeStarted;
private long timeStopped;
private static final long TIME_TO_SHOW = 100000
private static final String KEY_TIME_LEFT = "timeLeftToRun";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
if (savedInstanceState != null) {
timeLeft = savedInstanceState.getLong(KEY_TIME_LEFT, 0);
} else {
timeleft = TIME_TO_SHOW;
}
timer = new Thread() {
public void run() {
try {
sleep(timeLeft);
Intent AActivityIntent = new Intent("com.example.ex.LISTSCREEN");
startActivity(AActivityIntent);
} catch(InterruptedException e) {}
}
}};
timeStarted = SystemClock.elapsedRealtime();
timer.start();
}
#Override
protected void onPause() {
super.onPause();
timer.interrupt();
timeStopped = SystemClock.elapsedRealtime();
finish();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
timeLeft -= timeStopped - timeStarted;
if (timeLeft > 0) outState.putLong(timeLeft);
}
}
The main idea here is that you kill the thread if the activity is killed, but you take a note for how long it has run and how much time it has left. When the activity is restored, you do the same actions, except you have to wait for a smaller amount of time.
The code above is, of course, untested, but it should illustrate the idea.
Insert into your manifest these below block.
It means orientation change situation controlled by your "activity".
http://developer.android.com/guide/topics/manifest/activity-element.html#config
android:configChanges="orientation"
And more.
Override "onConfigurationChanged" method.
Try this. You can do everything you want.
Instead of using a Thread for delayed launch of activity use Alarmmanager, even if you are quitting the app you could always cancel the pending Alarm
Related
I have splash screen .
once i open my application the splash screen will appears after completion of splash screen passed intent to HomeActivity.
but when i kill this app while splash screen running after some time HomeScreen will automatically open , but i want to kill the app.
but the HomeScreen should not show when i killed the app .
public class SplashAnimation extends Activity {
ImageView imageViewSplash;
TextView txtAppName;
RelativeLayout relativeLayout;
Thread SplashThread;
MediaPlayer mySong;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_view);
mySong=MediaPlayer.create(SplashAnimation.this,R.raw.monn);
mySong.start();
imageViewSplash = (ImageView) findViewById(R.id.imageViewSplash);
txtAppName = (TextView) findViewById(R.id.txtAppName);
relativeLayout = (RelativeLayout) findViewById(R.id.relative);
startAnimations();
}
private void startAnimations() {
Animation rotate = AnimationUtils.loadAnimation(this, R.anim.translate);
Animation translate = AnimationUtils.loadAnimation(this, R.anim.translate);
rotate.reset();
translate.reset();
relativeLayout.clearAnimation();
imageViewSplash.startAnimation(rotate);
txtAppName.startAnimation(translate);
SplashThread = new Thread() {
#Override
public void run() {
super.run();
int waited = 0;
while (waited < 3500) {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
waited += 100;
}
SplashAnimation.this.finish();
Intent intent = new Intent(SplashAnimation.this, LibraryView.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(intent);
mySong.stop();
}
};
SplashThread.start();
}
#Override
protected void onStop() {
SplashAnimation.this.finish();
finish();
mySong.stop();
super.onStop();
}
#Override
protected void onDestroy() {
finish();
mySong.stop();
super.onDestroy();
}
}
Once you have called SplashThread.start() it will do its job as long as it can do. I would recommend to use a Handler instead, tho you can remotely cancel the task, the Handler runs:
//init and declare the handler instance
private Handler delayHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (delayHandler == null) {
delayHandler = new Handler();
}
//your code
}
//define the task the handler should do
private void startAnimations() {
//replace the code beginning at 'Thread SplashThread = new Thread()' with the following
delayhandler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(SplashAnimation.this, LibraryView.class);
//these flags will prevent to 'redo' the transition by hitting the back button, that also makes calling 'finish()' obsolete
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
//instead of the while loop just execute the runnable after below given amount of milliseconds
}, 3500)
//to remotely cancel the runnable, if the app, respectively the Activity gets killed override 'onDestroy()'
#Override
public void onDestroy() {
super.onDestroy();
mySong.stop();
//calling 'finish()' is obsolete, tho 'finish()' calls 'onDestroy()' itself
//tell the handler to quit its job
delayHandler.removeCallbacksAndMessages(null);
}
Call in onStop() method
SplashThread.interrupt()
You can use Timer instead of instantiating the Thread class.
Refer the code below to start the Activity after 4 seconds. Use this in onCreate() of SplashActivity.
timer = new Timer().schedule(new TimerTask() {
#Override
public void run() {
startActivity(new Intent(getApplicationContext(), MainActivity.class));
}
}, 4000);
In your onPause() method use:
timer.cancel()
This will terminate the timer and disregards any currently scheduled tasks.
So I'm trying to make a clicker game that is about money. Every time you click the middle button it gives you 1€, but it also gives 1€/second.
I'm having a problem when I go to the shop activity and then come back to MainActivity, it counts as 2 timers are running, and if I alternate activities again, it counts as if 3 Timers were running at the same time. Thats giving me issues because I declared "money_per_sec" int, and dont want 2€/s or more just because I click on "Shop".
Any help?
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
money = loadGame.getInt("money", 0);
money_per_sec = loadGame.getInt("money_per_sec", 0);
money_per_click = loadGame.getInt("money_per_click", 0);
money = money + money_per_sec;
SharedPreferences saveGame = getSharedPreferences(SAVE, 0);
SharedPreferences.Editor editor = saveGame.edit();
editor.putInt("money", money);
editor.putInt("money_per_sec", money_per_sec);
editor.apply();
runOnUiThread(new Runnable() {
#Override
public void run() {
tv_money_per_sec.setText(String.valueOf(money_per_sec));
tv_money_per_click.setText(String.valueOf(money_per_click));
toolbar_title.setText(String.valueOf(money));
}
});
}
}, 1000, 1000);
You have to check which Activity's life-cycle method are you using for starting your timer. I think you are using onResume which case this problem, and you start another timer by getting back to your Activity.
you can take a look at this diagram and choose the best position, or even separate your timer from activity life-cycle:
also you can implement Application class and place your timer there. this class is instantiated once during your application life time:
public class MyApplication extends Application{
private OnTimerTick listener;
public void setListener(OnTimerTick listener) {
this.listener = listener;
}
#Override
public void onCreate() {
super.onCreate();
// start your timer
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
money = loadGame.getInt("money", 0);
money_per_sec = loadGame.getInt("money_per_sec", 0);
money_per_click = loadGame.getInt("money_per_click", 0);
money = money + money_per_sec;
SharedPreferences saveGame = getSharedPreferences(SAVE, 0);
SharedPreferences.Editor editor = saveGame.edit();
editor.putInt("money", money);
editor.putInt("money_per_sec", money_per_sec);
editor.apply();
if(listener!=null)
listener.onTick(money,money_per_sec);
}
}, 1000, 1000);
}
interface OnTimerTick {
void onTick(int money, int moneyPerSec);
}
}
you have to add this to your manifest like this:
<application
android:name=".MyApplication"
...
also you can access this singleton class every where in your application:
MyApplication application = (MyApplication) getApplication();
inside your MainActivity:
public class MainActivity extends AppCompatActivity implements MyApplication.OnTimerTick {
private MyApplication application;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
application = (MyApplication) getApplication();
// other stuff
}
#Override
protected void onResume() {
super.onResume();
application.setListener(this);
}
#Override
protected void onPause() {
super.onPause();
application.setListener(null);
}
#Override
public void onTick(final int money, final int moneyPerSec) {
runOnUiThread(new Runnable() {
#Override
public void run() {
tv_money_per_sec.setText(String.valueOf(moneyPerSec));
tv_money_per_click.setText(String.valueOf(moneyPerSec));
toolbar_title.setText(String.valueOf(money));
}
});
}
This is how you can even access the Timer within any other activity you like.
First, you should probably consider using a Handler instead of a Timer. This will allow you to more easily manage your Timer within the lifecycle of the Activity.
private final int interval = 1000; // 1 Second
private Handler handler = new Handler();
private Runnable runnable = new Runnable(){
public void run() {
Toast.makeText(MyActivity.this, "C'Mom no hands!", Toast.LENGTH_SHORT).show();
}
};
...
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);
Next, based on your comment:
I'm actually using onCreate in all other activities, but the fun part
is, that when I change activity, the timer still runs. And when I go
back to the activity that has the Timer, it "creates" another timer.
It looks like you are using the standard launchMode for your Activity. This launchMode will create a new Activity when the Back or Up buttons are pressed because the second Activity is creating an Intent to start that Activity.
Try setting the launchMode for the Activity with the Timer to android:launchMode="singleTop". This will instead route the Intent from the second Activity to the existing parent Activity, and trigger a call to onNewIntent. This will prevent the Activity from being restarted, and creating another Timer.
You should also probably terminate the Timer in the onDestroy method of your Activity, otherwise it will continue to run and could cause memory leaks.
Make your timer an instance of the activity rather than an anonymous class. Check if it is already running in onResume(). If not, start it. Stop it in onDestroy(). Something like this:
class MyActivity extends Activity {
private Timer mTimer;
#Override
public void onResume() {
super.onResume();
if (mTimer == null) {
mTimer = new Timer() {
};
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
}
this is my Splash Screen, If I press home or multitasking/appswitch button when Intent is started app crash, in logcat is FATAL EXEPTION: Thread-1277. Can I kill/delete this Intent when player press home button?
public class SplashScreen extends Activity {
private static int loadingTime = 1000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
setContentView(R.layout.loading_screen);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent i = new Intent(SplashScreen.this, MainActivity.class);
startActivity(i);
finish();
}
}, loadingTime);
}
}
The following code tracks whether the SplashActivity is at least partially showing. If yes, it will continue to MainActivity. If not (activity is finished by pressing Back button, activity is stopped by pressing Home button) nothing happens.
This solution uses Fragments so the timing is preserved across e.g. screen orientation changes (it will always take specified time no matter how many times you rotate your device - the timer will not reset).
public class SplashActivity extends Activity {
// tracks when the activity is at least partially visible (e.g. under a dialog)
private boolean mStarted = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// your current code
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
setContentView(R.layout.activity_startup);
if (savedInstanceState == null) {
// first time onCreate, create fragment which starts countdown
getFragmentManager()
.beginTransaction()
.add(SplashFinishFragment.newInstance(), SplashFinishFragment.TAG)
.commit();
} else {
// fragment already set up from first onCreate after screen rotation
}
}
#Override
protected void onStart() {
// the activity becomes at least partially visible
mStarted = true;
super.onStart();
}
#Override
protected void onStop() {
// the activity is no longer visible
mStarted = false;
super.onStop();
}
public boolean isStarted2() {
// there is already hidden method isStarted() in the framework
// you can't use it and are not allowed to override it
return mStarted;
}
public static class SplashFinishFragment extends Fragment {
private static final String TAG = SplashFinishFragment.class.getSimpleName();
private static final int DELAY = 1000; // one second delay
private static final Handler mHandler = new Handler(); // one main thread anyway
private final Runnable mRunnable = new Runnable() {
#Override
public void run() {
if (getActivity() == null) {
// this should never happen, there is no activity, so no fragment
Log.e(TAG, "No activity!");
return;
}
SplashActivity a = (SplashActivity) getActivity();
if (a.isStarted2() || a.isChangingConfigurations()) {
// if activity is even partially visible or is rotating screen right now, continue
Intent i = new Intent(a, SettingsActivity.class);
a.startActivity(i);
}
// in any case close splash
a.finish();
}
};
public static SplashFinishFragment newInstance() {
return new SplashFinishFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// the countdown will continue (not reset) across screen rotations
setRetainInstance(true);
// try running the main activity after specified time
mHandler.postDelayed(mRunnable, DELAY);
}
#Override
public void onDestroy() {
// if the fragment gets destroyed (e.g. activity closes) do not launch main activity
mHandler.removeCallbacks(mRunnable);
super.onDestroy();
}
}
}
This was tested on a virtual Galaxy S2. It works when Home or Back button is pressed. It doesn't work when Recent Apps button is pressed. I don't know your use case but personally I would expect the app to continue launching while I browse recent apps.
Activity.onPause() and onStop() are called in (at least) two situations:
The another Activity was launched on top of the current one.
The app was minimized.
Is there an easy way to tell the difference?
You could do it this way. Make all of your activities extend from a base activity. The base activity needs to keep a visibility counter that is incremented/decremented during onResume/onPause:
public abstract class MyBaseActivity extends ActionBarActivity {
private static int visibility = 0;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
}
#Override
protected void onResume() {
super.onResume();
visibility++;
handler.removeCallBacks(pauseAppRunnable);
}
#Override
protected void onPause() {
super.onPause();
visibility--;
handler.removeCallBacks(pauseAppRunnable);
// give a short delay here to account for the overhead of starting
// a new activity. Might have to tune this a bit (not tested).
handler.postDelayed(pauseAppRunnable, 100L);
}
#Override
protected void onDestroy() {
super.onDestroy();
// uncomment this if you want the app to NOT respond to invisibility
// if the user backed out of all open activities.
//handler.removeCallBacks(pauseAppRunnable);
}
private Runnable pauseAppRunnable = new Runnable() {
#Override
public void run() {
if (visibility == 0) {
// do something about it
}
}
};
}
I have an activity that contains many UI views. In its onCreate method, I found single line of setContentView takes 8-12 seconds to be complete. So I want to show my logo image while it's loading. I tried many things but without any success. I suspect main reason might be that before finishing setContentView, nothing can be shown.
Any help would be appreciated.
UPDATE:
I think many people do not know that you cannot show any dialog before finishing setContentView. So using another splash activity does not help me at all.
UPDATE2
I forgot to update this question after I found cause of the problem. Please refer to following question: setContentView taking long time (10-15 seconds) to execute
use AsyncTask
put splash in onPreExecute()
and do your work in doInBackground()
and close splash in onPostExecute()
Below is the simple code for creating splash screen using CountDownTimer class
public class SplashDialogActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// Be sure to call the super class.
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.layout);
counter.start();
}
MyCount counter = new MyCount(5000, 1000);
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
go_back();
}
#Override
public void onTick(long millisUntilFinished) {
}
}
public void go_back()
{
counter.cancel();
Intent i=new Intent(this,account.class);
i.putExtra("first_time", true);
startActivity(i);
this.finish();
}
}
try this code for splash page
private Thread mSplashThread;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splesh);
final Splash sPlashScreen = this;
mSplashThread = new Thread(){
#Override
public void run(){
try {
synchronized(this){
wait(5000);
}
}
catch(InterruptedException ex){
}
finish();
Intent intent = new Intent();
intent.setClass(sPlashScreen,Login.class);
startActivity(intent);
stop();
}
};
mSplashThread.start();
}
// Processes splash screen touch events
#Override
public boolean onTouchEvent(MotionEvent evt) {
if(evt.getAction() == MotionEvent.ACTION_DOWN)
{
synchronized(mSplashThread){
mSplashThread.notifyAll();
}
}
return true;
}