In my android application, I have extended Application class. I am having some meta data which I do not want to re-initialize again and again. I initialize them in Application class and then use them.
private SampleSettings getSettings(){
return sampleSettings;
}
public class SampleApplication extends Application {
public void onCreate(){
super.onCreate();
sampleSettings = getSettingsFromDB();
}
}
Here getSettings returns null in some cases when accessed in application using applicationContext.
Sometime I am getting null pointer exception for such properties. I have seen when the app goes to background it occurs but not frequently.
My understanding is that those values should not become as long as application is started.
What am I missing which is causing them to become null?
Thanks
Your process does not live forever. When you are not in the foreground, your process may be terminated at any time by Android, to free up system RAM for other apps.
A custom Application object, or any static fields, are only for caching and other in-flight data. Your app needs to be able to start up, from any activity, lazy-initializing all of that as needed.
Related
I have an android application
#HiltAndroidApp
class MyApp extends Application {
static MyApp app;
static MyApp getApp() {
return app;
}
#Override
public void onCreate() {
super.onCreate();
app = this;
}
}
and I am trying to use it inside a class
class AppStateUsingClass {
public void mymethod() {
MyApp app = MyApp.getApp();
//use app
}
}
Now I can access the app where I don't have the context but I am not sure if its correct way of doing.
My understanding is that the application life cycle is through out app start and stop, therefore its lives as a Singleton so it shall be fine but not sure.
Isn't there any simpler cleaner API to access app, I have app state in MyApp class which I would like to access where context is absent?
Any suggestions are highly appreciated?
What you are doing is a fairly common pattern, and shouldn't really cause problems.
The application class can be treated as a singleton that is alive as long as any part of your application is alive.
The docs specifically state that this class is used to hold application state.
However, depending your actual design, the kind of state information you want to hold and where you want to access it, you may want to create your own singleton, independent of the application class and use that.
Or, you may want to initialize your AppStateUsingClass with a state object passed in the constructor.
This is a design decision, and if you want more opinions on it, create a working code example and post it on https://codereview.stackexchange.com
We've recently started running into crashes in our Android app due to the app being open in multiple processes. Several different errors point towards that. For instance this error:
com.google.firebase.database.DatabaseException: Failed to gain
exclusive lock to Firebase Database's offline persistence. This
generally means you are using Firebase Database from multiple
processes in your app. Keep in mind that multi-process Android apps
execute the code in your Application class in all processes, so you
may need to avoid initializing FirebaseDatabase in your Application
class. If you are intentionally using Firebase Database from multiple
processes, you can only enable offline persistence (i.e. call
setPersistenceEnabled(true)) in one of them.
We are also seeing similar errors from SQLite and H2. This is a new issue and we have not explicitly allowed multiple processes to run. Nothing in our AndroidManifest.xml specifies a custom android:process attribute.
I suspect that some third party library is causing this. How do I identify the root cause of the multiple processes and how do I prevent it?
Another of our apps is connecting to this app via a ContentProvider. At first I thought that it having android:multiprocess="true" was the culprit but changing it to "false" did not help. I still suspect that the other app is somehow triggering the creation of a new process. This is how to the ContentProvider is defined:
<provider
android:name=".DegooContentProvider"
android:authorities="${applicationId}.DegooContentProvider"
android:exported="true"
android:protectionLevel="signature"
android:multiprocess="false">
</provider>
You can check in your applicaition class if there is foreign process. Here is an example:
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
if (!isMainProcess()) {
// Do not call thread unsafe logic. Just return
return;
}
// Thread unsafe logic.
...
}
private boolean isMainProcess() {
int pid = android.os.Process.myPid();
ActivityManager manager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
String currentProcName = processInfo.processName;
if (processInfo.pid == pid) {
if (TextUtils.equals(currentProcName, BuildConfig.APPLICATION_ID)) {
return true;
}
}
}
return false;
}
}
Looks like you are calling the method setPersistenceEnabled() multiple times.
Ensure it is not. You can do this in a several ways.
The preferred method will be to place it only in the onCreate() method of the default Application class if you are extending one.
Another solution will be to place it in the static block of any class.
static {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Or you can even set a static boolean variable say, inFirebaseInstanceInitialized and call setPersistenceEnabled() only if it is not true already.
I am using the PostContextCreate part of the life cycle in an e4 RCP application to create the back-end "business logic" part of my application. I then inject it into the context using an IEclipseContext. I now have a requirement to persist some business logic configuration options between executions of my application. I have some questions:
It looks like properties (e.g. accessible from MContext) would be really useful here, a straightforward Map<String,String> sounds ideal for my simple requirements, but how can I get them in PostContextCreate?
Will my properties persist if my application is being run with clearPersistedState set to true? (I'm guessing not).
If I turn clearPersistedState off then will it try and persist the other stuff that I injected into the context?
Or am I going about this all wrong? Any suggestions would be welcome. I may just give up and read/write my own properties file.
I think the Map returned by MApplicationElement.getPersistedState() is intended to be used for persistent data. This will be cleared by -clearPersistedState.
The PostContextCreate method of the life cycle is run quite early in the startup and not everything is available at this point. So you might have to wait for the app startup complete event (UIEvents.UILifeCycle.APP_STARTUP_COMPLETE) before accessing the persisted state data.
You can always use the traditional Platform.getStateLocation(bundle) to get a location in the workspace .metadata to store arbitrary data. This is not touched by clearPersistedState.
Update:
To subscribe to the app startup complete:
#PostContextCreate
public void postContextCreate(IEventBroker eventBroker)
{
eventBroker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, new AppStartupCompleteEventHandler());
}
private static final class AppStartupCompleteEventHandler implements EventHandler
{
#Override
public void handleEvent(final Event event)
{
... your code here
}
}
I have Android application and own Application derived class holding some internal data.
Among other there are some string fields. The problem is that if I put the application in foreground, work on other application, switch back to my app again, the app may be restarted because it got killed by system. Unfortunatelly the Application object seems not to be created again because the onCreate method of application object doesn't get called and all fields are set to null. My Activity gets recreated but all Application's object fields are null. When is the Application.onCreate method called? How to handle it?
there is no onCreate that you can register to.in later API's there's a way to register to the Activity lifecycle functions. and then you can do what ever you want.
basically, what you should do is use SharedPrefrences for storing information.
what I would do is:
class MyApp extends Application {
private static String someResource = null;
public static String getSomeResource(Context context) {
if(someResource == null) {
SharedPrefrences prefs = (SharedPrefrences)
context.getSystemService(Context.SHARED_PREFRENCES);
someResource = prefs.getString(SOME_RESOURCE, null);
}
return someResource;
}
Application onCreate() will called only for one time during its life-cycle, i.e.. only when application is started.
As suggested by thepoosh below answer is valid ,if your application is killed,still the data is saved in shared preference.
I have a singleton in Android for data loaded from xml. It gets recycled from time to time and I don't understand why. Singleton should exist through the lifetime of app process by my knowledge. Here's my singleton:
public class DataLib {
public static CategoryList categories = new CategoryList();
public static RegionList regions = new RegionList();
public static CompanyTypeList types = new CompanyTypeList();
public static SearchData searchData = new SearchData();
public static CompaniesList companies = new CompaniesList();
private static RegionData currentRegion;
private static final DataLib INSTANCE = new DataLib();
protected DataLib() {
}
public static DataLib getInstance() {
return INSTANCE;
}
public static void loadData() {
loadCategories();
loadRegions();
loadTypes();
}
/* ... some more static functions are here ...*/
}
As you can see it is not instantiated by any activity directly but rather by the process itself. The data are loaded by calling DataLib.loadData() when the application starts = activity which will end when the data are loaded.
I cannot tell for sure what triggers the recycling - sometimes app needs to stay in the background for longer time, sometimes it's in a few minutes. I am logging the pointer of the DataLib class so I can tell that it truly changed = got recycled.
Any ideas? Thanks.
EDIT: Answer is partially in marked answer + comments to it.
It gets recycled from time to time and I don't understand why.
Android will terminate your process "from time to time".
sometimes app needs to stay in the background for longer time, sometimes it's in a few minutes
The OS and the user can get rid of your process whenever they feel like it. Singletons and other static data members need to be caches for persistent data, loading that data using background threads and the like.
If there is particular work that you are doing in the background, you should be using a Service for that, to indicate to the OS that you are doing work in the background independent of any activities. That does not prevent Android from terminating your process (e.g., at user request), but it will make it a bit less likely to terminate your process on its own (i.e., the OS will tend to choose other processes).