I am trying to pass a List of PackageInfo between multiple activities in my application. Is it possible to do this using an Intent?
You can again get package info in second activity, if you do want some operation to be done based on package, pass array of package names (com.google.) from one activity to other.
You can put anything in the intent's extra, the object just have to be parcelable (seems complicate but it's not at all!).
You have example here : http://developer.android.com/reference/android/os/Parcelable.html
Maybe a concrete list is parcelable (like ArrayList) I don't remember.
The other way I'm thinking about is maybe to use the shared preference, I know you can put a set in there, if you wan't to access your list everywhere that can be a way to achieve it.
Hope I help !
In that exact case you can query the PackageInfo list in every activity. But in the common case, when I have to share non-parcelable objects through multiple activities, I use to create a singleton class for that. Note that it would consume memory, so make sure to dispose the singleton when it's not needed anymore.
For example, for PackageInfos it would look something like this:
public class SharedPackageInfos{
private SharedPackageInfos(){}
private static SharedPackageInfos _current;
public static SharedPackageInfos getCurrent()
{
if(_current == null)
{
_current = new SharedPackageInfos();
}
return _current;
}
private List<PackageInfo> packageInfos;
public List<PackageInfo> getPackageInfos()
{
return _packageInfos;
}
public void setPackageInfos(List<PackageInfo> packageInfos)
{
this.packageInfos = packageInfos;
}
public static void dispose()
{
_current = null;
}
}
And from the activities call
SharedPackageInfos.getCurrent().setPackageInfos(myList); //save a list
List<PackageInfo> packageInfos = SharedPackageInfos.getCurrent().getPackageInfos(); //retreive a list
Related
A network call returns a very large json file. However, I just need to use a small portion of this through out the entire app. What is the best strategy on using a small amount of data for several fragments and activities ?
I tried to use shared preferences, but that does not store objects.
For sharing complex data structures or objects, I would extend Application by making a custom sub class. Application object (as the name implies) is accessible to all Activities, even when app transitions from one to another. Below is a very simple example, just to show you the idea. You can modify/adjust that to your needs.
public class MyApplication extends Application {
private X x;
public static void setX(X x) { ... }
public static X getX() { ... }
}
public class ActivityA extends Activity {
...
MyApplication.setX(x);
}
public class ActivityB extends Activity {
...
X x = MyApplication.getX();
}
X can be a collection, data structure, or any object for that matter.
When extending Application, you need to declare it in the manifest. You can find information on how to do that.
Extract the required data from your JSON as a String and then pass it as an extras parameter to the Activities and Fragments that need it:
Intent intent = new Intent(context, SomeActivity.class);
intent.putExtra("YOUR_DATA_KEY", yourJsonString);
startActivity(intent);
and then extract it back again at the Activities and Fragments that need it:
Intent intent = getIntent();
String yourJsonString= intent.getStringExtra("YOUR_DATA_KEY");
I am new at developing Android .I have a question. How to pass object from one activity to another activity without using Intent.Can I do it by Interface ,if so how Could you please how can I hanle that
I think you have 2 options
In memory, save it to somewhere that all activities can reach, or make it static. This is not good idea though
Save it to disk, and use it, such as shared preferences
You can store it in SharedPreferences and then in another Activity
restore it.
You can store it in SQLite and then in another Activity restore it.
You can use static links
You can use service
save data in a singleton class model and get the same object from another activity
Create a class like this
public class SingletonModel {
private static SingletonModel instance;
public String textData = ""
public synchronized static SingletonModel getSingletonModel() {
if (instance == null) {
instance = new SingletonModel();
}
return instance;
}
private void SingletonModel(){}
}
From first activity do like this
SingletonModel.getSingletonModel().textData ="Your data goes here";
From second activity do like this
textView.setText(SingletonModel.getSingletonModel().textData);
If the data should persist, use a file. If not, use a singleton.
My MainActivity calls another Activity A which needs to access some members of MainActivity.
What is the best way to send a reference to Main Activity (or its context) to Activity A without resorting to complicated methods like parcelables etc?
There are some heavyweight android wrestling matches here but I am not sure that it is relevant to my problem.
details
I have Alert and Alerted objects in a one-to-many relationship (Alerted represents the various times an Alert was rung).
AlertsListActivity extends ListActivity which displays a list of Alert objects from a SQLite database table (primary key: alertId). It has an AlertsListAdapter.
AlertedsListActivity has a ListFragment which displays a list of Alerted objects from Alerted table (foreign key is alertId from Alert table).
It has an AlertedsListAdapter.
AlertsListActivity needs to call AlertedsListActivity to display the list of Alerted objects. I used startActivityForResult().
Inside AlertedsListAdapter
public View getView(int position, View convertView, ViewGroup parent) {
final Alert alertItem = (Alert) mainActivity.alertsListAdapter.getItem(position);
final Alerted alertedItem = (Alerted) getItem(position);
...
I do need the Alert objects also, in order to display some identifying information from them with each Alerted list item. Hence I need the reference to mainActivity.alertsListAdapter
How can AlertedsListActivity access AlertsListActivity?
Update: Since I did not get any solutions, I implemented a workaround. The data that I needed to access from Main Activity, I modified. So the Alert object was made a parcelable, and the SQLOpenHelper was made a singleton.
This allows the data to be accessed from Activity A.
Here's the simple, common way to do it:
singletons typically have variables like the below example, "useThisContext" or "mainFeedIsHere".
public class Cloud
{
private static Cloud ourInstance = new Cloud();
private Cloud() { Utils.Log("cloud singleton launched"); }
public synchronized static Cloud getInstance()
{
return ourInstance;
}
/////////////////////////////////////////////////
public Context useThisContext;
another example ...
public class Feed
{
private static Feed ourInstance = new Feed();
private Feed()
{
Utils.Log("feed singleton launched");
freshestPostsForDisplay = new ArrayList<ParseObject>();
}
public synchronized static Feed getInstance()
{
return ourInstance;
}
public List<ParseObject> freshestPosts;
public MainActivity mainFeedIsHere;
Quite simply when everything launches (or when it changes), those "things" need to set those variables in the singleton. In other words, those things "tell the singleton, where they are." It's that simple.
So, in the MainActivity perhaps, in onCreate, it might say something like...
CLOUD.useThisContext = this;
FEED.mainFeedIsHere = this;
Then for example inside Feed.java you may have say
mainFeedIsHere.feedReload();
It goes without saying you have to check that they are not null (but how else could it be?) and you have to keep them up-to-date as it were. (i.e., for whatever reason you may want to change "useThisContext" -- again how else could it be?)
{Sometimes you'll have one "centralised" singleton .. perhaps "State" .. to sort of combine all these together - so that anyone can "get to" any of those "exposed" things as needed. This is, really, how game engines go; so that you can say more or less SoundEffects.Booms() or Tanks.Faster() or AI.FindVillains() at any time anywhere.}
Cheers!
Since I did not get any solutions, I implemented a workaround. The data that I needed to access from Main Activity, I modified. So the Alert object was made a parcelable, and the SQLOpenHelper was made a singleton.
This allows the data to be accessed from Activity A.
I'm a beginner to android development, and I'm trying to write my code in an MVC pattern, but I'm having trouble understanding how a model would work. As far as I can tell every time you start a new activity with an intent you are not able to pass a model along with it. As far as i can tell you'd have to reinitialize it each time you start a new activity. Am I missing something? I looked into Parcelable, but it seems that you loose your methods if you make your model Parcelable. right now I'm building a log in system, which checks my local sqllite db on start up if the user has already logged in, and if so it passes to another activity, otherwise it passes to the log in activity, but I wan't to keep that user model alive through all the activities. Is thee a way to do that?
You might want to also consider keeping a static reference around to the model data that you want to share across activities so that you don't have to keep serializing/deserializing the model when switching between activities. You can get away with using Parcelable if your models are small, but at some point, performance may become an issue.
I'm working on a project where we keep the models in a Singleton that we can access throughout the app, and although I generally hate Singleton's for how they can make unit testing more difficult, I have found this approach to perform better with larger models than trying to rely on Android's serialization mechanism.
Here's is a very rough example of what I mean (disclaimer: I have not actually run tested this code, but I hope this illustrates the concept):
You might have a singleton class that I terribly called Models
public class Models {
private static Models instance;
private boolean isInitialized = false;
private User user;
private OtherInterestingModel otherInterestingModel;
private Models() {
}
public static synchronized Models getInstance() {
if (instance == null) {
instance = new Models();
}
return instance;
}
public void loadModels() {
if (!isInitialized) {
/*
* One-time model initialization here.
*/
isInitialized = true;
}
}
public User getUser() {
return user;
}
public OtherInterestingModel getOtherInterestingModel() {
return otherInterestingModel;
}
}
In your LoginActivity, you can initialize the Models class, say, in your onCreate():
public class LoginActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Models.getInstance().loadModels();
User user = Models.getInstance().getUser();
OtherInterestingModelData otherData = Models.getInstance().getOtherInterestingModel();
// Do something with the model data...
}
/*
* This might be called after the user enters data and clicks a login button...
*/
private void login() {
startActivity(new Intent(this, AwesomeLoggedInActivity.class));
}
}
Once the user successfully logs into your app, you could have basically the same code in your main activity:
public class AwesomeLoggedInActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Models.getInstance().loadModels();
User user = Models.getInstance().getUser();
OtherInterestingModelData otherData = Models.getInstance().getOtherInterestingModel();
// Do something with the model data...
}
}
Notice that by having a Singleton, you avoided having to serialize the model data by passing it through the intent that started the main activity.
Yes, you can do that with the Parcelable interface.
You do not lose your class's methods when you implement the Parcelable interface. The interface simply defines a method for writing your member variables to a Parcel object when you need to pass the object around.
Once you retrieve the data from your Intent via getParcelableExtra(), the object is recreated from the Parcel and you can once again treat it as an instance of whatever class it is.
For example, if you have a User class that extends Parcelable, you can bundle it with an Intent by calling putExtra("user", myUser). myUser is then (behind the scenes) packed into a Parcel and attached to the Intent. In your next Activity, you can retrieve that User object with User myUser = (User) getParcelableExtra("user");, and the Parcel will be unpacked and returned to you. You wil once again have a fully functioning User object.
I have implemented a bus for my app for communication between fragments and activities. I add a subscriber by adding an instance of either a Fragment or an Activity to a list. and I iterate through that list invoking a method to notify each of the subscribers of what is going on. Now I need to keep the list clean, I don't want to add multiple instances of of the same class in the list. I can use equals() for an Activity but I cant for a Fragment because its final so I cant override it.
WHAT I HAVE TRIED
I have tried to keep a Class object of each subscriber in the list which works fine until I go to invoke the method. You cant invoke a method without an instance to invoke it from. So that doesnt work.
I could also keep a separate list, one to hold Class objects and one to hold the actual instance. But I want to avoid adding another dependency if at all possible.
I could also manually do a instanceof check for each Fragment, but I dont want to do that because I already have 5 fragments, and if I add or remove any then I have to come back here and update this method.
So my question is, other than adding another List to hold the Class objects or manual instanceof checks, are there any other ways I can make sure I dont add multiple instances to the subscribers List?
Here is the relevant code if you need it:
public void subscribe(Object object) {
if (!mSubscribers.contains(object)) {
mSubscribers.add(object);
}
}
public void notifySubscribers(BusEvent event) throws InvocationTargetException, IllegalAccessException {
for (Object o : mSubscribers) {
Method methodToCall = getMethodToCall(o);
if (methodToCall != null) {
methodToCall.invoke(o, event);
}
}
}
Ok I have found a suitable answer to my problem. I want to share it here in hopes that it will help someone else out. Android has a class called LocalBroadcastManager. It is available in the v4 support library. In your activity you call 'LocalBroadcastManager.getInstance().registerReceiver()'. You pass into that method a class that extends BroadcastReceiver and an 'IntentFilter' to tell the receiver what to listen for. Then in any class including Fragments you call LocalBroadcastManager.getInstance().sendBroadcast() and pass in an Intent that matches the IntentFilter you used when registering. Here is the code I used to get it to work:
private void registerLocalBroadcastReceiver() {
// call this method in your activity (or any class you want to listen for broadcasts)
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
manager.registerReceiver(new OpenMenuBroadcastReceiver(), new IntentFilter("open-html"));
}
private void sendMessageToActivity(int position) {
// use this in a fragment (or any other class) to send a message
LocalBroadcastManager broadcast = LocalBroadcastManager.getInstance(getActivity());
Intent message = new Intent("open-html");
String name = (String) getListAdapter().getItem(position);
message.putExtra("name", name);
broadcast.sendBroadcast(message);
}
class OpenMenuBroadcastReceiver extends BroadcastReceiver {
// this is an inner class to my activity, when you send the message this method
// will be called to handle the message
#Override
public void onReceive(Context context, Intent intent) {
String name = intent.getStringExtra("name");
if (name != null && name.equalsIgnoreCase("home")) {
replaceFragment(Tag.HOME_FRAGMENT.getTag(), new HomeFragment(), R.id.main_frame);
mDrawerLayout.closeDrawer(Gravity.START);
return;
}
openMenuItemsFragment(name);
}
}
The good thing about this is that it is completely local to your app. External apps cant receive your broadcasts so its secure. You can find out more on how to use it on the Android developer site.