Since An开发者_JAVA技巧droid introduced library projects, I've been converting my app into a library so that I can make several versions with appropriate tweaks (for example, a free and pro version using the same code base, but changing a few things).
I initially had trouble allowing the library project's code access to fields in my sub-projects. In other words, my free and pro versions each had a class with a few constants in them, which the library project would use to distinguish certain features.
In the sub-project, I extended the library's main activity and added a static initialisation block which uses reflection to change the values of fields in the library.
public class MyMainActivityProVersion extends MyMainActivity {
public static final String TAG = Constants.APP_NAME + "/SubClass";
static {
try {
ConstantsHelper.setConstants(Constants.class);
} catch (Exception e) {
Log.d(TAG, "--- Constants not initialised! ---");
e.printStackTrace();
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
In this code, ConstantsHelper is in the library, and I am providing Constants.class from my sub-project. This initialises the constants in the library project.
My approach works great, except for one particular use case. When the app hasn't been used in a while and it is 'stopped' by the OS, the static fields in ConstantsHelper are forgotten.
The constants are supposed to be reset by the main activity (as shown above), but the main activity isn't even launched because the OS resumes a different activity. The result of this is that the initialisation of the constants is forgotten and I cannot re-initialise them because the resumed activity is in the library (which has no knowledge of the sub-project).
How can I 'tell' other activities in the library to call code from sub-projects on resuming? Alternatively, is there a way to ensure that some code in my sub-project is called on every resume?
I think you're "cheating" by trying to share data across two Activities through static members. This happens to work when they're in the same, or related, classloaders. Here I believe Android uses separate classloaders for separate Activities, but, child Activities are in child classloaders. So ViewActivity
happens to be able to see up into the parent classloader and see statics for the parent. Later I believe that parent goes away, and so your child re-loads MyMainActivity
locally when you next access it and it's not initialized as you wanted. (Well, if it's not that, it's something very like this explanation.)
I think there are some more robust alternatives. You could use the LicenseChecker
API to decide whether you're in a free or for-pay version rather than rely on details of the activity lifecycle and classloader. That's probably going to be better as it protects you from other types of unauthorized use.
I'm afraid I never found a good answer to this question. I'll probably continue with my terrible use of reflection and figure out some hacky workaround.
I felt I should come back and at least point out that I didn't solve this for the benefit of others who come to this page.
You can resolve this using Android resources.
Basically, define your constants in a resources xml values file in your Library project
E.g. "lib project"\values\constants.xml
<resources xmlns:tools="http://schemas.android.com/tools">
<bool name="const_free_version">false</bool>
<string name="const_a_constant">pippo</bool>
</resources>
Then, in your sub-project you can redefine the lib-project values using a different resources xml values file:
E.g. "sub project"\values\constants.xml
<resources xmlns:tools="http://schemas.android.com/tools">
<bool name="const_free_version">true</bool>
</resources>
In your lib project code when you refer to R.bool.const_free_version you get the actual value based on sub-project constant values xml.
Note that you don't have to redefine every values defined in the lib project constants.xml but only the ones you need different in your sub project.
精彩评论