Copy/share configurations between paid/free versions of Android app? - android

My Android app comes both as a free and paid version. I have created a library project and two additional Application projects, one 'Free' and one 'Paid' version (signed with the same key, of course). Note that these Application projects are pretty much empty, no settings etc. Hence, the library contains 99% of the code.
My app creates both an SQLite database and a SharedPreferences file with user data. Is it possible to copy these files between the free and paid versions? (The preferences are more important than the database.)
E.g.
User runs the free version. A database and configuration file are created.
User installs the paid version and runs it.
The paid version checks for any free version data and copies it. This is what I want!

Implement a ContentProvider to expose the stored data in your free version.
Ensure the provider is exported (android:exported="true")
Declare a permission in your client application. The protection level should be "signature".
Require the permission declared in (3) as a readPermission for the provider.
In your paid app, add a uses-permission for the permission declared in your free app.
Check for the presence of the provider & load the data into your paid app.
This, of course, only works if you are signing the free and paid apps with the same cert (which most sane people do).

If you don't wish to go to the trouble of implementing a ContentProvider, or if it is possible that both apps may remain installed and used, there is a different solution.
Code and usage
Let us assume that the data in question is in a class:
class DataToBeShared() {
// Data etc in here
}
Then, add a class to both apps as follows:
public class StoredInfoManager {
public static String codeAppType = "apptype";
public static String codeTimestamp = "timestamp";
public static String codeData = "data";
public static String codeResponseActionString = "arstring";
public static String responseActionString = "com.me.my.app.DATA_RESPONSE";
private static int APP_UNKNOWN = 0;
private static int APP_FREE = 1;
private static int APP_PAID = 2;
private static String freeSharedPrefName = "com.me.my.app.free.data";
private static String paidSharedPrefName = "com.me.my.app.paid.data";
// Use only one pair of the next lines depending on which app this is:
private static String prefName = freeSharedPrefName;
private static int appType = APP_FREE;
//private static String prefName = paidSharedPrefName;
//private static int appType = APP_PAID;
private static String codeActionResponseString = "response";
// Provide access points for the apps to store the data
public static void storeDataToPhone(Context context, DataToBeShared data) {
SharedPreferences settings = context.getSharedPreferences(prefName, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
// Put the data in the shared preferences using standard commends.
// See the android developer page for SharedPreferences.Editor for details.
// Code for that here
// And store it
editor.commit();
}
So far, this is a fairly standard shared preferences storage system. Now is where the fun starts. First, make sure that there is a private method for getting the data stored above, and a private method for broadcasting it.
private static DataToBeshared getData(Context context) {
SharedPreferences settings = context.getSharedPreferences(prefName, Context.MODE_PRIVATE);
DataToBeShared result = new DataToBeShared();
// Your code here to fill out result from Shared preferences.
// See the developer page for SharedPreferences for details.
// And return the result.
return result;
}
private static void broadcastData(Context context, DataToBeShared data, String intentActionName) {
Bundle bundle = new Bundle();
bundle.putInt(codeAppType, appType);
bundle.putParcelable(codeData, data);
Intent intent = new Intext(intentActionString);
intent.putEXtras(bundle);
context.sendBroadcast(intent);
}
Create a BroadcastReceiver class to catch data responses from the other app for our data:
static class CatchData extends BroadcastReceiver {
DataToBeShared data = null;
Long timestamp = 0L;
int versionListeningFor = Version.VERSION_UNKNOWN;
Timeout timeout = null;
// We will need a timeout in case the other app isn't actually there.
class Timeout extends CountDownTimer {
Context _context;
public Timeout(Context context, long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
_context = context;
}
#Override
public void onFinish() {
broadcastAndCloseThisBRdown(_context);
}
#Override
public void onTick(long millisUntilFinished) {}
}
// Constructor for the catching class
// Set the timeout as you see fit, but make sure that
// the tick length is longer than the timeout.
CatchDPupdate(Context context, DataToBeShared dptsKnown, Long timeKnown, int otherVersion) {
data = dptsKnown;
timestamp = timeKnown;
versionListeningFor = otherVersion;
timeout = new Timeout(context, 5000, 1000000);
timeout.start();
}
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
if (extras == null) return;
// Check it's the data we want
int sendingVersion = extras.getInt(codeAppType, APP_UNKNOWN);
if (sendingVersion != versionListeningFor) return;
// This receiver has served its purpose, so unregister it.
context.unregisterReceiver(this);
// We've got the data we want, so drop the timeout.
if (timeout != null) {
timeout.cancel();
timeout = null;
}
Long tsInc = extras.getLong(codeTimestamp, 0L);
DataToBeShared dataInc = extras.getParcelable(codeData);
// Now, you need to decide which set of data is better.
// You may wish to use a timestamp system incorporated in DataToBeStored.
if (/* Incoming data best*/) {
data = dpInc;
// Make it ours for the future
storeDataToPhone(context, data);
}
// Send the data out
broadcastAndCloseThisBRdown(context);
}
private void broadcastAndCloseThisBRdown(Context context) {
broadcastData(context, data, responseActionString);
}
}
Now, provide the static access function for the apps to use. Note that it doesn't return anything, that's done by the response catcher above.
public static void geDataFromPhone(Context context) {
DataToBeStored myData = getData(context);
// See security discussion point 2 for this next line
String internalResponseActionString = "com.me.my.app.blah.hohum." + UUID.randomUUID();
// Instantiate a receiver to catch the response from the other app
int otherAppType = (appType == APP_PAID ? APP_FREE : APP_PAID);
CatchData catchData = new CatchData(context, mydata, otherAppType);
context.registerReceiver(catchData, new IntentFilter(internalResponseActionString));
// Send out a request for the data from the other app.
Bundle bundle = new Bundle();
bundle.putInt(codeAppType, otherAppType);
bundle.putString(codeResponseActionString, internalResponseActionString);
bundle.putString(CatchDataRequest.code_password, CatchDataRequest.getPassword());
Intent intent = new Intent(responseActionString);
context.sendBroadcast(intent);
}
That's the core of it. We need one other class, and a tweak to the manifest. The class (to catch the requests from the other app for the data:
public class CatchDataRequest extends BroadcastReceiver {
// See security discussion point 1 below
public static String code_password = "com.newtsoft.android.groupmessenger.dir.p";
public static String getPassword() {
return calcPassword();
}
private static String calcPassword() {
return "password";
}
private static boolean verifyPassword(String p) {
if (p == null) return false;
if (calcPassword().equals(p)) return true;
return false;
}
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;
String passwordSent = bundle.getString(code_password);
if (!verifyPassword(passwordSent)) return;
int versionRequested = bundle.getInt(StoredInfoManager.codeAppType);
String actionStringToRespondWith = bundle.getString(StoredInfoManager.codeResponseActionString);
// Only respond if we can offer what's asked for
if (versionRequested != StoredInfoManager.appType) return;
// Get the data and respond
DataToBrStored data = StoredInfoManager.getData(context);
StoredInfoManager.broadcastData(context, data, actionStringToRespondWith);
}
}
In the manifest, be sure to declare this class as a Receiver with the action name matching StoredInfoManager.responseActionString
<receiver android:name="com.me.my.app.CatchDataRequest" android:enabled="true">
<intent-filter>
<action android:name="com.me.my.app.DATA_RESPONSE"/>
</intent-filter>
</receiver>
Using this is relative simple. The class you are using the data in must extend BroadcastReceiver:
public class MyActivity extends Activity {
// Lots of your activity code ...
// You'll need a class to receive the data:
MyReceiver receiver= new MyReceiver();
class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
if (extras == null) return;
// Do stuff with the data
}
}
// But be sure to add the receiver lines to the following methods:
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(receiver);
}
#Override
public void onResume() {
super.onResume();
this.registerReceiver(receiver, new IntentFilter(StoredInfoManager.receiver_action_string));
}
}
// To store the data
StoredInfoManager.storeDataToPhone(contextOfApp, data);
// To retrieve the data is a two step process. Ask for the data:
StoredInfoManager.getData(contextOfApp);
// It will arrive in receiver, above.
}
Security
The weakness of this method is that anyone can register a receiver to catch the communication between the two apps. The code above circumvents this:
Make the request broadcast hard to fake through the use of a password. This answer sin't a place to discuss how you might make that password secure, but it is important to realise that you can't store data when you create the password to check it against later - it's a different app that will be checking.
Make the response harder to catch by using a unique action code each time.
Neither of these is fool proof. If you're simply passing around favourite app colours, you probably don't need any of the security measures. If you're passing around more sensitive information, you need both, and you need to think about making the password appropriately secure.
Other improvement
If you wish to check if the other version is installed before sending out the query and waiting for an answer, see Detect an application is installed or not?.

I've collected information from a number of stackoverflow answers to provide a way to copy all SharedPreference data from one app to another. In my particular case I'm using product flavours for a free and a pro app, and I want to copy from free to pro.
CAUTION: This only works if you have not released either version on the play store. If you add (or remove) sharedUserId to your app after it is on the play store, your users won't be able to update without uninstalling. I learnt this the hard way. Thanks Google..
Add sharedUserId to your manifest in both apps. Note that this will only work if both apps are signed with the same certificate.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my.package.name.free"
android:sharedUserId="my.package.name">
Then call this method when you first intialize the pro app.
private void getSettingsFromFreeApp() {
// This is a build config constant to check which build flavour this is
if (BuildConfig.IS_PRO) {
try {
Context otherAppContext = this.createPackageContext("my.package.name.free", Context.MODE_PRIVATE);
SharedPreferences otherAppPrefs = PreferenceManager.getDefaultSharedPreferences(otherAppContext);
Map<String, ?> keys = otherAppPrefs.getAll();
SharedPreferences.Editor editor = prefs.edit();
for(Map.Entry<String, ?> entry : keys.entrySet()){
Object value = getWildCardType(entry.getValue());
Log.d("map values", entry.getKey() + ": " + entry.getValue());
if (entry.getValue() instanceof Boolean) {
editor.putBoolean(entry.getKey(), (boolean) value);
editor.apply();
} else if (value instanceof Long) {
editor.putLong(entry.getKey(), (long) value);
editor.apply();
} else if (value instanceof Float) {
editor.putFloat(entry.getKey(), (float) value);
editor.apply();
} else if (value instanceof Integer) {
editor.putInt(entry.getKey(), (int) value);
editor.apply();
} else if (value instanceof String) {
editor.putString(entry.getKey(), String.valueOf(value));
editor.apply();
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
private Object getWildCardType(Object value) {
return value;
}
Also, according to this answer you will want to call getSettingsFromFreeApp() before any other call to get preferences in your app.

Related

Access SharedPreference inside a class that extends BroadcastReceiver

I'm trying to call my method(saveSharedpreferences.setCountReceived) from a class (SMSSendingWeb) that extends BroadcastReceiver, to a custom SaveSharedPreferences class.
My problem is it can't save into the SharedPreferences nothing happens.
I'm confused where is the problem of my code.
My argument in this method has error when
saveSharedpreferences.setCountReceived(SMSSendingWeb.this, countReceived);
I changed it to context has also error
saveSharedpreferences.setCountReceived(context, countReceived);
Here's my code: Please look into setCountReceived()
public class SaveSharedPreferences {
static final String PREF_USER_NAME= "username";
static final String PREF_COUNT_RECEIVED= "received";
static SharedPreferences getSharedPreferences(Context ctx) {
return PreferenceManager.getDefaultSharedPreferences(ctx);
}
//==========================================================
public static void setCountReceived(Context ctx, Integer countReceived)
{
SharedPreferences.Editor editor = getSharedPreferences(ctx).edit();
editor.putInt(PREF_COUNT_RECEIVED, countReceived);
editor.commit();
}
}
Android code:
public class SMSSendingWeb extends BroadcastReceiver {
RestService restService;
public static Integer countReceived = 0;
SaveSharedPreferences saveSharedpreferences;
#Override
public void onReceive(Context context, Intent intent) { //for Receiving
restService = new RestService();
saveSharedpreferences = new SaveSharedPreferences();
Bundle b = intent.getExtras();
Object[] pduObj= (Object[]) b.get("pdus");
String mobileno = null;
String message = null;
String data = null;
for(int i=0;i<pduObj.length;i++){
SmsMessage smsMessage=SmsMessage.createFromPdu((byte[]) pduObj[i]);
//get the sender number
mobileno=smsMessage.getOriginatingAddress();
//get the sender message
message=smsMessage.getMessageBody();
data="From : "+mobileno+"\n Message : "+message;
}
SMSInbox sms = new SMSInbox();
sms.MobileNo = mobileno;
sms.Message = message;
restService.getService().addSMS(sms, new Callback<String>() {
#Override
public void success(String s, Response response) {
//Toast.makeText(, "Successfully added", Toast.LENGTH_LONG).show();
countReceived += 1;
saveSharedpreferences.setCountReceived(SMSSendingWeb.this, countReceived);
Log.d("API inside restService", "count: " + countReceived);
}
#Override
public void failure(RetrofitError error) {
//Toast.makeText(MainActivity.this, error.getMessage().toString(), Toast.LENGTH_LONG).show();
}
});
countReceived += 1;
Log.d("API outside restService", "count: " + countReceived);
saveSharedpreferences.setCountReceived(context, countReceived);
}
You are trying to access the Preferences and not Shared Preference there is a subtle difference between the two. As from this answer
Preferences is an Android lightweight mechanism to store and retrieve
pairs of primitive data types (also called Maps, and Associative
Arrays).
In each entry of the form the key is a string and the value must be a
primitive data type.
WHEN WE NEED THEM:
PREFERENCES are typically used to keep state information and shared
data among several activities of an application.
Shared Preferences is the storage, in android, that you can use to
store some basic things related to functionality, users' customization
or its profile.
Suppose you want to save user's name in your app for future purposes.
You cant save such a little thing in database, So you better keep it
saved in your Preferences. Preferences is just like a file , from
which you can retrieve value anytime in application's lifetime in a
KEY-VALUE pair manner.
Take another example, If you use whatsapp, we have a wallpaper option
there. How the application knows which image serves as wall-paper for
you whenever you open your whatsapp. This information is stored in
preferences. Whenever you clear data for any app, preferences are
deleted
You are using Preferences and trying to write a value in Shared Preference so I just changed your code to using the Shared Preference.
For saving preferences
public static void setCountReceived(Context ctx, Integer countReceived)
{
SharedPreferences.Editor editor = getSharedPreferences(YOUR_PREF_NAME,MODE_PRIVATE).edit();
editor.putInt(PREF_COUNT_RECEIVED, countReceived);
editor.commit();
}
For retrieving preferences,
static SharedPreferences getSharedPreferences(Context ctx) {
return context.getSharedPreferences(YOUR_PREF_NAME,MODE_PRIVATE);
}

Best practices of transferring data from service to activity

What is the best practice for transfer of some (not huge, but often) amount of data from several services to activity?
I'm using BroadcastReceiver in my MainActivity this way:
private class Receiver extends BroadcastReceiver{
public Receiver() {
super();
}
#Override
public void onReceive(Context context, Intent intent) {
// Receiving and showing received symbols
if (intent.getAction() == getString(R.string.key_recognized)) {
char key = intent.getCharExtra("key" , '0');
MainActivity.this.addText(key);
}
// Received transfer ending flag
if (intent.getAction() == getString(R.string.transfer_ended)) {
mServiceWorking = false;
MainActivity.this.mToneButton.setText(getText(R.string.send_text));
}
// Recieving an array (~2Kb) and drawing it on correspondig ImageView
if (intent.getAction() == getString(R.string.spectrum_ready)) {
Spectrum spectrum = (Spectrum) intent.getSerializableExtra("spectrum");
if (spectrum != null) {
drawSpectrum(spectrum);
}
}
}
}
Broadcasts are sended from services somehow like this:
Intent taskIntent = new Intent();
taskIntent.setAction(getString(R.string.key_recognized));
taskIntent.putExtra("key", key);
this.sendBroadcast(taskIntent);
Is this normal code or my hands should be cut off in some way?)
I don't see why passing the data via extras is not the best choice. For me, is the safest, and fastest way to pass data between activities or intents.
You can simple use post method from Handler class
For normal data up to a maximum of 1MB (see this answer) you can use extra data of intents.
For bigger data, or data that is not serializable, you could store that data in one of following:
In a file. Pass URI in extra data.
In the shared preferences.
In a special class that holds your data. Store it in a hashmap, where you pass the key in your extra data of the intent.
The class could look like this:
private static final Map<Long, Object> storage = new HashMap<>();
public static synchronized long store(Object tempData){
if(storage.size() < Long.MAX_VALUE) {
storage.put(storage.size() + 1l, tempData);
return storage.size();
}else{
return -1;
}
}
The store()-Method returns a long value, that can be used to identify the stored data. This way is faster than storing your data in a file and can be bigger than 1MB. But keep in mind, that you have limited memory in android, so don't store to many or too big data. Remove them as soon as you retrieved them.

Global variables not passing properly

I have created a class that holds common variables and functions and is inherited by the activity classes that interface with the different UI pages in my app. I have been passing information between classes and activities using getVariable() and setVariable(input) functions. Suddenly, I can no longer pass information this way (it had been working well until recent edits, and now I can't figure out which change screwed this up). I have used Log outputs to determine that the data is storing properly - with the setVariable(input) functions - but when called later with the getVariable() functions it returns null. Any thoughts?
*Note, I recently started incorporating fragments into my project, extending FragmentActivity instead of Activity on my main class. I don't think this is causing the problem, but could it? If it does, whats the best practice to pass global variable info, and use fragments?
Code samples:
Main Inherited class:
public class MenuBarActivity extends FragmentActivity {
private String keyA;
private String keyB;
private int token;
private String Salt;
private long expires;
public String getKeyB() {
return keyB;
}
public String getKeyA() {
return keyA;
}
public int getTokenID() {
return token;
}
public void setToken(int tkn) {
token = tkn;
}
public void setKeyB(String kyB) {
keyB = kyB;
}
public void setKeyA(String kyA) {
keyA = kyA;
}
//Other common functions
}
LogIn Activity Class (gets log in info from web, stores into global variables):
public class WebContentGet extends MenuBarActivity{
public int tryLogOn(String uEmail, String pw) {
//call to get new keys on start up
JSONObject jObSend = new JSONObject();
try {
jObSend.put("email", uEmail);
jObSend.put("password", pw);
t.start();
t.join();
if(getStatus() == USER_STATUS_SUCCESSFULLOGIN){
String data = getData();
JSONObject jObReturn = new JSONObject(data);
String kyA = jObReturn.getString("keyA");
String kyB = jObReturn.getString("keyB");
int tkn = Integer.parseInt(jObReturn.getString("tokenID"));
String salt = jObReturn.getString("salt");
long exp = Long.parseLong(jObReturn.getString("expiration"));
int uID = Integer.parseInt(jObReturn.getString("userID"));
// Log outputs confirm data being read properly, and reported to setX() functions
setToken(tkn);
setKeyA(kyA);
setKeyB(kyB);
setSalt(salt);
setExpires(exp);
Log.d("WebContentGet tryLogIn","login values stored");
}
return getStatus();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return getStatus();
}
}
Activity Class, checks if keyA/B/etc stored:
public class UserLogIn2 extends MenuBarActivity implements EmailListener {
String emailIn;
String pwIn;
Context context = this;
#Override
public void onEmailLogInClick(String email, String pw) {
Log.d("UserLogin2", "onEmailLogInClick");
emailIn = email;
pwIn = pw;
emailIn = emailIn.trim();
emailIn = emailIn.toUpperCase();
Log.d("prepped email", emailIn);
pwIn = pwIn.trim();
WebContentGet webOb = new WebContentGet();
int webLog = webOb.tryLogOn(emailIn, pwIn);
if (webLog == USER_STATUS_SUCCESSFULLOGIN) {
int tkn = getTokenID();
long exp = getExpires();
String kya = getKeyA();
String kyb = getKeyB();
String slt = getSalt();
Log.d("UserLogIn2 - token", String.valueOf(tkn));
//Log statements confirm that getX() functions returning null
session.storeLoginSession(emailIn, pwIn, thisUser, tkn, exp, kya, kyb, slt);
Intent intent1 = new Intent(context, MainActivitiy.class);
startActivity(intent1);
} else {
showDialog(this, "Log in failure", "Incorrect Password");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.userlogin2);
}
}
This cannot work, because you have two differend instances of your MenuBarActivity. Also that is not the way to pass data from one activity to another in android.
If you want to use data from one activity in another activity, you have to add them to an intent in the activity which provides the data, and extract them in the other. For more information see here: How do I pass data between Activities in Android application?
If you don't want to start the activity and send the data with the intent, you have to store the data somewhere e.g. SharedPreferences and fetch them again: How to use SharedPreferences in Android to store, fetch and edit values

analytics - google tutorial for measuring referrals - is this tutorial ok?

According to Google Analytics Campaign Measuring (version 3) I followed by theirs tutorial, but in onStart we only create calls MapBuilder.createAppView() without sending this data, should I change it to
EasyTracker.getInstance(this).send(MapBuilder.createAppView().setAll(getReferrerMapFromUri(uri)).build());
? I think there is an error because I don't see any refferals on my Google Analytics Panel.
Here is the Google Analytics Campaing Measuring code:
public class MainActivity extends Activity {
private static final String GA_PROPERTY_ID = "UA-XXXX-Y";
private static final String SCREEN_LABEL = "Home Screen";
private static final String CAMPAIGN_SOURCE_PARAM = "utm_source";
Tracker mTracker;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTracker = GoogleAnalytics.getInstance(this).getTracker(GA_PROPERTY_ID);
}
#Override
public void onStart() {
super.onStart();
mTracker.set(Fields.SCREEN_NAME, SCREEN_LABEL);
Intent intent = this.getIntent();
Uri uri = intent.getData();
MapBuilder.createAppView().setAll(getReferrerMapFromUri(uri));
}
Map<String,String> getReferrerMapFromUri(Uri uri) {
MapBuilder paramMap = new MapBuilder();
if (uri == null) { return paramMap.build(); }
if (uri.getQueryParameter(CAMPAIGN_SOURCE_PARAM) != null) {
paramMap.setCampaignParamsFromUrl(uri.toString());
} else if (uri.getAuthority() != null) {
paramMap.set(Fields.CAMPAIGN_MEDIUM, "referral");
paramMap.set(Fields.CAMPAIGN_SOURCE, uri.getAuthority());
}
return paramMap.build();
}
}
I got the same problem.
To retrieve the "general campaign and traffic source attribution", I tried the sample code of https://developers.google.com/analytics/devguides/collection/android/v3/campaigns
And my Uri is generated by "Google Play URL Builder"
https://play.google.com/store/apps/details?id=com.flipr.ga3&referrer=utm_source%3Dsource3%26utm_medium%3Dmedium3%26utm_term%3Dterm3%26utm_content%3Dcontent3%26utm_campaign%3Dcampaign3"
When click the app and it did launch my app. But the "getQueryParameter(CAMPAIGN_SOURCE_PARAM)" returned null.
I found the exact parameter name in Uri is "referrer", instead of "utm_source".
I think that's why the getQueryParameter(CAMPAIGN_SOURCE_PARAM) returned null.
I think the sample is wrong and we should:
1. String str1 = getQueryParameter("referrer")
2. Then, retrieve all the key-vaue pairs into map
3. createAppView().setAll(map)
I have solved the problem. On some level.
Documentation editor have done too much operation.
Instead:
MapBuilder.createAppView().setAll(getReferrerMapFromUri(uri));
Should be:
mTracker.send(getReferrerMapFromUri(uri));
Because .send() needs Map and the getReferrerMapFromUri(uri) return this.

More elegant way to restore state of Android Application subclass?

In my application, I extend the application class to maintain information relevant to the authenticated user. However, after running through some tests where I disallow background process, open up another application(thus killing mine), and reopen mine, I notice that this state is lost(variables returning to their default value). I realized that the Application class doesn't have any lifecycle callbacks, besides onCreate, like the Activities do, which I thought the elegant solution would be. So I decided to write this information to a SharedPreference, so that it can be recovered when needed. Is this the correct solution, or is there a more elegant one?
Relevant sample code for reference:
public class ApplicationUser extends Application {
private static final String PREF_KEY_USER = "prefKeyUser";
private static final String PREF_KEY_ID = "prefKeyID";
private static final String PREF_KEY_FIRST_NAME = "prefKeyFirstName";
private static final String PREF_KEY_LAST_NAME = "prefKeyLastName";
private static final String PREF_KEY_EMAIL = "prefKeyEmail";
private User mUser;
private SharedPreferences mSharedPreferences;
#Override
public void onCreate() {
super.onCreate();
mSharedPreferences = getSharedPreferences(PREF_KEY_USER,MODE_PRIVATE);
}
/**
*
* #return the user
*/
public User getUser() {
if (mUser == null) {
int id = mSharedPreferences.getInt(PREF_KEY_ID, -1);
String firstName = mSharedPreferences.getString(PREF_KEY_FIRST_NAME, "");
String lastName = mSharedPreferences.getString(PREF_KEY_LAST_NAME, "");
String email = mSharedPreferences.getString(PREF_KEY_EMAIL, "");
mUser = new User(id, firstName, lastName, email);
}
return mUser;
}
/**
* sets user, writing to shared preferences as well
* #param user
*/
public void setUser(User user) {
mUser = user;
Editor e = mSharedPreferences.edit();
e.putInt(PREF_KEY_ID, user.getID());
e.putString(PREF_KEY_FIRST_NAME, user.getFirstName());
e.putString(PREF_KEY_LAST_NAME, user.getLastName());
e.putString(PREF_KEY_EMAIL, user.getEmail());
e.commit();
}
}
It seems like the way I did it was the correct way, so I am just going to add this as the answer. If this is the incorrect procedure, please correct me.

Categories

Resources