I can I retain ArrayList<HashMap<String, String>> in bundle?
I want to display ListView immediately after rotating the screen.
You dont have to save it in the Bundle. In fact, that seems like a lot of info to store in a Bundle.
Since you are just saving a HashMap of String objects, you could make a class to cache it for you or make it a static field in the class.
Static fields are fine to use as long as they dont contain a reference to the Activity or a View or Drawable. (That can cause memory leaks)
The simplest way you could do this might just be:
private static HashMap<String,String> myMap = new HashMap<String,String>();
Because this field is static, it will not be recreated when your activity is recreated. Rather, it will still be there for you to use with the same values.
More ways to store data:
(These techniques apply to sharing data over a configuration change also).
http://developer.android.com/guide/faq/framework.html#3
How do I pass data between Activities/Services within a single application?
It depends on the type of data that you want to share:
Primitive Data Types
To share primitive data between Activities/Services in an application,
use Intent.putExtras(). For passing primitive data that needs to
persist use the Preferences storage mechanism.
Non-Persistent Objects
For sharing complex non-persistent user-defined objects for short
duration, the following approaches are recommended:
Singleton class
You can take advantage of the fact that your application components
run in the same process through the use of a singleton. This is a
class that is designed to have only one instance. It has a static
method with a name such as getInstance() that returns the instance;
the first time this method is called, it creates the global instance.
Because all callers get the same instance, they can use this as a
point of interaction. For example activity A may retrieve the instance
and call setValue(3); later activity B may retrieve the instance and
call getValue() to retrieve the last set value. A public static
field/method
An alternate way to make data accessible across Activities/Services is
to use public static fields and/or methods. You can access these
static fields from any other class in your application. To share an
object, the activity which creates your object sets a static field to
point to this object and any other activity that wants to use this
object just accesses this static field.
A HashMap of WeakReferences to Objects
You can also use a HashMap of WeakReferences to Objects with Long
keys. When an activity wants to pass an object to another activity, it
simply puts the object in the map and sends the key (which is a unique
Long based on a counter or time stamp) to the recipient activity via
intent extras. The recipient activity retrieves the object using this
key.
Persistent Objects
Even while an application appears to continue running, the system may
choose to kill its process and restart it later. If you have data that
you need to persist from one activity invocation to the next, you need
to represent that data as state that gets saved by an activity when it
is informed that it might go away.
For sharing complex persistent user-defined objects, the following
approaches are recommended:
Application Preferences
Files
contentProviders
SQLite DB
If the shared data needs to be retained across points where the
application process can be killed, then place that data in persistent
storage like Application Preferences, SQLite DB, Files or
ContentProviders. Please refer to the Data Storage for further details
on how to use these components.
You should probably be overriding the Activity or Fragments onSaveInstanceState(Bundle) function. This will allow you to set any data that you wish to save between instances of the same Activity or Fragment. This is the correct way to save between rotations.
** Updated **
Since you have an ArrayList that contains 1 or more Hashmaps, you might need to save two objects into the bundle. One being the number of HashMaps that are in the array, and then each HashMap. Since the HashMaps are Serializable, you can just use the Bundle.putSerializable to place each of the HashMaps into the bundle. You will need to place the needed information into the bundle in order to re-create the ArrayList in the OnResume().
One method might be this: Have the keys to each HashMap be some string like "Hashmap1", "Hashmap2" and so on for each HashMap. Then if you know the number of HashMaps to retrieve from the bundle and the key format, then you can recreate the ArrayList.
Related
I have an Activity that needs to save a single primitive (not an object) that is used to alter the UI in onResume(). I store this primitive in a separate class with a static variable reference. I realize I could use SharedPreferences to store this variable, however, what I want to know is if using the static variable to hold this primitive could potentially create problems.
Thanks to everyone for their input.
static variables holds value till application is running, once application get destroy all static variables loses their references (non long term) while share preference holds the value even if application get destroy, so consistency is more in share preference
now its upto you whether you want the variable value consistent or not
I DISAGREE with static variable loses their references. Even when activities that hold static variable values destroy, other activities can still access them. For example, a bitmap variable from another activity that is closed completely, can be used by another activity
I have a ListView with a custom ArrayAdapter, that shows orders from an ArrayList. These orders are supposed to be synced with my server. There I have an API, which I am requesting for new orders, and if there are any, I get an XML of the order back. What is the best approach to dynamically update the listView? I do not want to use SQLite to store the orders, because only last ten are supposed to be displayed. With a ContentProvider I am not able to store my custom Order object. And if I wrap the ArrayList into a singleton class and use it in the service as well as in the Activity class for the ArrayAdapter, the ListView is not dynamically updated (probably, because the arrayAdapter makes a copy of the arraylist?). Thank you very much.
Filip
use Intent or Bundle
i'm no sure what you mean regarding the ArrayAdapter not being updated, but i can give you a solution we used in my company.
I have a DataMaanger which is a bridge between the Activities and the Networking or SQLite.
The dataMaanger keeps it's data in memory so it's not in DB or on disk. the disadvantage of it is if your app gets killed for lack of memory and reconstructs itself, the dataManager will be empty, which leaves you with two options, either on every Activitie's death or you main task's activities death you serialize your DataManager's data, or if you are not dependant on any previous data, just make arequest again and update the data manager.
I use broadcasts to notify my activities.
To get an access to the DataManager i don't use a sigletone. i use the Application object, you can extend it and in the Manifest.xml give it's name in the tag, then it will be used instead of the regualr Application object.
You can access it later by using getApplication() method in Activity class.
I was looking at the way Android handles orientation change for my application (I discovered that it restarts the mainactivity on orientation change. I've seen that you can override the method
protected void onSaveInstanceState(Bundle outState)
To save stuff, then have the in onStart. The problem is that I've my view with custom objects and a listview using a custom adapter. Everything is in a ArrayList of these objects, but I've noticed that you can't put arbitrary objects in the bundle! So how do I save the state?
Have you tried using: its work around ,
<activity name= ".YourActivity" android:configChanges="orientation|screenSize"/>
in Manifest file?
It does not work by default because , when you change the orientation onCreate will be called again and it redraws your view.
If you write this parameter no need to handle in Activity , the framework will take care of rest of things.
It will retain the state of the screen or layout if orientation is changed.
NOTE If you are using a different layout for landscape mode , by adding these parameters the layout for landscape mode will not be called.
Other way and Another way
EDIT: On newer versions of Android and with the compatibility library, retained fragments are usually the best way to handle keeping expensive-to-recreate data alive across activity destruction/creation. And as Dianne pointed out, retaining nonconfiguration data was for optimizing things like thumbnail generation that are nice to save for performance reasons but not critical to your activity functioning if they need to be redone - it's not a substitute for properly saving and restoring activity state.
But back when I first answered this in 2010:
If you want to retain your own (non view-state) data, you can actually pass an arbitrary object specifically for orientation changes using onRetainNonConfigurationInstance(). See this Android Developers blog post. Just be careful not to put any Views or other references to the pre-rotation Context/Activity in the object you pass, or you'll prevent those objects from being garbage collected and may eventually run out of memory (this is called a context leak).
First, you need to determine what is actually the "state" in your app. You haven't said what you are actually doing, but let me assume that the ArrayList of objects is the state the user is working with.
Second, decide what the lifecycle of this state actually is. Is it really tied to that activity? Or should the user not lose it if say their battery runs low, the device turns off, and they later return to your app? If the former, onSaveInstanceState() is correct; if the latter, you'll want to save to persistent storage in onPause().
For onSaveInstanceState() with custom objects, the key is to implement the Parcelable interface. This involves implementing the methods on Parcelable, as well as making a static CREATOR object in your class. Here's the code for a typical simple Parcelable class:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/ComponentName.java
The key functions are the Parcelable implementation:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/ComponentName.java#317
and the CREATOR static class:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/ComponentName.java#355
(The static writeToParcel() and readFromParcel() are just conveniences that were done for that class and not required.)
Now that you have that, you can put your entire ArrayList of objects into the saved state Bundle with Bundle.putParcelableArrayList:
http://developer.android.com/reference/android/os/Bundle.html#putParcelableArrayList(java.lang.String, java.util.ArrayList)
In Activity.onCreate(), check to see if you have a savedState Bundle, and if so try to retrieve the ArrayList from that and use it if found, creating a new adapter and list view for the new activity that are used to display it.
but I've noticed that you can't put arbitrary objects in the bundle!
First make your custom objects Parcelable.
Then you can put them in to a bundle.
Everything is in a ArrayList of these objects
You can use putParcelableArrayList method in bundle to store an ArrayList of custom "parcelable" objects.
write your objects to JSON Strings using Google's Gson, then save them as a String. Then, build them back from the saved JSON Strings when rebuilding the Activity/Fragment
import com.google.gson.Gson;
public class MyClass {
private int a;
private String s;
private OtherSerializableClass other;
private List<String> list;
public String toJson() {
return new Gson().toJson(this);
}
public static ChatAPI_MessagesArray fromJson(String json){
return new Gson().fromJson(json, YourClass.class);
}
// Getters
...
// Setters
...
}
Usually we pass value in android from one activity to another activity by Intent function.Is there is any another way is possible to pass the values from one activity to another activity with out Intent function
Yes. Create a class that extends android.app.Application, then in the Manifest put this class as the name of your application
<application android:name=".ClassNameOfTheClassYouCreated"...>
...activities etc here...
</application>
Now, that class that you created is your application. Its lifespan is all the way as long as the application is running, it holds the activities stack and you can add some custom fields to hold your values. To get the Application instance from an Activity, hit this.getApplication().
Edit regarding fields values being reset (in response to the commend by #hackbod): Using static fields on singletons is the other way to hold global values, but I find the proposed one more elegant. As of the case you mention with resetting values, that can also happen in other contexts (like incoming phone call, orientation change), which raises the need to sanitize (or check for existence, call it whatever you like) values before using them. Always!
Information flow can be realized in various way, all you need is a way to save and retrieve your data.
You can save and then get your data which you want it to flow via static class, file storage, database, or even remote storage by using network.
Intent is the better way. Android creates it, so use it. :)
From http://developer.android.com/guide/topics/providers/content-providers.html :
Content providers store and retrieve data and make it accessible to all applications. They're the only way to share data across applications; there's no common storage area that all Android packages can access.
If you want to make your own data public, you have two options: You can create your own content provider (a ContentProvider subclass) or you can add the data to an existing provider — if there's one that controls the same type of data and you have permission to write to it.
I'm not very experienced in android specific components, so I just can't get where I need to look.
I have three activities:
1st gets info about some groups of objects, user selects some of this groups and activity needs to star next activity
2nd activity shows all objects from groups, that user selected at previous activity, here user can deselect some selected objects and then activity starts 3d activity
3d activity allows user to do something with selected objects
My solution is make some singleton model, that let activities get and save information about objects,
but i suppose, that android has some special components to provide data between activities
Help me to find this components^ please
It depends on the type of data that you want to share:
Primitive Data Types
To share primitive data between Activities/Services in an application, use Intent.putExtras(). For passing primitive data that needs to persist use the Preferences storage mechanism.
Non-Persistent Objects
For sharing complex non-persistent user-defined objects for short duration, the following approaches are recommended:
The android.app.Application class
The android.app.Application is a base class for those who need to maintain global application state. It can be accessed via getApplication() from any Activity or Service. It has a couple of life-cycle methods and will be instantiated by Android automatically if your register it in AndroidManifest.xml.
A public static field/method
An alternate way to make data accessible across Activities/Services is to use public static fields and/or methods. You can access these static fields from any other class in your application. To share an object, the activity which creates your object sets a static field to point to this object and any other activity that wants to use this object just accesses this static field.
A HashMap of WeakReferences to Objects
You can also use a HashMap of WeakReferences to Objects with Long keys. When an activity wants to pass an object to another activity, it simply puts the object in the map and sends the key (which is a unique Long based on a counter or time stamp) to the recipient activity via intent extras. The recipient activity retrieves the object using this key.
A Singleton class
There are advantages to using a static Singleton, such as you can refer to them without casting getApplication() to an application-specific class, or going to the trouble of hanging an interface on all your Application subclasses so that your various modules can refer to that interface instead.
But, the life cycle of a static is not well under your control; so to abide by the life-cycle model, the application class should initiate and tear down these static objects in the onCreate() and onTerminate() methods of the Application Class
Persistent Objects
Even while an application appears to continue running, the system may choose to kill its process and restart it later. If you have data that you need to persist from one activity invocation to the next, you need to represent that data as state that gets saved by an activity when it is informed that it might go away.
For sharing complex persistent user-defined objects, the following approaches are recommended:
Application Preferences
Files
contentProviders
SQLite DB
If the shared data needs to be retained across points where the application process can be killed, then place that data in persistent storage like Application Preferences, SQLite DB, Files or ContentProviders.
yes, you can send data between activities using Intents. Using the putExtra() function for that. If you want to pass your own objects, you need to implement Parcalable class.
There is no problem with using a singleton to share information between your Activities, especially if you need this data to be consistent throughout your whole app.
Alternatively you could use an Intent to pass data between Activities - putExtra().
Yes it does:
http://www.remwebdevelopment.com/dev/a33/Passing-Bundles-Around-Activities.html
Basically you can either send a Bundle or just use putExtra function for that.
try this way please
Intent i = new Intent(this, YourTragetedActivity.class);
i.putExtra("value1", "test1");
i.putExtra("value2", "test2");
startActivity(i);
//// On Your TragetedActivity
getIntent().getStringExtra("value1")
getIntent().getStringExtra("value2")