I know, there are plenty of questions in regards to saving/retrieving data on here. I was doing find looking things up on my own and really thought I could manage to find my answers without having to "ask a question", but I began to wonder something that I haven't seen an answer for on here.
MY SITUATION:
Naturally, I'm making an app. Upon closing the app, I want to save a simple array of numbers (0 or 1) or boolean values as it were. Upon starting the app, I want to search for that array, if it exists, and retrieve it for use within the app.
I began placing my code into the activity in which the array would be used. But, I started wondering if I would have to copy/paste the overridden onStop() function into all of my activities? Or do I do it in the main activity and somehow link the other activities.
Basically, no matter what state/activity the app is currently on when the app is closed, I want to be able to save the array of int/bool and open it back up when the app is started.
Maybe I didn't know how to search for what I wanted, so explaining it felt like the right thing to do.
I don't mind doing more searching, but if someone would point me in the right direction at the very least, I'd be extremely grateful.
EDIT: If there's a better way to do what I want than what I described (i.e. using a different state instead of onStop(), for instance), please feel free to throw out ideas. This is my first time actually having to deal with the activities' lifecycles and I'm a bit confused even after looking through the android development tutorials. I really think they're poorly done in most cases.
When you application needs to save some persistent data you should always do it in onPause() method and rather than onStop(). Because if android OS kills your process then onStop() and onDestroy() methods are never called. Similarly retrieve data in onResume() method.
Looking at the purpose you want to fulfill, SharedPreferences is all you want.
The documentation states:
"SharePreferences provides a general framework that allows you to save
and retrieve persistent key-value pairs of primitive data types. You
can use SharedPreferences to save any primitive data: booleans,
floats, ints, longs, and strings. This data will persist across user
sessions (even if your application is killed)."
Use SharedPreference to store small amount of data or use SQLite to store large amount of data.
See this link
http://developer.android.com/guide/topics/data/data-storage.html
Serialize an object and pass it around which is more dependable than shared preferences (had lots of trouble with consistency with shared preferences):
public class SharedVariables {
public static <S extends Serializable> void writeObject(
final Context context, String key, S serializableObject) {
ObjectOutputStream objectOut = null;
try {
FileOutputStream fileOut = context.getApplicationContext().openFileOutput(key, Activity.MODE_PRIVATE);
objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serializableObject);
fileOut.getFD().sync();
} catch (IOException e) {
Log.e("SharedVariable", e.getMessage(), e);
} finally {
if (objectOut != null) {
try {
objectOut.close();
} catch (IOException e) {
Log.e("SharedVariable", e.getMessage(), e);
}
}
}
}
Then use a class to use:
public class Timestamps implements Serializable {
private float timestampServer;
public float getTimestampServer() {
return timestampServer;
}
public void setTimestampServer(float timestampServer) {
this.timestampServer = timestampServer;
}
}
Then wherever you want to write to the variable use:
SharedVariables.writeObject(getApplicationContext(), "Timestamps", timestampsData);
Best way to achieve that is:
create a class. Call it MySettings, or whatever suits you
in this class, define the array of ints / booleans you are going to share, as static. Create getter & setter method (property) to access that (also as static methods)
add a static load() method to MySettings that reads from SharedPreferences. When you launch the app (in your first activity or better in a subclass of Application) call MySettings.load(). This load method sets the array
add a static save() method. Public also. Now you can save from anywhere in you app. This save() method reads the array and writes in SharedPreferences
Code sample:
public class MySettings {
private static List<Integer> data;
public static void load() {
data = new ArrayList<Integer>();
// use SharedPreferences to retrieve all your data
}
public static void save() {
// save all contents from data
}
public static List<Integer> getData() {
return data;
}
public static void setData(List<Integer> data) {
MySettings.data = data;
}
}
Related
I just curious what makes a value inside of some variable become empty again or back to its initial value in the android life cycle.
First lets take a look at how i create a variable :
public class myData {
public static String myCode = "";
public static String getData(String Choice) {
String theData = "";
if ("Code".equals(Choice) {
theData = myCode;
}
return myCode;
}
public static void setData(String setData,String Choice) {
if ("Code".equals(Choice) {
myData.myCode = setData;
}
}
}
If I want to fill the variable, i usually do this :
myData.setData("value of variable","Code");
And if I want to get the value of the variable, I usually do this :
myData.getData("Code");
I just want to know what makes my variable gone inside of android lifecycle, of course excluding when the application is closed.
I have to try to Log and show the value in onstart , oncreate, onresume and onrestart. And all of them is still have the value inside of my variable intact without any problem.
My client always tells me that my application sometimes gets crash when they open some activity. I also ask if they did something while using my application,
some of them answer that the application get crashed after they got a phone call and when the phone call is ended, the application is started with a crash.
some of them also said that when they open the application and then idle the phone withouth closing the application until the phone become black screen, and when they open it again the application get crashed.
After I check the log, the problem was the variable become empty. which is why I want to know is there another possibilites that makes the value inside of the variable become empty?
As John Lord saying, on low-end device variables might back to its initial value again if there is not enough memory.
So for future reference, I use a shared preference to counter it, here is my structure for fetching the data :
public class myActivity extends AppCompatActivity {
String myCode = "";
protected void onCreate(Bundle savedInstanceState) {
....
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData", Context.MODE_PRIVATE);
myCode = sharedPreferences.getString("Code",null);
....
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData", Context.MODE_PRIVATE);
myCode = sharedPreferences.getString("Code",null);
}
}
And here is how i set the data :
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData",Context.MODE_PRIVATE);
sharedPreferences.edit().putString("Code","Hello World").apply();
I hope it will be helpful for those who want to search the same thing
When i start my android app, it loads large amount of data from server in mainactivity and adapt it with listView and when listview is clicked , new activity will launch . When return back to mainactivity from current activity , my app again load data from server that was previously loaded? How can i use 1st time loaded data after returning back to same activity next time??
There are several possible approaches to your problem depending on what you want to do. First of all, in the activity where you download and process the data, you should override the onSaveInstanceState and onRestoreInstanceState methods so that your data is persisted and survives orientation changes (and not loose the work you did processing the data).
If your application simply opens a detail activity, from the main activity, then when you press back, your data will be available. You do not have to reload anything. If this is not the case, then there may be some problem with how you load the data in the activity's lifecycle (e.g. avoid loading and processing data in the onStart/onResume methods).
If you want to persist data after your application has died, you can either use http caching (e.g. with OkHttp) or use an Sqlite database, as others have pointed out. These approaches can also be combined for additional performance gains.
You can cache the server response in shared preference in form of JSON and store to avoid making server calls each time. (However this is recommended only when data is small)
Example :
public <T> void putJsonIntoSharedPreferences(String key, T object) {
SharedPreferences sharedPreferences = getSharedPreferences();
SharedPreferences.Editor edit = sharedPreferences.edit();
String json = convertToJson(object);
edit.putString(key, json);
edit.commit();
}
public <T> T getFromSharedPreferences(String key, Class<T> clazz) {
SharedPreferences sharedPreferences = getSharedPreferences();
final String fromSharedPreferences = sharedPreferences.getString(key, "");
T object = null;
if (!fromSharedPreferences.equals("")) {
try {
object = JsonConverter.fromJson(fromSharedPreferences, clazz);
} catch (IOException e) {
return null;
}
} else {
try {
return clazz.newInstance();
} catch (Exception e) {
return null;
}
}
return object;
}
private <T> T fromJson(String json, Class<T> clazz) throws IOException {
ObjectMapper objectMapper = getObjectMapper();
if(json!=null)
return objectMapper.readValue(json,clazz);
return null;
}
private String convertToJson(Object object) {
ObjectMapper objectMapper = new ObjectMapper();
String string = null;
try {
string = objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
Log.d(ComponentConstants.JSON_PARSE_ERROR_TAG,e.getMessage(),e);
}
return string;
}
You can simply use an http client with caching like OkHttp. more complicated yet more appropriate in some cases is to manage an internal Sqlite Database.
As a Side note You can save all your data and load it when activity is reloaded but you should not. as no metter what way you choose, IO will be involved and its going to be a heavy operation if your data is big enough.
Its good practice to load exactly what the activity needs to show when its being loaded, and not the full data. You should use CursorLoader or CursorAdapter to load dynamically what your activity needs as user interacts with it...
I have an Activity that consists of multiple containers (FrameLayouts, more specifically) in order to display Fragments. These Fragments are actually audio effects, so once I choose a number of fragments to show in their corresponding containers and adjust their knobs (typical guitar effects stuff), I would like to save and load their presets.
In another words, I want to save the view of my Activity (with data of which effect is in which container, what values are the knobs etc.) to a file, and then load the file. On load, I would like my Activity to switch to the view I saved in file.
I have made the interface for saving and loading, but I can't find a way to save and load my views. I've found numerous examples of saving and loading views on orientation change, but not one example of saving and loading in files.
Here are the snippets of my code for saving and loading, too bad it doesn't work. Actually, this was just "mushed" by me via some marginal instructions I've found on the internet, perhaps I couldn't be farther from the answer:
public void save_file (Object file, String fileName, Context context) {
try {
FileOutputStream fos = context.openFileOutput(fileName, context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(MainActivity.this);
oos.writeObject(file);
oos.flush();
oos.close();
fos.close();
if (fileName != null) {
Toast.makeText(context, "Save successful", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Enter name", Toast.LENGTH_LONG).show();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static MainActivity load_file(String fileName, Context context) {
MainActivity Main = null;
try {
FileInputStream fis = context.openFileInput(fileName);
ObjectInputStream is = new ObjectInputStream(fis);
Main = (MainActivity) is.readObject();
is.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return Main;
}
I also don't know a way to switch a view to the loaded one. Thank you for your help.
So right now it looks like all you're doing is creating a new instance of MainActivity in load_file, but that's not really going to do you any good. In Android, you don't deal with creating instances of your Activity classes, the system will do that for you.
It sounds to me like for what you're trying to do, you should be using the shared preferences to store the information about your views, then re-render the Views with all the proper values in the onCreate method of MainActivity. If you're unfamiliar with SharedPreferences, you can look at the docs here: http://developer.android.com/reference/android/content/SharedPreferences.html
Basically, it's just writing to a file like you're already doing, but abstracted a little so that it's more convenient. You want to have a field in MainActivity called mPrefs, initialize it in onCreate like this:
mPrefs = getSharedPreferences(<unique name here>, Context.MODE_PRIVATE);
For example, say a user adjusts a guitar knob to a tension of 6 (I'm imagining that gets stored as an int)
SharedPreferences.Editor editor = mPrefs.edit();
//you should actually store the key string "guitar_knob_1" as a static final global variable rather than hard-coding
editor.putInt("guitar_knob_1", 6);
editor.commit();
Now, back in onCreate, you can have something like this:
if(mPrefs.getInt("guitar_knob_1", -1) != -1) { //-1 is the value we get if nothing is stored there
//set the knob to the value we read
}
The way it would make sense to me to do what you're asking would be to store a String of the names of the Views you have associated with each FrameLayout, then write some functions to render the correct Views in onCreate. You don't really need to "save" the views, just save all the values associated with them and rebuild them correctly when the activity opens. Hope that helps!
I create an app that like dictionary app. When the user types in an Edittext, I call an AsyncTask to compute and update the result to the screen (I put the UI update code in onPostExecute() method ). However, when you type little fast, the eddittext become not responesive (a little latency). I think this promblem occurs because many AsyncTasks are running (each AsynTask for an input letter). So, I think I need to stop the first task before calling new task. Am I right? What should I do in this situation?
You don't need to implement the filter method in an async task. I call filter method on data when first letter has been written in editbox and save the result in an temporary array, then when another letter has been written, I call filter method on the temporary data which technically has less information than the original data. By doing this, the dimmension of data set decreases as you type in editbox. Also, you can use this method to store previous data set so when you press backspace, you don't have to call filter method again, you just go to previous saved temporary data set. For me, it works fine and I don't have to use async task because it is efficient
I suggest you another approach: use only one thread. The searching thread should wait for searching data > do search > and sleep until new data. E.g.:
private static class SearchThread extends Thread{
private Object monitor = new Object();
private String value;
public void search(String value){
this.value = value;
synchronized (monitor){monitor.notify();}
}
#Override
public void run() {
while(true){
try {System.out.println("Wait for search data."); synchronized (monitor){monitor.wait(); }
} catch (InterruptedException e) {e.printStackTrace();}
System.out.println("Searching for " + value);
}
}
}
I have an activity that contain a list of data (TextView), i need to save this data that have been choose (onClick) in the list and been able to get and read it in another activity(history)
I understand that is exist a possibility with the "serializable" but i did not success to understand how it could help me.
i will be happy if someone can clarify this subject for me,example?.
Thank you for helping!!
If you're trying to pass a String to another activity, you can do this with putExtra and getStringExtra:
Intent intent = new Intent(this, OtherActivity.class);
intent.putExtra("parameter", myStringParameter);
startActivity(intent);
and then read it in OtherActivity's onCreate method:
String parameter = getIntent().getStringExtra("parameter");
The Serializable interface is useful for marshalling more complicated objects; you don't need this if you're just dealing with String.
Edit - if you need to store small amounts of data persistently you could use SharedPreferences:
final String TAG = "MyApplication";
SharedPreferences prefs = getSharedPreferences(TAG, MODE_PRIVATE);
prefs.edit().putString("parameter", myStringParameter).commit();
and then to read the preferences:
final String TAG = "MyApplication";
SharedPreferences prefs = getSharedPreferences(TAG, MODE_PRIVATE);
String parameter = prefs.getString("parameter", null);
This data will be available even after your application closes.
Yes, use classes that implement Serializable. See my answer on this question: How to pass several variables of different types from one function to another on android?
Create some model classes which will hold data:
public class Page implements Serializable {
private String name;
private String description;
//and so on...
public Page(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
}
Now you can create a Page object and fill it with data(name, description) via the constructor. Optionally make some setters.
Page p = new Page("James", "Hello World");
startActivity(new Intent(context, MyActivity.class).putExtra("Page", p));
Retrieve your Page in MyActivity in its onCreate method:
Page p = (Page)getIntent().getExtras().getSerializable("Page");
Toast.makeText(this, "Name: " + p.getName() + ", Description:" + p.getDescription(), Toast.LENGTH_LONG).show();
I am aware about the methods mentioned above. But just for alternative thoughts, since you are mentioning the history word, how about using SQLite for this purpose?
In first activity, you can save the data, and in second activity, retrieve the data.
You can share data between your activities in various ways depending on how much data you need to save and how long the data needs to be saved.
Intents : Useful when transferring small bits of data between 2-3 screens
Singleton / Static data store classes : useful when sharing lot of data between various activities
SQLite DB : Large amount of data to be shared , also useful to save the same between app launches
Shared Preferences : Small amount of data , between app launches.
For your use-case its best to use intents unless the data is shared between more than 2-3 activities where option 2 would be a better solution
Sending immutable stateful objects between activities (messaging) is commendable, IMHO. It can be argued that OOP is about messaging, not objects. Two suggestions. 1) use the fully qualified name for the name:value pair so do:
private void launchManagePassword() {
Intent i= new Intent(this, ManagePassword.class); // no param constructor
PasswordState outState= new PasswordState(lengthKey,timeExpire,isValidKey,timeoutType,"",model.getIsHashPassword());
Bundle b= new Bundle();
b.putSerializable("jalcomputing.confusetext.PasswordState", outState);
i.putExtras(b);
startActivityForResult(i,REQUEST_MANAGE_PASSWORD); // used for callback
}
This will minimize runtime casting errors.
2) When you have the app working well and the object interface is stabilized consider refactoring the code to a Parcel for speed.
JAL
EDIT: AS REQUESTED Code