Android Studio - saving user data - android

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.

Related

new BlobStoreManager read write on Android 11

I previously used external storage to store specific data that I would like to share between my applications (without having any contentprovider "host")
File folder = new File(Environment.getExternalStorageDirectory(), "FOLDER_NAME");
File file = new File(folder, "FILE_NAME.dat");
FileOutputStream outputStream = new FileOutputStream(file);
That is why I am trying to use BlobStoreManager, as suggested in google's recommendation for targeting 30 (https://developer.android.com/training/data-storage/shared/datasets)
The read & write are based on a BlobHandle with 4 parameters, one being MessageDigest based on a "content". BlobHandle must use the same 4 parameters, or read will fail (SecurityException).
I managed to write data, and to read it, but it makes no sense:
It seems that in order to write, I need to use the data I want to write to generate the BlobHandle.
Then, to read, as BlobHandle must use the same 4 parameters, I also need the data I wrote to be able to read.
Totally illogic, as I wanted to read this data, I don't have it!
I must miss something or just do not understand how it work. If someone can help :)
Here are my sample:
If I set the following:
createBlobHandle: content = "mydata"
write: data = "mydata"
Then write will success, and read will success too. But it I can not know the value before reading it in a normal usecase :(
If I set the following (which would be logic, at least to me):
createBlobHandle: content = "somekey"
write: data = "mydata"
Then write will fail :(
#RequiresApi(api = Build.VERSION_CODES.R)
private BlobHandle createBlobHandle() {
//Transfer object
String content = "SomeContentToWrite";
String label = "label123";
String tag = "test";
//Sha256 summary of the transmission object
try {
byte[] contentByte = content.getBytes("utf-8");
MessageDigest md = MessageDigest.getInstance("sha256");
byte[] contentHash = md.digest(contentByte);
return BlobHandle.createWithSha256(contentHash, label,0, tag);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
private void write() {
String data = "SomeContentToWrite";
#SuppressLint("WrongConstant") final BlobStoreManager blobStoreManager = ((BlobStoreManager) applicationContext.getSystemService(Context.BLOB_STORE_SERVICE));
//Generate the session of this operation
try {
BlobHandle blobHandle = createBlobHandle();
if (blobHandle == null)
return;
long sessionId = blobStoreManager.createSession(blobHandle);
try (BlobStoreManager.Session session = blobStoreManager.openSession(sessionId)) {
try (OutputStream pfd = new ParcelFileDescriptor.AutoCloseOutputStream(session.openWrite(0, data.getBytes().length))) {
//The abstract of the written object must be consistent with the above, otherwise it will report SecurityException
Log.d(TAG, "writeFile: >>>>>>>>>>text = " + data);
pfd.write(data.getBytes());
pfd.flush();
//Allow public access
session.allowPublicAccess();
session.commit(applicationContext.getMainExecutor(), new Consumer<Integer>() {
#Override
public void accept(Integer integer) {
//0 success 1 failure
Log.d(TAG, "accept: >>>>>>>>" + integer);
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String read() {
String data = "";
#SuppressLint("WrongConstant") final BlobStoreManager blobStoreManager = ((BlobStoreManager) applicationContext.getSystemService(Context.BLOB_STORE_SERVICE));
BlobHandle blobHandle = createBlobHandle();
if (blobHandle != null) {
try (InputStream pfd = new ParcelFileDescriptor.AutoCloseInputStream(blobStoreManager.openBlob(createBlobHandle()))) {
//Read data
byte[] buffer = new byte[pfd.available()];
pfd.read(buffer);
String text = new String(buffer, Charset.forName("UTF-8"));
Log.d(TAG, "readFile: >>>>>>>>>>>>>>>>>>>>" + text);
} catch (IOException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
return data;
}
According to the official training documentation linked in the question, the missing piece of information, at the time of the question having been asked, is that the four pieces of data contained in the BlobHandler need to be uploaded to a server owned by the client application then subsequently downloaded by which ever other application wants to access the blob via the BlobStorageManager.
So it would seem that on-device blob discovery is not supported. There could also be a solution possible using a Content Provider which could offer up the four required pieces of data, thus circumventing the need for the server infrastructure.

Saving objects in cache

I am trying to save in cache response from server for certain time.
There are tne next data for saving in cache: I have a List<ProgrammeItem> which I am getting from server. While user is working, he can download up to ~230 List<ProgrammeItem> (but it is unreal to reach this, estimated is 10-50).
ProgrammeItem oblect including strings, int, int[].
That is how I am saving and getting the last downloaded List<ProgrammeItem>:
//saving / getting Programme items
public boolean saveObject(List<ProgrammeItem> obj) {
final File suspend_f=new File(android.os.Environment.getExternalStorageDirectory(), "test");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
boolean keep = true;
try {
fos = new FileOutputStream(suspend_f);
oos = new ObjectOutputStream(fos);
oos.writeObject(obj);
} catch (Exception e) {
keep = false;
Log.e("catching exception ", "" + e.getMessage() + ";;;" + e);
} finally {
try {
if (oos != null) oos.close();
if (fos != null) fos.close();
if (keep == false) suspend_f.delete();
} catch (Exception e) { /* do nothing */ }
}
return keep;
}
public List<ProgrammeItem> getObject(Context c) {
final File suspend_f=new File(android.os.Environment.getExternalStorageDirectory(), "test");
List<ProgrammeItem> simpleClass= null;
FileInputStream fis = null;
ObjectInputStream is = null;
try {
fis = new FileInputStream(suspend_f);
is = new ObjectInputStream(fis);
simpleClass = (List<ProgrammeItem>) is.readObject();
} catch(Exception e) {
String val= e.getMessage();
} finally {
try {
if (fis != null) fis.close();
if (is != null) is.close();
} catch (Exception e) { }
}
return simpleClass;
}
That is how I am saving and getting object in activity:
PI = new ProgrammeItem();
List<ProgrammeItem> programmeItems = new ArrayList<>();
...
//filling programmeItems with data from server
...
boolean result = PI.saveObject(programmeItems); //Save object
ProgrammeItem m = new ProgrammeItem();
List<ProgrammeItem> c = m.getObject(getApplicationContext()); //Get object
The question is: how can I save a lot of my objects instead of only one?
I think I should done something like public boolean addObjectsInCache(List<ProgrammeItem> obj) for adding objects, not overriding them.
And change get method into public List<ProgrammeItem> getObject(Context c, String id), where id will be unique identifier, which will includes into every ProgrammeItem in the every List<ProgrammeItem>.
Am I right? And how I can achieve this? Maybe you will show me the other way to work with objects and cache?
You can use SharedPreference instead, while having a local database Android Room can also be an option. SharedPreference basically is stored in your device's cache while the local database is stored in your device's data hence in our apps we have clear cache and clear data function.
Additional Resources:
StackOverFlow: How Android SharedPreferences save/store object
Object based preference library: https://github.com/ShawnLin013/PreferencesManager I would suggest you go with this one, since it can easily save you time saving list based object and retrieving them. You can also add more to the persisted list object when needed.
Secured Preferences: https://github.com/scottyab/secure-preferences
An option could be to use Room database with inMemoryDatabaseBuilder:
db = Room.inMemoryDatabaseBuilder(context, ProgrammeDatabase::class.java)
.build()
if it all can fit in memory.

Write whole Android shared_preferences.xml at once

Is it possible to write a whole shared_preferences.xml at once?
I want to realize a kind of settings import/export, so i need to read and write the whole file without loosing the xml-tags.
Reading the file is easy, but when i write my values (using PrintWriter) the old values stored in memory overwrite them seconds later.
what can i do to prevent that without writing single values using preference editor.
Now I read it from a file designed like Android's own preferences.xml and write it successively in my own function like this:
public static void preferencesImport(String PreferenceFilepath) {
preferencesImportPreferenceFilepath = PreferenceFilepath;
try {
// Parsing
// see http://theopentutorials.com/tutorials/android/xml/android-simple-xml-dom-parser/
XMLParserHelper parser = new XMLParserHelper(); // reference to described XMLDOMParser helper class
BufferedInputStream stream;
try {
stream = new BufferedInputStream(new FileInputStream(preferencesImportPreferenceFilepath));
org.w3c.dom.Document doc = parser.getDocument(stream);
// string value
NodeList nodeListString = doc.getElementsByTagName("string");
for (int i = 0; i < nodeListString.getLength(); i++) {
Element eString = (Element) nodeListString.item(i);
Pref.setString(eString.getAttribute("name"), eString.getTextContent()); // Own getter/setter -> use Android's preference manager instead in similar way
}
// repeat code above for boolean, long, int, float values
stream.close();
} catch (IOException e1) {
// output IOException
} catch (Throwable t1) {
// output Throwable1
}
writer.close();
} catch (Throwable t2) {
// output Throwable2
}
}

Is there any way to store a 2D array in a persistant storage?

I want to load a 2D array like this one:
[
[false, true, false, false],
[true, false, false, false],
[false, false, false, true],
[false, false, true, false],
[false, false, true, false]
]
Actually, these are the radio button states, false indicating radiobutton is uncheck while true indicating that the radio button is checked.
To explain the whole scenario, I am creating a quiz, which has a question and options for this i have created a radiobuttonStates[][] 2D array. The first [] indicating number of questions versus number of options in second []. There is a save and exit button which saves the quiz (saving the question number from where the user left and the selected radio buttons, previous as well as present). So the 2D array which i have created in the first attempt of the quiz, I want to load this same array when the user again comes back and resumes the quiz. Right now i am thinking to store this array in some persistant storage (Database or any kind). But I am not getting any way on how to store. The user clicks the resume button and I am showing the current question number from the database but not able to show the radio button selection. Please help me.
Well you can always transform your boolean array into a string(or more strings), and store it in SharedPreferences.
For example: ResultString = "false,true,false,false";
When you need the result back from the SharedPreference just split your strings, using a certain separator (for instance ",") and reuse your saved data.
Like this you get faster store/restore data backup. Using SQLite to store this kind of data is not a good idea.
Good luck,
Arkde
Well, you can make some kind of table structure where you put each individual array value in a specific row/column. However, if your array contains a small number of elements (like the one you showcase in your question), you can just serialize the instances and save the bytes in the database. This way you won't have to make all the boiler-plate code that thakes each array value and puts it in some row/column and then builds an array out of various row/column values.
An easy and instant way is to store the array or multiple 2d arrays is to use file to read and write your array object.
here is the code sample below which reds my custom objects from a file and writes them to the file. the only thing in the methods below are when reading it reds all objects and when writing it writes all objects again means you can not append single object with previous file or read single object from file. so if you hae to append another array you have to read all previous ones and then write them again with the increment of one you want to append.
public static boolean writeBlockedMessagesInFile(Context context,
ArrayList<BlockedMessages> blockedMessages) {
boolean status = false;
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = context.openFileOutput("BlockedMessagesFile.dat",
Context.MODE_WORLD_WRITEABLE);
oos = new ObjectOutputStream(fos);
if (blockedMessages != null && blockedMessages.size() != 0) {
for (int i = 0; i < blockedMessages.size(); i++)
oos.writeObject(blockedMessages.get(i));
}
oos.flush();
oos.close();
fos.close();
status = true;
} catch (IOException e) {
e.printStackTrace();
}
return status;
}
public static ArrayList<BlockedMessages> readBlockedMessagesFromFile(Context context) {
ArrayList<BlockedMessages> blockedMessages = new ArrayList<BlockedMessages>();
FileInputStream fis = null;
ObjectInputStream ois = null;
Object object = null;
try {
fis = context.openFileInput("BlockedMessagesFile.dat");
ois = new ObjectInputStream(fis);
BlockedMessages blo;
Object temp;
try {
while ((blo = (BlockedMessages) ois.readObject()) != null) {
blockedMessages.add(blo);
}
} catch (NullPointerException npe) {
npe.printStackTrace();
} catch (EOFException eof) {
eof.printStackTrace();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return blockedMessages;
}

android - where to save history and autocomplete values

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.

Categories

Resources