Start a one-time sound when app starts [duplicate] - java

I'd like to implement an update checker in an application, and I obviously only need this to show up once when you start the application. If I do the call in the onCreate() or onStart() method, it'll be shown every time the activity is created and this is not a viable solution.
So my question is: Is there a way to do something, like check for updates, just once per application start / launch?
I'm sorry if it's a bit hard to understand, I'm having difficulties explaning myself on this one.

SharedPreferences seems like ugly solution to me. It's much more neat when you use application constructor for such purposes.
All you need is to use your own Application class, not default one.
public class MyApp extends Application {
public MyApp() {
// this method fires only once per application start.
// getApplicationContext returns null here
Log.i("main", "Constructor fired");
}
#Override
public void onCreate() {
super.onCreate();
// this method fires once as well as constructor
// but also application has context here
Log.i("main", "onCreate fired");
}
}
Then you should register this class as your application class inside AndroidManifest.xml
<application android:label="#string/app_name" android:name=".MyApp"> <------- here
<activity android:name="MyActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
You even can press Back button, so application go to background, and will not waste your processor resources, only memory resource, and then you can launch it again and constructor still not fire since application was not finished yet.
You can clear memory in Task Manager, so all applications will be closed and then relaunch your application to make sure that your initialization code fire again.

looks like you might have to do something like this
PackageInfo info = getPackageManager().getPackageInfo(PACKAGE_NAME, 0);
int currentVersion = info.versionCode;
this.versionName = info.versionName;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int lastVersion = prefs.getInt("version_code", 0);
if (currentVersion > lastVersion) {
prefs.edit().putInt("version_code", currentVersion).commit();
// do the activity that u would like to do once here.
}
You can do this every time, to check if the app has been upgraded, so it runs only once for app upgrade

The shared preferences approach is messy, and the application class has no access to an activity.
Another alternative I've used is to have a retained fragment instance, and within that instance, a lot more stuff can be done especially if you need access to the main activity UI.
For this example, I've used asynctask within the retained fragment. My AsyncTask has callbacks to the parent activity. It is guaranteed to run only once per application because the fragment is never destroyed-recreated when the same activity is destroyed-recreated. It is a retained fragment.
public class StartupTaskFragment extends Fragment {
public interface Callbacks {
void onPreExecute();
void onProgressUpdate(int percent);
void onCancelled();
void onPostExecute();
}
public static final String TAG = "startup_task_fragment";
private Callbacks mCallbacks;
private StartupTask mTask;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (Callbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); // this keeps fragment in memory even if parent activity is destroyed
mTask = new StartupTask();
mTask.execute();
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class StartupTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
if (mCallbacks != null) {
mCallbacks.onPreExecute();
}
}
#Override
protected Void doInBackground(Void... ignore) {
// do stuff here
return null;
}
#Override
protected void onProgressUpdate(Integer... percent) {
if (mCallbacks != null) {
mCallbacks.onProgressUpdate(percent[0]);
}
}
#Override
protected void onCancelled() {
if (mCallbacks != null) {
mCallbacks.onCancelled();
}
}
#Override
protected void onPostExecute(Void ignore) {
if (mCallbacks != null) {
mCallbacks.onPostExecute();
}
}
}
}
Then, in main (or parent) activity where you want this startup task fragment to run once.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
StartupTaskFragment st = (StartupTaskFragment) fm.findFragmentByTag(StartupTaskFragment.TAG);
if(st == null) {
fm.beginTransaction().add(mStartupTaskFragment = new StartupTaskFragment(), StartupTaskFragment.TAG).commit();
}
...
}
Ideas for retained fragment came from here: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. I just figured out its other uses aside from config changes.

Yes you can do it Using SharedPrefernce concept of android. Just create a boolean flag and save it in SharedPrefernce and check its value in your onCreate() method .

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!prefs.getBoolean("onlyonce", false)) {
// <---- run your one time code here
// mark once runned.
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("onlyonce", true);
editor.commit();
}
}

This continues on #Vitalii's answer.
After having setup the Application class, if access to the Activity is required, we can use the aptly named android library "Once" https://github.com/jonfinerty/Once.
In the Application class's onCreate method
Once.initialise(this)
In the Activity / Fragment class's onCreate / onViewCreated method.
val helloTag = "hello"
if (!Once.beenDone(Once.THIS_APP_SESSION, helloTag)) {
//Do something that needs to be done only once
Once.markDone(helloTag) //Mark it done
}

I do this the same way as described in the other answer. I just have a global variable in the first activity which matches the release number from the manifest. I increment it for every upgrade and when the check sees a higher number, it executes the one-time code.
If successful, it writes the new number to shared preferences so it wont do it again until the next upgrade.
Make sure you assign the default to -1 when you retrieve the version from shared preferences so that you error on the side of running the code again as opposed to not running it and not having your app update correctly.

Use SharedPreference for this-
If you are not restarting your launcher activity again once your app is active then in that case you case use it.
Use this in a Splash screen if you are implementing it in the app.
If you are not using any splash screen then you need to create a activity with no view set and on it's oncreate call you can do start updation and start your main activity.
you can use counter value or boolean for this.
Here is SharedPreference doc:
http://developer.android.com/reference/android/content/SharedPreferences.html

try {
boolean firstboot = getSharedPreferences("BOOT_PREF",MODE_PRIVATE)
.getBoolean("firstboot", true);
if(firstboot){
//place your code that will run single time
getSharedPreferences("BOOT_PREF",MODE_PRIVATE).edit().
putBoolean("firstboot", false)
.commit();
}

I just solved doing this myself, I reopen my main activity multiple times throughout the application's execution. While the constructor is a valid approach for some things it doesn't let you access the current Application context to write toasts among other things.
My solution was to create a simple 'firstRun' boolean set to true in the class of my MainActivity, from there I run the contents of the if statement then set it to true. Example:
public class MainActivity extends AppCompatActivity
{
private static boolean firstRun = true;
#Override
protected void onCreate(Bundle savedInstanceState)
{
if(firstRun)
{
Toast.makeText(getApplicationContext(), "FIRST RUN", Toast.LENGTH_SHORT).show();
//YOUR FIRST RUN CODE HERE
}
firstRun = false;
super.onCreate(savedInstanceState);
//THE REST OF YOUR CODE
}

Related

How to preserve the state of android activity

I have two activities my MainActivity and some other one called DetailActivity. When the app is first started it opens MainActivity and there it binds DataService and makes a call to fetch some data and populate a list view.
From that list view user has a button to open so called detail view for every item in the list. Opening that detail view means starting the second activity (DetailActivity).
Its done like this:
final Intent intent = new Intent(getContext(), DetailActivity.class);
intent.putExtra("data", dto);
getContext().startActivity(intent);
When second one is opened user is able to go back either by using back button (one left of home button on android) or by clicking back arrow in the header.
Everything works as expected except that when user comes back to MainActivity DataService is binded again and call to fetch the data is made and the list is updated. So if user is somewhere at item no. 205 he will be returned back to the start item.
Is there a way to hold the data or the state of MainActivity when user comes back to it that its not refreshed ?
Service is bonded like this
#Override
protected void onStart() {
super.onStart();
bind(DataService.class);
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
private void bind(final Class... toBind) {
for (final Class clazz : toBind) {
bindService(new Intent(this, clazz), connection, BIND_AUTO_CREATE);
}
}
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(final ComponentName name, final IBinder service) {
if (service instanceof DataService.LocalBinder) {
dataService = ((DataService.LocalBinder) service).getInstance();
dataService.readData();
}
}
#Override
public void onServiceDisconnected(final ComponentName name) {
// Empty By Default
}
};
You can achieve this by binding the service in onCreate() instead of onStart().
You should also have a look at the symmetry of your life cycle. Currently you are binding in start and unbinding in destroy. If you bind in onStart you should probably unbind in onStop. When you move the binding to onCreate you can keep the unbinding in onDestroy
Explanation: onCreate() is called when the activity is created first. onStart() is called every time your activity becomes visible.
Managed to solve it like this
#Override
public boolean onSupportNavigateUp() {
onBackPressed(); // one inherited from android.support.v4.app.FragmentActivity
return false;
}
Doing it this way seamed to do the trick. I would return to the place where I left from and there is no need to load any data since everything is already there

Recurring background task Android - Handler vs AlarmManager

I am working on an application for research purposes. We want to track some user activity on the phone: if some actions are easily detactable with broadcast receivers, we want also to check current running applications.
This application works only on Android devices that runs android 5.0 or lower.
My problem is that I post a Runnable Obj in a handler, Runnable posts again itself in handler after HALF_SECOND (see code for details). In runnable I get information and send them to IntentService to perform work.
Everything works fine: app starts at boot, handler and runnable do their job in background UNLESS I open the main Activity.
The app is able to keep going for days, but if I open the main Activity and then close it from "recent open activities" with a swipe, or from the memory task manager, handler and runnable stop, even if they are not called/accessed by the activity (they are in a Separate Service).
Moreover, not always a call to onDestroy (of the activity or Service) is made.
Reading online I understand that swipe or task manager remove the app from memory abrouptly thus not always calling onDestory.
What I want to achive is to make the handler start again soon after the main activity is closed.
What I have tried is to put some check in onPause method of the activity, making sure to remove this check if onStart is called again (like in case the the app switches from vertical to horizontal layout, or if home button is pressed and then app is opend again). Also implemented a way to make the handler send "ImAlive" intent to a broadcast receiver, which should restart the service that starts the handler, if intents do not arrive before a count down is finished. Unfortunately, as soon the main activty stops existing, even the broadcast is automatically unregistered and destroyed.
My question is, is there a way to create something that is able to make my handler restart if the activity is closed? Or is there some other pattern that can help me as workaround for what I want to achieve? Because I am polling data every half second I read is better to use handler, because Timer augments small interval to a greater interval, and AlarmManager is not precise enough for very small interval.
What I want to achieve is something similar to Facebook, Instagram, Whatsapp, Telegram app, that are always in memory, and even if you force to terminate them, after a few seconds are back again there... how?
We are not interested in battery issues because of continuous polling to data. As for research purposes we don't mind if the phone on which we are testing last 2 days straight, 1 day or 12 hours or less.
Here the code: OnBootService is started from broadcast receiver, declared in manifest when onBootCompleted and ShutDown actions are received, in order to start and stop handler.
public class OnBootService extends Service{
private static final Handler handler = new Handler();
private final long HALF_SEC = 500;
private RunnableTest r = null;
private Context myContext = this;
private final String TAG = "BootService";
// Extras
public static final String START = "start";
public static final String STOP = "stop";
#Override
public IBinder onBind(Intent intent){
return null;
}
#Override
public int onStartCommand(Intent intent, int flag, int startId){
String action = intent.getAction();
switch(action){
case START: startHandler();
break;
case STOP: stopHandler();
break;
}
return START_NOT_STICKY;
}
private void startHandler(){
if(r == null){
r = new RunnableTest();
handler.post(r);
Log.i(TAG, "----Handler started!");
}
}
private void stopHandler(){
if(r != null){
Log.i(TAG, "----calling STOP");
handler.removeCallbacks(r);
r = null;
}
}
private class RunnableTest implements Runnable {
private String TAG = "RunnableTest";
public RunnableTest(){}
#Override
public void run(){
handler.removeCallbacks(this);
// Do stuff
Intent i = new Intent(myContext, MyIntentService.class);
i.putExtra("addStuff", myStuff);
myContext.startService(i);
handler.postDelayed(this, HALF_SEC);
}
}
Activity is empty: all method overridden just to understand proper Activity lifecycle, but else is empty for now.
public class MainActivity extends AppCompatActivity {
private final String TAG = "Activity";
private Context myContext = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// access a file and get stored information to show
setContentView(R.layout.activity_main);
Toast.makeText(getBaseContext(), "Application open successfully", Toast.LENGTH_LONG).show();
}
#Override
protected void onRestart(){
super.onRestart();
Log.e(TAG, "----onRestart Called");
}
#Override
protected void onStart(){
super.onStart();
Log.e(TAG, "----onSTART Called");
}
#Override
protected void onResume(){
super.onResume();
Log.e(TAG, "----onRESUME Called");
}
#Override
protected void onPause(){
super.onPause();
Log.e(TAG, "----onPAUSE Called");
}
#Override
protected void onStop(){
super.onStop();
Log.e(TAG, "----onSTOP Called");
}
#Override
protected void onDestroy(){
super.onDestroy();
Log.e(TAG, "----onDestroy Called");
}
}
Any help is really appreciated, if you need some more information on the code, I will update the post.
Thank you!
Android system can restart the service if u return START_STICKY inside onStartCommand().
It works perfectly on all lower version than Lollipop in Android.
No need of CountDownTimer.

Android initializatoin of class fields not done

Struggled with an appropriate title on this one. I've encountered and odd/baffling situation which only came to light as I sometimes initialize fields.
In this case, I had a boolean which I initialized to false (I know, redundant... but...)
the app runs fine and prior to exit my boolean is set to true. I watch the log cat to see that onDestroy() has been called.
I then restart the app.
My boolean, whose value I now log in onCreate(), is true.
WTF?
I noted that the activity started with a new PID. And yet, it is bypassing field initializations. Mind you, I have some which are not redundant. So what is going on here?
I then force stopped the app from the settings menu on the device. Restarting the app now shows all as expected, boolean = false.
So is onDestroy() not a reliable/real termination? I don't recall ever reading anything like that.
This is not my app but is an example of the situation:
public class MyActivity extends Activity {
/**
* Called when the activity is first created.
*/
private static boolean b = false;
private static int i = 1;
private static final String TAG = "junk app";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(TAG, "==================================================================");
if(b) Log.i(TAG,"boolean is true");
if(!b) Log.i(TAG,"boolean is false");
Log.i(TAG,"The value of i is"+i);
i++;
b=!b;
foo();
}
public void foo() {
finish();
}
#Override
public void onResume() {
Log.i(TAG,"onResume");
super.onResume();
}
#Override
public void onStop() {
Log.i(TAG,"onStop");
super.onStop();
}
#Override
public void onDestroy() {
Log.i(TAG,"onDestroy");
super.onDestroy();
}
}
Run this app on a device and watch your logcat. onDestroy() is called. Now start the app again from its icon. i is incremented and b becomes !b.
IDK but my (naive) expectation is that if an app is destroyed, if it is restarted it starts fresh and all initializations, etc are done again.
Statics are statics -- they are global to the process. So their value
will last for the lifetime of the process, which is usually much
longer than an individual activity instance.
Source: https://groups.google.com/forum/#!topic/android-developers/PZXbCXliRbo

OrientationChange doesn't destroy activity?

I have a rather commonly occurring situation in Android, which has to do with the previous asynctask updating the activity, whilst the activity has been lost because of a change in orientation.
I have an activity, Activity A.
Activity A implements OnDownloadCompleteListener {
public void sync()
{
new SyncAttestationInfoTask(this).execute();
}
#Override
public void onComplete()
{
loadAttestationInfo();
}
}
Here is my asynctask shortened:
package com.evento.mofa.backgroundtasks;
import java.util.ArrayList;
import java.util.List;
/**
* #author Ahmed
*
*/
public class SyncAttestationInfoTask extends AsyncTask<Void, Void,Void> {
/*TIP*/
//TO SPEED UP THIS OPERATION WE CAN USE THE EXECUTEONEXECUTOR .
private ProgressDialog pd;
private OnDownloadComplete parentActivityContext;
EntityConvert convert = new EntityConvert();
private AttestationDao aDao = new AttestationDao();
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
if (Locale.getDefault().getLanguage().equals("ar"))
{
/*EMPTY ALL THE TABLES THEN START PROCESSING*/
aDao.flushTables(Locale.getDefault().getLanguage());
syncAttestLocations(Webservices.ATTEST_LOCATION_AR,1);
syncDocumentTypes(Webservices.DOCUMENT_TYPES_AR,1);
syncAttestationInfo(Webservices.ATTESTATION_INFO_AR,1);
} else {
/*EMPTY ALL THE TABLES THEN START PROCESSING*/
aDao.flushTables(Locale.getDefault().getLanguage());
syncAttestLocations(Webservices.ATTEST_LOCATION,0);
syncDocumentTypes(Webservices.DOCUMENT_TYPES,0);
syncAttestationInfo(Webservices.ATTESTATION_INFO,0);
}
return null;
}
public SyncAttestationInfoTask(OnDownloadComplete context) {
parentActivityContext = context;
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog((Context)parentActivityContext);
pd.setTitle("Loading...");
pd.setMessage("Updating Data.");
pd.setCancelable(false);
pd.setIndeterminate(true);
pd.show();
}
#Override
protected void onPostExecute(Void result) {
pd.dismiss();
parentActivityContext.onComplete();
// findViewById(R.id.the_button).setEnabled(true);
}
}
There is something strange with my Activity.
I put a breakpoint on the onComplete callback inside my activity
I start a progress dialog inside the sync async task.
As soon as the progress dialog displays on the screen I landscape my device.
The dialog box vanishes, and pd.dismiss() raises a "View not attached" error (I understand that the activity that it was attached to no longer exists).
The above means that parentActivityContext().oncomplete should also throw the same error, however it does not.
I commented the pd.Dismiss(), and found out that the breakpoint on onComplete() is invoked? Isn't this strange given the fact that the reference to the activity has been lost at this point?
Please give me insight into this.
I would do this
Add this line to your Manifest.xml file, this will prevent of calling onCreate() when screen rotates.
<activity android:name=".yourActivity" android:configChanges="keyboardHidden|orientation">
Version above Android 3.2, you also need to add "screenSize":
<activity android:name=".yourActivity" android:configChanges="keyboardHidden|orientation|screenSize">
This will prevent activity from restarting on orientation change, and you should not have any problems (except maybe some layout fixes)
The previous Activty is being referenced by the AsyncTask via a strong reference.
AsyncTask constructed with Activity 1 (parentActivityContex =
Activity 1)
Activity 1 "destroyed" and Activity 2 comes into foreground
AsyncTask completes, calls parentActivityContext (Activity 1) onComplete
Activity 2 just sits there doing nothing
Activity 1 no longer has active references pointing to it, is collected
You could try doing your task in a Service and having whatever Activity is in the foreground receive a broadcast, or you could try having your AsyncTask reference a Fragment with setRetainInstance(true). Below is an example of the second case. Note that you might want to handle the case where the AsyncTask completes while the Fragment is detached from one Activity and not yet attached to the next Activity
public class ExampleDownloadFragment extends Fragment {
#Override
public void onCreate(final Bundle savedInstanceState) {
setRetainInstance(true);
new SyncAttestationInfoTask(this).execute();
}
public void onComplete() {
final Activity activity = getActivity();
if (activity != null && activity instanceof A) {
((A) activity).onComplete();
}
}
}

Get context of current running activity

I wonder if there is a way to get the context of current running activity on android. For example, I have an Activity Class and it is running. What I want is to call another Simple Class to run some functions which called from Activity Class. By doing this, I need to set up a context of Activity Class on Simple Class; On the other way, I need to have the context of Current Running Activity, so that my Simple Class can actually run the functions called from Current Running Activity.
Below is the soft code from my project.
public class Main1 extends Activity {
private static GetAPNsInfo getAPNsInfo = new GetAPNsInfo();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getAPNsInfo.doSomething();
}
}
public class GetAPNsInfo {
public void doSomething() {
Button button = currentRunningActivityContext.findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
}
});
}
}
Finally, my purpose of this thread is that I need a good way to get the current running activity info.
This is a solution that I found my self. But it doesn't totally solve this case. We can add a receiver in Manifest.xml. This will run a background application.
<receiver android:name=".RunningActivityCapture">
<intent-filter android:priority="-1">
<action android:name="android.intent.action.NEW_OUTGOING_CALL"></action>
</intent-filter>
</receiver>
The background application interface look like this:
public class RunningActivityCapture extends BroadcastReceiver {
#Override
public void onReceive(Context aContext, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_ALL_APPS)) {
Activity activty = intent.getCurrentActivity();
Session session = new Session();
session.setRunningActivity(activty);
}
return;
}
}
I only get the activity from session class which setting from my background application. This is my first idea to solve this problem. But the code is not correct. So I need your help.
If you are asking how to use this MainActivity in your helper class, you can pass the Activity itself into your class, as an activity is a Context. So your constructor will be:
public GetAPNsInfo(Context context) {
...
}
where you store the context in a field and use it later. You will initialize with
private static GetAPNsInfo getAPNsInfo = new GetAPNsInfo(this);
if you are asking how to get the context for ANY activity in your application, I don't think that is recommended.

Categories