I'm having trouble retrieving values (on an Android 9.0 device) from shared Preferences after I re-installed the App and while having allowBackup=true.
<manifest ... >
...
<application android:allowBackup="true" ... >
...
</application>
</manifest>
According to this:
https://developer.android.com/guide/topics/data/autobackup
The shared preferences should be restored?
SharedPreferences prefs = getSharedPreferences("TEST", MODE_PRIVATE);
String name = prefs.getString("name", "No name defined");//"No name defined" is the default value.
int idName = prefs.getInt("idName", 0); //0 is the default value.
SharedPreferences.Editor editor = getSharedPreferences("TEST", MODE_PRIVATE).edit();
editor.putString("name", "Elena");
editor.putInt("idName", 12);
editor.apply();
I have logged into my Gmail account on the (emulator) phone (API 27) and when going to
the Drive App, Backups, App-data, I see 18 Apps such as Youtube,
Gmail etc. and also my own App.
When I go to "Settings > System > Backup" I see the same Apps and also my own App. I load the App, sharedprefs code is executed. I close the App and remove it from memory. And then I press the "Backup now" button:
To Verify I can see my App in the list and it got backup 0 minutes ago:
Then I remove and reinstall the App and expect the 2 values (Elena and 12) to be there. But they are erased...
I also tried the same via command line, but also not working:
https://developer.android.com/guide/topics/data/testingbackup.html#Preparing
adb shell
dreamlte:/ $ bmgr enabled
Backup Manager currently enabled
dreamlte:/ $ bmgr list transports
android/com.android.internal.backup.LocalTransport
com.google.android.gms/.backup.migrate.service.D2dTransport
* com.google.android.gms/.backup.BackupTransportService
dreamlte:/ $ bmgr backupnow my.package.name
Running incremental backup for 1 requested packages.
Package #pm# with result: Success
Package nl.dagelijkswoord.android with progress: 1536/309248
Package nl.dagelijkswoord.android with result: Success
Backup finished with result: Success
dreamlte:/ $ dumpsys backup
Backup Manager is enabled / provisioned / not pending init
Auto-restore is disabled
No backups running
Last backup pass started: 1573804513565 (now = 1573806675410)
next scheduled: 1573819001046
...
1573806051616 : my.package.name
dreamlte:/ $ bmgr restore 1573806051616 my.package.name
No matching restore set token. Available sets:
35e84268c94b7d9c : SM-G950F
3a8e32898034f8af : SM-G950F
3e2610c4ea45fb96 : Nexus 5X
done
dreamlte:/ $ bmgr restore 35e84268c94b7d9c my.package.name
Scheduling restore: SM-G950F
restoreStarting: 1 packages
onUpdate: 0 = my.package.name
restoreFinished: 0
done
Remove App
Reinstall App and check if the SharedPreferences values are still there.
Values are gone...
The behaviour also seems to differ on Samsung devices with Samsung Cloud, but for now let's focus on stock Android.
UPDATE:
It wasn't working anymore because I downgraded the version in build.gradle:
build.gradle:
versionCode 70
versionName "1.6.1"
Even with android:restoreAnyVersion="true" in the AndroidManifest it would only work when the version was not downgraded.
By default android system backups all default data if device is connected to a Wi-Fi network (if the device user hasn't opted in to mobile-data backups), try to reinstall the app and connect with WI-FI usually android system sync data once in every 24 hours if any changes are there.
You can also try to specify your own rules for backup like this.
`<application
android:fullBackupContent="#xml/backup_rules">
</application>`
and create a xml file and put it in res/xml directory.
Inside the file, add rules with the and elements. The following sample backs up all shared preferences except device.xml.
`<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
</full-backup-content>`
I hope it will solve your issue.
As per the data back document, you need to create SharedPreferencesBackupHelper and follow these steps to achieve SharedPreferences back up also need to register the backup services for your case
You didn't turn on the Auto-restore settings as it showed in the console message. You should go to system settings and turn it on. After that, the restoration could work.
Settings -> Backup -> Automatic restore.
BTW, the token you used is not correct. 1573806051616 is a timestamp instead of the token. The token should appear as below:
Ancestral packages: none
Ever backed up: XXXXXXXXXXXXXXXX
Here, the XXXXXXXXXXXXXXXX should be the token.
To test restoration, you need to run the below command without removing your app. The restore command will force stop the app, wipe it's data and perform the restore hence simulating the functionality of the Android AutoBackup:
bmgr restore <TOKEN> <PACKAGE>
TOKEN is retrieved from the logcat command when running the backup command or from the dumpsys backup command. Also you could check the dumpsys backup to verify that the backup was created.
More info here: https://developer.android.com/guide/topics/data/testingbackup.html#TestingRestore
May this procedure will work for you.
Try to backing up and restoring a user's sharedPreferences. This will backup your preference to any External Storage or device.
When user uninstall app, user should take back up it. Add some logic that if file is present in External Storage or device, restore it back.
use below code to back up your preference.
public static void backupUserPrefs(Context context) {
final File prefsFile = new File(context.getFilesDir(), "../shared_prefs/" + context.getPackageName() + "_preferences.xml");
final File backupFile = new File(context.getExternalFilesDir(null),
"preferenceBackup.xml");
String error = "";
try {
FileChannel src = new FileInputStream(prefsFile).getChannel();
FileChannel dst = new FileOutputStream(backupFile).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast toast = Toast.makeText(context, "Backed up user prefs to " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
toast.show();
return;
} catch (FileNotFoundException e) {
error = e.getMessage();
e.printStackTrace();
} catch (IOException e) {
error = e.getMessage();
e.printStackTrace();
}
use below code to restore preference
public static boolean restoreUserPrefs(Context context) {
final File backupFile = new File(context.getExternalFilesDir(null),
"preferenceBackup.xml");
String error = "";
try {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
Editor editor = sharedPreferences.edit();
InputStream inputStream = new FileInputStream(backupFile);
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(inputStream);
Element root = doc.getDocumentElement();
Node child = root.getFirstChild();
while (child != null) {
if (child.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) child;
String type = element.getNodeName();
String name = element.getAttribute("name");
// In my app, all prefs seem to get serialized as either "string" or
// "boolean" - this will need expanding if yours uses any other types!
if (type.equals("string")) {
String value = element.getTextContent();
editor.putString(name, value);
} else if (type.equals("boolean")) {
String value = element.getAttribute("value");
editor.putBoolean(name, value.equals("true"));
}
}
child = child.getNextSibling();
}
editor.commit();
Toast toast = Toast.makeText(context, "Restored user prefs from " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
toast.show();
return true;
} catch (FileNotFoundException e) {
error = e.getMessage();
e.printStackTrace();
} catch (ParserConfigurationException e) {
error = e.getMessage();
e.printStackTrace();
} catch (SAXException e) {
error = e.getMessage();
e.printStackTrace();
} catch (IOException e) {
error = e.getMessage();
e.printStackTrace();
}
Toast toast = Toast.makeText(context, "Failed to restore user prefs from " + backupFile.getAbsolutePath() + " - " + error, Toast.LENGTH_SHORT);
toast.show();
return false;
}
Toast toast = Toast.makeText(context, "Failed to Back up user prefs to " + backupFile.getAbsolutePath() + " - " + error, Toast.LENGTH_SHORT);
toast.show();
}
then restart your app before these prefrence will take hold
if (restoreUserPrefs(context)) {
// Restart
AlarmManager alm = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
alm.set(AlarmManager.RTC,
System.currentTimeMillis() + 1000, PendingIntent.getActivity(context, 0,
new Intent(context, MainActivityName.class), 0));
android.os.Process.sendSignal(android.os.Process.myPid(),
android.os.Process.SIGNAL_KILL);
}
One way to do this is as follows,
(Please note, this may be not the best way, but it works!)
Before uninstall the app, take back up of it. Add some logic that if file is present in External Storage, restore it back.
Preferences stored in the SharedPreferences class get saved into /data/data//shared_prefs/_preferences.xml - backing up is easy, you just need to copy the contents of this file to external storage:
public static void backupUserPrefs(Context context) {
final File prefsFile = new File(context.getFilesDir(), "../shared_prefs/" + context.getPackageName() + "_preferences.xml");
final File backupFile = new File(context.getExternalFilesDir(null),
"preferenceBackup.xml");
String error = "";
try {
FileChannel src = new FileInputStream(prefsFile).getChannel();
FileChannel dst = new FileOutputStream(backupFile).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast toast = Toast.makeText(context, "Backed up user prefs to " + backupFile.getAbsolutePath(), Toast.LENGTH_SHORT);
toast.show();
return;
} catch (FileNotFoundException e) {
error = e.getMessage();
e.printStackTrace();
} catch (IOException e) {
error = e.getMessage();
e.printStackTrace();
}
Use following code to restore preference
But restoring provides more of a challenge, since the shared_prefs file isn’t directly writable by the app, and the SharedPrefs class doesn’t directly expose its functionality to serialise from xml. Instead you have to parse the XML yourself and push the values back in. Thankfully the XML file has a straightforward structure, so it’s easy to loop over the elements and turn these back into preferences.
if (restoreUserPrefs(context)) {
// Restart
AlarmManager alm = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
alm.set(AlarmManager.RTC,
System.currentTimeMillis() + 1000, PendingIntent.getActivity(context, 0,
new Intent(context, MainActivityName.class), 0));
android.os.Process.sendSignal(android.os.Process.myPid(),
android.os.Process.SIGNAL_KILL);
}
NOTE: External storage write and read permission required.
I just started to learn developping android and I have a (probably) basic questions, but I didn't find anything clear.
I'm trying to store data in a JSON file, well, I've understood the logic to store it, my way is:
public boolean writeFileJson(JSONObject jobj) {
try {
FileOutputStream fOut = openFileOutput(file, Context.MODE_PRIVATE);
fOut.write(jobj.toString().getBytes());
fOut.close();
Toast.makeText(getBaseContext(), "file saved", Toast.LENGTH_SHORT).show();
} catch (Exception e1) {
e1.printStackTrace();
}
return true;
}
But my problem is to read, and concretely for the first time, because the way I do it is:
public String readFileJson() {
int c;
String temp = "";
try {
FileInputStream fin = openFileInput(file);
while ((c = fin.read()) != -1) {
temp = temp + Character.toString((char) c);
}
Toast.makeText(getBaseContext(), "file read", Toast.LENGTH_SHORT).show();
} catch (Exception e2) {
}
return temp;
}
So wen I read it for the first time and I want to acces to a parameter of my JSON is obvious that any JSON Object already exist in the file.
So I try to save a first JSON Object with my parameters in onCreate() method and save it in the file, but wen I run the app, and I stop it, it returns again to execute onCreate() and deletes all data stored during the run time.
So my question is: There is any way to init only for one time the parameters of the JSON file to could access for the first time unlike it's empty???
I hope that I'd explained well!!
Thanxxxx!!!!
You can create your own flag boolean and check when you start.
Well I don't understand well why you can use a flag if the flag is set to init value in onCreate(), but I've tried a basic method: check each time if the json file is null. But it's like so basic no? Is there any ther way, or trying to understand how to use flags without reset their values?
msgjson = readFileJson();
if(msgjson == "") {
json.put("ARRAY", jsonArray);
}else{
json = new JSONObject(msgjson);
}
Thanx!!
I want to save a file "xp.txt" to keep track of the user's experience in a game. If the file doesn't exist, I'd like to create it and write "0" in the file (to indicate 0 experience). If the file exists I'd like to read from it and save the exp to an int variable in the java class. And I'd also like to know how to change the value from "0" to some other value.
Thanks in advance!
My current code is:
try {
OutputStreamWriter out = new OutputStreamWriter(openFileOutput(XP, 0));
out.write("0");
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
InputStream in = openFileInput(XP);
if (in != null) {
InputStreamReader temp = new InputStreamReader(in);
BufferedReader reader = new BufferedReader(temp);
String str;
StringBuilder buf = new StringBuilder();
while ((str = reader.readLine()) != null) {
xp = Integer.parseInt(str);
System.out.println(xp);
}
in.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
But I cannot find the text file and it doesn't work as I intended.
You can use the following ways to store data
Shared Preferences - Store private primitive data in key-value
pairs.
Internal Storage - Store private data on the device memory.
External Storage - Store public data on the shared external storage.
SQLite Databases - Store structured data in a private database.
Network Connection - Store data on the web with your own network
server.
I think for your use case SharedPreferences will do good. A quick example would be
To Save a value :
SharedPreferences.Editor editor = getSharedPreferences("unique_name", MODE_PRIVATE).edit();
editor.putInt("xp", 10);
editor.commit();
To Retrieve value
SharedPreferences prefs = getSharedPreferences("unique_name", MODE_PRIVATE);
int xp = prefs.getInt("xp", 0); // will return 0 if no value is saved
You can read more from this here.
i did an application to collects light sensor data, such that these data are stored in text file in the external sdcard, the data is stored correctly and file are created successfully but the problem is when then application running on the my device for x period (e.g 1 min)the data is stored but when is close the application and re running it on from the device for the same period also the new collected data are append stored to the previous stored data from previous running and i noted that when the sizes of the text files is increases with each running.
i need for each running ,the collected data is stored totally (for the whole period of the running i.e 1 min ) in the text file and when i re- running the application again the new collected data of the new running to be overwriting on previous stored data.
i attempted to do that using arraylist, i .e when then app starts running i put all gathered reading in array list and when the running is stopped the arraylist will out all gathered data to the text file but when i re-running app the array list also gathered data and append out it into the text file next to the previous running stored data, where this is the problem which need to solve,i need to overwrite new running gathered data on the previous running stored data.
the code of collecting light sensor data looks like:
#Override
public void onSensorChanged(SensorEvent event) {
if(event.sensor.getType()==Sensor.TYPE_LIGHT){
max = msensorManager.getDefaultSensor(Sensor.TYPE_LIGHT).getMaximumRange();
//getMaximumRange() is the maximum range of the sensor in the sensor's unit.
//tv1.setText("Max Reading: " + String.valueOf(max));
tv1.setText(msg +"Max Reading: " + String.valueOf(max) );
tv1.invalidate();
lightMeter.setMax((int)max);
//setMax is the max of the upper range of this progress bar
currentReading = event.values[0];
//timestamp = event.timestamp;
lightMeter.setProgress((int)currentReading);
Toast.makeText(MainActivity.this,"Event Happend '", Toast.LENGTH_SHORT).show();
tv2.setText("Current Reading: " + String.valueOf(currentReading));
current_reading_list.add((double) currentReading);
}
the code of writing from array list into file looks like :
public void writing_in_file_1(){
try{
fw = new FileWriter(file_1, true);
bw = new BufferedWriter(fw);
out = new PrintWriter(bw);
//out.append( String.valueOf(currentReading + " \t"));
//out.append(String.valueOf(current_reading_list));
out.print(String.valueOf(current_reading_list));
out.flush();
Toast.makeText(this,"Done writing SD 'specific text file'", Toast.LENGTH_SHORT).show();
}
catch (IOException e)
{
e.printStackTrace();
}
finally{
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
the writing is done when the stop button is pressed:
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1:
counter_function();
//onResume();
break;
case R.id.bt2:
onPause();
writing_in_file_1();
tv1.setText("");
tv2.setText("");
break;
default:
break;
}
}
can any one help me?
thank you in advance.
You are using the constructor FileWriter(File file, boolean append) with append = true
Replace
fw = new FileWriter(file_1, true);
with
fw = new FileWriter(file_1, false);
my history objects only have 2 fields (id + name). i have to save them. i used sharedpreferences because this is just perfect to save key-value pairs. problem is..there is no possibilty to change to location where the files are saved. i dont want to save them into the sharedpref folder because i want to give the user of the app the possibility to delete all history entries. i have to check which files are history files and which files are preferences files used by the app. this is no proble..but dirty imo. on the other hand..my history files shouldnt be in sharedpref folder..they have nothing to do in that folder..
the other possibility is to store the data in internal storage as xml for example. i would have to write a serializer and parser.
the third possibility (i just remembered writing this question)is to save it via Java Properties. this is probably the easiest solution. its like sharedpref
the last possibility is to store it in sqlite. i dont know..my data is so tiny..and i use a databae to store it?
my question is simply..what do u recommend to use and why. what do you use? same question belongs to the autocomplete values. id like to save the values the user once entered in a textfield. where to save them? where do you save such data?
thx in advance
You can create a separate sharedpreferences file for your history using (say) Context.getSharedPreferences("history") which will create a sharedpreferences file as follows.
/data/data/com.your.package.name/shared_prefs/history.xml
But I'm pretty sure that all sharedpreferences files will be created in /data/data/com.your.package.name/shared_prefs/. I don't think you can change the location.
I may be mis-interpreting your objective but for something like this I would just straight-up use a BufferedWriter from java.io.BufferedWriter to write a new file for each object. Likewise you can read the data with a BufferedReader. The code would look something like this:
public static void save(FileIO files){
BufferedWriter out = null;
try{
//use a writer to make a file named after the object
out = new BufferedWriter(new OutputStreamWriter(
files.writeFile(objectSomething)));
//the first line would be ID
out.write(Integer.toString(objectID));
//second line would be the name
out.write(objectName)
//Theres two possible IOexceptions,
//one for using the writer
//and one for closing the writer
} catch (IOException e) {
} finally {try {
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
In this example, I have used "objectSomething" as the string name of the file, objectID and objectName are the int and string respectively that your file contains.
to read this data, pretty straightforward:
public static void load(FileIO files) {
BufferedReader in = null;
try {
// Reads file called ObjectSomething
in = new BufferedReader(new InputStreamReader(
files.readFile(ObjectSomething)));
// Loads values from the file one line at a time
varID = Integer.parseInt(in.readLine());
varName = in.readLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
}
}
}
here, I've used varID and varName as local variables in this class that you would use if you needed them in your code throughout your application.