In my android application I coded to read shared data of another Android application and then to delete that data from shared preferences.
My code as follows :
try {
con = createPackageContext("com.testapp.ws", 0);
SharedPreferences pref = con.getSharedPreferences("demopref", Context.MODE_PRIVATE);
ipAdr = pref.getString("demostring", "No Value");
pref.edit().remove("demopref").commit();
}
This shows following error:
06-12 11:52:07.400: E/ApplicationContext(3587): Couldn't rename file /data/data/com.testapp.ws/shared_prefs/demopref.xml to backup file /data/data/com.testapp.ws/shared_prefs/demopref.xml.bak
I used this method in my other application to make shared data
public void shareData(){
String strShareValue = ip;
SharedPreferences prefs = getSharedPreferences("demopref",Context.MODE_WORLD_READABLE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("demostring", strShareValue);
editor.commit();
}
How can I do that ? Is there anything to add Manifest file ?
Thanks!
If you use android:sharedUserId in your manifest files it should work. This is a permissions issue I've been running into myself.
To do this, you simply need to add a tag such as android:sharedUserId="com.example.you" to your <manifest> tag in your AndroidManifest.xml file for both of your applications (and the com.example.you has to be the same in both apps, of course).
Example start of the manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="package.name"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="com.example.you" >
...
For an indepth description of the way to get this working see my answer on How can I share a SharedPreferences file across two different android apps?
You need to use MODE_WORLD_READABLE instead of MODE_PRIVATE. Read the docs for further information.
Here's a tutorial to check further if you have any more mistakes.
While the other solutions here will technically work in most circumstances, the framework that Android has provided to you for sharing data between processes/applications is the ContentProvider. It may seem like a lot of extra abstraction, but it's the one that is guaranteed to work.
While the interface for this component mirrors the calls into a database, the underlying data structure can be anything you like. In specific, you can return a MatrixCursor in response to queries that provides the contents of your SharedPreferences object, and you can implement a URI scheme for delete/update calls that can be used to modify the preferences from other applications.
Here is a link to a blog post from another developer who used MatrixCursor to share preferences.
HTH
I've been struggling with SharedPreferences the last three days, but I think I finally solved it for myself. Here's a few tips and gotchas you should try out that might help you (and loads of other stackoverflow users).
Please note that all my observations are for ICS (4.0.2 and 4.0.4).
If you change the android:sharedUserId, delete the app as file/folder permissions will be incorrect. So you shouldn't change that value if you have already relased the app.
If you change the Context.MODE_* values, delete the app's data (or the whole app) to ensure file permissions aren't incorrect.
If you use android:sharedUserId, be sure to sign the apps with the same certificate.
Use a different filename for the preferences in the two apps. I had problems with the app just reading the local shared preferences even though I used createPackageContex().
This is what worked for me in the end:
I used the same android:sharedUserId for the two apps. (Not the same android:process.)
I used Context.MODE_WORLD_READABLE for both reading and writing local prefs, and for reading the other app's prefs.
I used Context.CONTEXT_IGNORE_SECURITY when calling createPackageContext().
Related
I followed the manual for implementing SharePreferences capture inside ACRA. What I basically did was including the following line in the configuration (is one of the lines of the complete configuration:
customReportContent = { APP_VERSION,
ANDROID_VERSION,
SHARED_PREFERENCES }
additionalSharedPreferences={"EXTRA_MESSAGE","NOTIF_ACTIVATED"}
I followed the information from this manual and the details on this one .
However, all the preferences I received in my Cloudant database appear as empty. I made sure that ALL variables are not the default variables, specially on this 2 ones, which are changed earlier in the configuration, I tricked my code just before the message changing intentionally those variables. But, I am still receiving empty values.
I order to double check I included the email option to check what data was written by ACRA, also filling the field empty. The evidences I have:
- Report at Clound Ant with SharedPreferences are empty.
- The email text introduced by ACRA and offered to the user is also having the field as "empty".
- No error output from ACRA in any operation
After investigating during the morning I am blocked and I don't know what else to do.
SDK21 and ACRA4.5.0 using a 2.3 android mobile.
This was actually a wrong usage of SharePreferences in ACRA and not actually a bug in ACRA.
When the SharedPreferences is instantiated is a good practice to create a dedicated file using a code line like this one:
String MyPREFERENCES = "MYPREFS";
sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
In this case "MyPREFENCES" will be the new preferences name. In order to properly use ACRA this new file needs to be explicitly added in the ACRA configuration using the following:
additionalSharedPreferences={"MYPREFS"}
The problem I was having was that I included the fields that I included in my shared preferences and NOT the preferences file that I created. Just adding the proper filename everything was working ok.
I'm working on a project where I have a core application and multiples plugins which are different apks. I would like to share some data between my different modules (for ex. the name of the user or his email address). I tried to give them all the same sharedUserId by adding it to their manifest :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.giom.mymodule1"
android:sharedUserId="com.giom">
My modules are really similar and both save and try retrieve their sharedpreferences the same way :
Context mainAppContext = getActivity().getApplicationContext().createPackageContext("com.giom.mainapp", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
SharedPreferences sharedPreferences = mainAppContext.getSharedPreferences("sharedpreferences", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
sharedPreferences.edit().putString("EMAIL", email).commit();
And
Context mainAppContext = getActivity().getApplicationContext().createPackageContext
("com.giom.mainapp", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
SharedPreferences sharedPreferences = mainAppContext.getSharedPreferences("sharedpreferences", Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
String email = sharedPreferences.getString("EMAIL", null)
Both codes are from my PreferenceActivities which are FragmentActivity. The problem is this seems to be working ; for example if I change the value in one of the modules and reboot the phone the other is changed. But if I open one of the activities, then the other, change the value in one of them and come back to the other I will still get the old one until I reboot. It's working like if there was some kind of cache...
My intuition is that I'm not using the right Context and that I should replace getActivity() by something else but I don't know what...
Thanks in advance for your help.
PS: I read that this method was depreciated so if you have any idea of how I should share my data feel free to tell me :)
Ok, found the answer here : https://stackoverflow.com/a/11025235/3628452
The getSharedPreferences method appears to check for a .bak file to
load the preferences from. This is why it says in the documentation
that it will not work across multiple processes; to minimize I/O, it
loads the prefs ONCE when you grab them and only backs them up when
you close your application/activity
Which means that if I don't open/close my modules I'll still have the data from the bak file from when I opened it...
When I originally wrote and published my app, I was using a custom written activity to handle application settings. I used custom file name to store shared preferfences, like this:
getSharedPreferences("custom_settings_file",MODE_PRIVATE);
But now I'm refactoring my app and I would like to implement PreferenceActivity or PreferenceFragment and an xml file with PreferenceScreen section. Every tutorial or example that I've seen is using
getDefaultSharedPreferences(context);
to retrieve shared preferences, because PreferenceActivity assumes default filename to store preferences and there's no way to tell it to use a different one(at least I couldn't find one after an hour of searching and reading documentation).
So now I have a problem. If I just simply use the new default file, existing users of my app will lose their settings when they update the app, because the new application will not know anything about "custom_settings_file". What would be the best way to move the data from an old file to a new one on app update?
Here are the possible options that I could come up with:
Extend Application class and implement a piece of code in onCreate() so that every time my app is launched, it would check for existence of "custom_settings_file" and move it's contents to the new one. But running a block of code on every app launch seems like wasting too much processing resources for an operation that only needs to run once.
Just notify the user that their old settings are gone. But obviously this is not acceptable.
Is there a better solution, than option 1? Perhaps someone has already faced a similar problem?
What is preventing you from doing number 1 only once?
Just add a "migration" boolean to the new sharedpreferences.
If you also load the xml preference file then you can try this:
PreferenceManager.setDefaultValues(context, YOUR_PREFERENCE_NAME, MODE_PRIVATE, R.xml.preference_file, false);
If not (you want to add each preference item dynamically in your code) then you can do like this:
PreferenceManager pm = getPreferenceManager();
pm.setSharedPreferencesMode(MODE_PRIVATE);
pm.setSharedPreferencesName(YOUR_PREFERENCE_NAME);
In case you still want to use the defaultSharedPreference and process the migration then ... I'm writing this and I see Nicklas's answer, so I'm done here.
Could you add value in your new SharedPreferences that records whether you are a new install or an upgrade. If you don't have the setting in your sharedpreferences, check to see if you have an old preferences file in the way you were before. Then convert those preferences to your new method, and set your private setting indicating that it's been upgraded. Then just set the new value indicating the new state and you won't need to check your old preferences any more.
I am having an odd issue in which the SharedPreferences are not being updated upon returning to an app. Here's the scenario:
I have two projects that use the same shared preferences. Project1 and Project2. They are separate but related apps. They are signed with the same key and use sharedUserId to share information.
Project1 opens Project2.
Project2 retrieves the SharedPreferences file and writes to it via this method:
Context prefsContext = c.createPackageContext(packageNameOfProject1, Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences prefs = prefsContext.getSharedPreferences(fileName, Context.MODE_PRIVATE);
SharedPreferences.editor editor = prefs.edit();
editor.putBool("bool1", value1);
editor.putBool("bool2", value2);
...
editor.putBool("boolN", valueN);
editor.apply();
Once that is done, I return to Project1 by calling finish().
Project1 then reads the data like so:
SharedPreferences prefs = getSharedPreferences(getPreferencesFileName(), Context.MODE_PRIVATE);
Boolean value1 = prefs.getBoolean(fileName, false);
Boolean value2 = prefs.getBoolean(fileName, false);
...
Boolean valueN = prefs.getBoolean(fileName, false);
Map<String, ?> mappings = prefs.getAll();
Set<String> keys = mappings.keySet();
for(String key : keys) {
log.d(TAG, "_____");
log.d(TAG, "Key = " + key);
log.d(TAG, "Value = " + mappings.get(key));
}
The problem is the values are not updated in Project1. I can tell based off the logs at the end that the file isn't even generating mappings. However, I can verify that the xml is being updated. If I force stop the app then restart it, all the mappings are there in Project1. All the values are correct. However, I need them updated when the user leaves Project2. I feel like there's something I'm missing here but can not spot it.
The only things I have been able to find on the subject is:
SharedPreferences.Editor not being updated after initial commit
SharedPreferences value is not updated
These don't help as I'm already doing that.
I have WRITE_EXTERNAL_STORAGE set in both manifests. The fileName is the same (else I wouldn't be able to read the file when I reenter the app).
EDIT:
I should note that I did try to do editor.commit() instead of editor.apply() as I thought I was facing a race condition. The problem still persisted. I'm thinking that for some reason, the old reference to the SharedPreference in Project1 is being used instead of a new one even though I'm lazy-loading it each time.
EDIT2:
Ok, to further test to see what id going on. I decided to try the opposite direction.
In Project1 I do:
Float testFloat (float) Math.random();
Log.d("TEST_FLOAT", "Project1: TEST_FLOAT = " + testFloat);
prefs.edit().putFloat("TEST_FLOAT", testFloat).commit();
In Project2 I do:
Log.d("TEST_FLOAT", "Project2: TEST_FLOAT = " + prefs.getFloat("TEST_FLOAT", 0.0f));
I then go back and forth between the two like so: Project1->Project2->Project1->Project2->Project1->Project2 and here is the logcat result:
Project1: TEST_FLOAT = 0.30341884
Project2: TEST_FLOAT = 0.30341884
Project1: TEST_FLOAT = 0.89398974
Project2: TEST_FLOAT = 0.30341884
Project1: TEST_FLOAT = 0.81929415
Project2: TEST_FLOAT = 0.30341884
In other words, it's reading and writing to the same file. However, it's keeping the mapping that it had when it was first opened it in the project. Even though I close the project, the mapping remains until the application is force stopped.
EDIT: I'm still getting upvotes on this answer even though it recommends a method that has since been deprecated. If you need consistent data through multi-process, then you need to use something other than SharedPreferences like a ContentProvider backed by a file system or database.
https://developer.android.com/reference/android/content/Context#MODE_MULTI_PROCESS
Final answer:
Replace
getSharedPreferences(fileName, Context.MODE_PRIVATE);
with
getSharedPreferences(fileName, Context.MODE_MULTI_PROCESS);
As per document:
Context.MODE_MULTI_PROCESS
SharedPreferences loading flag: when set, the file on disk will be
checked for modification even if the shared preferences instance is
already loaded in this process. This behavior is sometimes desired in
cases where the application has multiple processes, all writing to the
same SharedPreferences file. Generally there are better forms of
communication between processes, though.
This was the legacy (but undocumented) behavior in and before
Gingerbread (Android 2.3) and this flag is implied when targeting
such releases. For applications targeting SDK versions greater than
Android 2.3(Gingerbread), this flag must be explicitly set if desired.
I knew there was a simple oversight in this.
Try to call editor.commit(); instead of editor.apply();. Normally they should do the same, but I noticed there some weird behaviour sometimes.
From the SharedPreferences documentation the method "apply()" writes asynchronously (delayed) to the file and the method "commit()" writes the information synchronously (immediatly) to the file.
Also from the documentation, they say that you don't need to wary about the activity life cycle while using any of the above methods, as they ensure the "apply()" writes are completed before status changes, if they are running in the same system process.
However, as you are using two different projects, they run in two different processes and you can't be sure that "apply()" on project 2 will be concluded before the "onResume()" starts on project 1.
I suggest that you try "commit()" instead of "apply()" to force synchronous write. If this don't solve the issue, you can add a delay of a couple of seconds before reading the preferences in project 1, just to check if the issue is related to this delayed write.
--EDITED--
To debug the issue let's do the following:
1-In Eclipse Select/Add the view "File Explorer" and navigate to the directory:
/data/data/[your package name]/shared_prefs
your package name should be something like "com.myproject.shared"
2-Select the file with your saved preferences and press the button "download to PC".
3-Check if file contents match your expectations.
good luck.
I just curious. There are 3 method:
1. getPreferenceManager().setSharedPreferencesName(String PrefName);
2. PreferenceManager.getDefaultSharedPreferences(Context context)
3. Context.getSharedPreferences (String name, int mode)
As I know, the third method is only used when the first method is used, right?
But with 3 method we also use addPreferencesFromResource(int resID);
so, what is the difference? When can we use one of these method?
Thanks!
Let's go one step at a time:
setSharedPreferencesName() is method that allows to set the name of the preference group for later use. This is helpful for example when using the helper class of
PreferencesActivity before loading a preferences from XML resource file by calling addPreferencesFromResource(). It is therefore not as common as the other 2 methods you mentioned above.
getDefaultSharedPreferences() uses a default name, usually stored as /data/data/com.package.name/shared_prefs/com.package.name_preferences.xml.
It is commonly used. Note that this default is set per application.
The alternative method - getSharedPreferences() requires to indicate a specific preference (file) name and an operation mode.
As appears also in another answer about shared preferences,
getDefaultSharedPreferences() in fact uses Context.getSharedPreferences, so the result is the same, but without the flexbility to split to multiple preference files, that is offered by getSharedPreferences(). Sharing the preferences between apps using
a MODE_WORLD_READABLE operation indicator is also something possible using getSharedPreferences(), but is rarely used.
IMHO, getDefaultSharedPreferences() can be safely used without going into the confusion of multiple preference file names that are prone to typos and confusion.
If someone knows of a good reason to use getSharedPreferences() and not getDefaultSharedPreferences(), please let me know by commenting here.
getDefaultSharedPreferences() uses a default preference-file name like "com.example.something_preferences". This default is set per application, so all activities in the same app context can access it easily as in the following example:
SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(this);
if (spref.contains("email")) {
String sEmailAddr = spref.getString("email", "");
}
The preferences are usually stored at /data/data/com.package.name/shared_prefs/com.package.name_preferences.xml
getSharedPreference is the best way because using getDefaultSharedPreferences has some flaws
Actualy getDefaultSharedPreferences doesn't work correct on some
devices when build with targer api 13
Starting app from shortcut and from menu gives me different
DefaultSharedPreferences. After removing DefaultSharedPreferences
from my code - it works perfect. I can't just say: people dont make
shrotcuts, so I had to change code
This link may also help