java - putextra - parcelable




如何在Android上將對像從一項活動傳遞給另一項活動 (20)

我正在嘗試從一個Activity發送客戶類的對象,並將其顯示在另一個Activity

客戶類的代碼:

public class Customer {

    private String firstName, lastName, Address;
    int Age;

    public Customer(String fname, String lname, int age, String address) {

        firstName = fname;
        lastName = lname;
        Age = age;
        Address = address;
    }

    public String printValues() {

        String data = null;

        data = "First Name :" + firstName + " Last Name :" + lastName
        + " Age : " + Age + " Address : " + Address;

        return data;
    }
}

我想將其對像從一個Activity發送到另一個,然後在另一個Activity上顯示數據。

我怎樣才能做到這一點?


  1. I know that static is bad, but it seems that we're forced to use it here. The problem with parceables/seriazables is that the two activities have duplicate instances of the same object = waste of memory and CPU.

    public class IntentMailBox {
        static Queue<Object> content = new LinkedList<Object>();
    }
    

Calling activity

IntentMailBox.content.add(level);
Intent intent = new Intent(LevelsActivity.this, LevelActivity.class);
startActivity(intent);

Called activity (note that onCreate() and onResume() may be called multiple times when the system destroys and recreates activities)

if (IntentMailBox.content.size()>0)
    level = (Level) IntentMailBox.content.poll();
else
    // Here you reload what you have saved in onPause()
  1. Another way is to declare a static field of the class that you want to pass in that very class. It will serve only for this purpose. Don't forget that it can be null in onCreate, because your app package has been unloaded from memory by system and reloaded later.

  2. Bearing in mind that you still need to handle activity lifecycle, you may want to write all the data straight to shared preferences, painful with complex data structures as it is.


我使用parcelable將數據從一個活動發送到另一個活動。 這是我的代碼在我的項目中正常工作。

public class Channel implements Serializable, Parcelable {

    /**  */
    private static final long serialVersionUID = 4861597073026532544L;

    private String cid;
    private String uniqueID;
    private String name;
    private String logo;
    private String thumb;


    /**
     * @return The cid
     */
    public String getCid() {
        return cid;
    }

    /**
     * @param cid
     *     The cid to set
     */
    public void setCid(String cid) {
        this.cid = cid;
    }

    /**
     * @return The uniqueID
     */
    public String getUniqueID() {
        return uniqueID;
    }

    /**
     * @param uniqueID
     *     The uniqueID to set
     */
    public void setUniqueID(String uniqueID) {
        this.uniqueID = uniqueID;
    }

    /**
     * @return The name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name
     *            The name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the logo
     */
    public String getLogo() {
        return logo;
    }

    /**
     * @param logo
     *     The logo to set
     */
    public void setLogo(String logo) {
        this.logo = logo;
    }

    /**
     * @return the thumb
     */
    public String getThumb() {
        return thumb;
    }

    /**
     * @param thumb
     *     The thumb to set
     */
    public void setThumb(String thumb) {
        this.thumb = thumb;
    }


    public Channel(Parcel in) {
        super();
        readFromParcel(in);
    }

    public static final Parcelable.Creator<Channel> CREATOR = new Parcelable.Creator<Channel>() {
        public Channel createFromParcel(Parcel in) {
            return new Channel(in);
        }

        public Channel[] newArray(int size) {

            return new Channel[size];
        }
    };

    public void readFromParcel(Parcel in) {
        String[] result = new String[5];
        in.readStringArray(result);

        this.cid = result[0];
        this.uniqueID = result[1];
        this.name = result[2];
        this.logo = result[3];
        this.thumb = result[4];
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {

        dest.writeStringArray(new String[] { this.cid, this.uniqueID,
                this.name, this.logo, this.thumb});
    }
}

在activityA中像這樣使用它:

Bundle bundle = new Bundle();
bundle.putParcelableArrayList("channel",(ArrayList<Channel>) channels);
Intent intent = new Intent(ActivityA.this,ActivityB.class);
intent.putExtras(bundle);
startActivity(intent);

在ActivityB中使用它來獲取數據:

Bundle getBundle = this.getIntent().getExtras();
List<Channel> channelsList = getBundle.getParcelableArrayList("channel");

Android Activity objects can be destroyed and reconstituted. So, you will need to use another approach to look them - or any object they create !!! - up. That is, you could pass as static class reference but then the object handle (Java calls these "references", as does SmallTalk; but they are not references in the sense of C or assembly) will be possibly invalid later because a "feature" of Android OE is any Activity can be annihilated and reconstituted later.

The original question asked "How to pass object from one activity to another in Android" and nobody has answered that. For sure, you can serialized (Serializable, Parcelable, to/from JSON) and pass a copy of the object's data and a new object having the same data could be created; but it will NOT have the same references/handles. Also, many others mentioned you can store the reference in a static store. And that will work unless Android decides to onDestroy your Activity.

So, to really solve the original question you would need a static lookup plus each object will update its reference when/if it is recreated. Eg each Android Activity would relist itself if its onCreate is called. You can also see how some people use the task list to search out an Activity by name. (system is temporarily destroying this instance of the activity to save space..getRunningTasks, the task list is effectively a specialized listing of the most recent object instance of each Activity).

For reference:

Stopped: "The activity is completely obscured by another activity (the activity is now in the "background"). A stopped activity is also still alive (the Activity object is retained in memory , it maintains all state and member information, but is not attached to the window manager). However, it is no longer visible to the user and it can be killed by the system when memory is needed elsewhere."

onDestroy "system is temporarily destroying this instance of the activity to save space."

So, the Message Bus is a workable solution. It basically "punts". Rather than try to have references to objects; then you re-architect your design to use MessagePassing instead of SequentialCode. Exponentially harder to debug; but it lets you ignore these sort of OperatingEnvironment understandings. Effectively, each object method access is inverted so the caller posts a Message and the object itself defines a handler for that message. Lots more code but can make it robust with the Android OE restrictions.

If all you want is the top Activity (typical thing in Android apps due to "Context" being needed everywhere), then you can just have each Activity lists itself as "top" in the static global space whenever its onResume is called. Then your AlertDialog or whatever which needs a context can just grab it from there. Also, its a bit yucky to use a global but can simplifying passing a Context up and down everywhere and, for sure, when you use a MessageBus then IT IS global anyways.


Create two methods in your custom Class like this

public class Qabir {

    private int age;
    private String name;

    Qabir(){
    }

    Qabir(int age,String name){
        this.age=age; this.name=name;
    }   

    // method for sending object
    public String toJSON(){
        return "{age:" + age + ",name:\"" +name +"\"}";
    }

    // method for get back original object
    public void initilizeWithJSONString(String jsonString){

        JSONObject json;        
        try {
            json =new JSONObject(jsonString );
            age=json.getInt("age");
            name=json.getString("name");
        } catch (JSONException e) {
            e.printStackTrace();
        } 
    }
}

Now in your sender Activity do like this

Qabir q= new Qabir(22,"KQ");    
Intent in=new Intent(this,SubActivity.class);
in.putExtra("obj", q.toJSON());
startActivity( in);

And in your receiver Activity

Qabir q =new Qabir();
q.initilizeWithJSONString(getIntent().getStringExtra("obj"));

Hello all I see a lot of good options but I was wondering why Binding hasn't been used?

Passing a reference to an object just seems more efficient to me than serializing and desterilizing objects, but I have not done a deep dive to see if that is what is going on behind the scenes.

Creating a Binder is simple enough...

public class MyBinder extends Binder {

    private Object myObject;

    public MyBinder(Object object) {
        myObject = object;
    }

    public Object getObject() {
        return myObject;
    }

}

And creating the parcelable to use it isn't that bad ether.

public class MyParcelable implements Parcelable {

    private Object myObject;

    public MyParcelable() {
    }

    public MyParcelable(Parcel parcel) {
        myObject = ((MyBinder)parcel.readStrongBinder()).getObject();
    }

    public void setObject(Object object) {
        myObject = object;
    }

    public Object getObject() {
        return myObject;
    }

    public void writeToParcel(Parcel parcel, int flags) {
        parcel.writeStrongBinder(new MyBinder(myObject));
    }

    public int describeContents() {
        return myObject == null ? 0 : 1;
    }

    public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {

        public MyParcelable createFromParcel(Parcel parcel) {
            return new MyParcelable(parcel);
        }

        public MyParcelable[] newArray(int length) {
            return new MyParcelable[length];
        }

    };
}

This logic is really cool because you are actually passing a reference from activity to activity.

I would advise checking for nulls and if the instanceof Binder is MyBinder!

and to implement this you just...

Send it off

Object myObject = "some object";
MyParcelable myParcelable = new MyParcelable();
myParcelable.setObject(myObject);

intent.putExtra("MyParcelable", myParcelable);

Get it back

myParcelable = (MyParcelable) getIntent().getExtras().getParcelable("MyParcelable");
myObject = myParcelable.getObject();

Heck someone could get all crazy and make this sucker a true generic.


I had always wondered why this can't be as simple as calling into a method of the other activity. I recently wrote a utility library that makes it almost as simple as that. You can check it out here( https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher ).

GNLauncher makes sending objects/data to an Activity from another Activity etc as easy as calling a function in tha Activity with the required data as parameters. It introduces type safety and removes all the hastles of having to serialize, attaching to the intent using string keys and undoing the same at the other end.

用法

Define an interface with the methods you want to call on the Activity to launch.

public interface IPayload {
    public void sayHello(String name, int age);
}

Implement the above interface on the Activity to launch into. Also notify GNLauncher when the activity is ready.

public class Activity_1 extends Activity implements IPayload {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Notify GNLauncher when the Activity is ready. 
        GNLauncher.get().ping(this);
    }

    @Override
    public void sayHello(String name, int age) {
        Log.d("gnlib_test", "Hello " + name + "! \nYour age is: " + age);
    }
}

In the other Activity, get a proxy to the above Activity and call any method with the desired parameters.

public class Activity_2 extends Activity {
    public void onClick(View v) {
        ((IPayload)GNLauncher.get().getProxy(this, IPayload.class, Activity_1.class)).sayHello(name, age);
    }
}

The first activity will be launched and the method called into with the required parameters.

先決條件

Please refer to https://github.com/noxiouswinter/gnlib_android/wiki#prerequisites for information on how to add the dependencies.


Pass object from one activity to another activity.

(1) source activity

Intent ii = new Intent(examreport_select.this,
                    BarChartActivity.class);

            ii.putExtra("IntentExamResultDetail",
                    (Serializable) your List<ArraList<String>> object here);
            startActivity(ii);

(2) destination acitivity

List<ArrayList<String>> aa = (List<ArrayList<String>>) getIntent()
            .getSerializableExtra("IntentExamResultDetail");

Pass one activity to another:

startActivity(new Intent(getBaseContext(),GetActivity.class).putExtra("passingkey","passingvalue"));

Get values:

String myvalue= getIntent().getExtras("passingkey");

This question is also discussed in another question. Please have a look at a solution to Passing data through intent using Serializable . The main point is about using Bundle object which stores the necessary data inside Intent .

 Bundle bundle = new Bundle();

 bundle.putSerializable(key1, value1);
 bundle.putSerializable(key2, value2);
 bundle.putSerializable(key3, value3);

 intent.putExtras(bundle);

To extract values:

 Bundle bundle = new Bundle();

 for (String key : bundle.keySet()) {
 value = bundle.getSerializable(key));
 }

Advantage of Serializable is its simplicity. However, you should consider using Parcelable method if you need many data to be transferred, because Parcelable is specifically designed for Android and it is more efficient than Serializable . You can create Parcelable class using:

  1. an online tool - site
  2. a plugin for Android Studio - Android Parcelable code generator

We can pass the object from one activity to another activity:

SupplierDetails poSuppliersDetails = new SupplierDetails();

Inside poSuppliersDetails we have some values. Now I am sending this object to target activity:

Intent iPODetails = new Intent(ActivityOne.this, ActivityTwo.class);
iPODetails.putExtra("poSuppliersDetails", poSuppliersDetails);

How to get this in ACtivityTwo:

private SupplierDetails supplierDetails;
    supplierDetails =(SupplierDetails) getIntent().getSerializableExtra("poSuppliersDetails");

一種選擇是讓你的自定義類實現Serializable接口,然後你可以使用Intent#putExtra()方法的putExtra(Serializable..)變體傳遞額外的intent對象實例。

偽代碼

//To pass:
intent.putExtra("MyClass", obj);

// To retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");

使用gson將您的對象轉換為JSON並通過意向傳遞它。 在新的Activity中將JSON轉換為一個對象。

例:

Gson gson = new Gson();
String myJson = gson.toJson(vp);
intent.putExtra("myjson", myjson);

在你的下一個活動中,你想傳遞對象的地方:

Gson gson = new Gson();
YourObject ob = gson.fromJson(getIntent().getStringExtra("myjson"), YourObject.class);

在調用一項活動時

Intent intent = new Intent(fromClass.this,toClass.class).putExtra("myCustomerObj",customerObj);

在toClass.java中接收活動

Customer customerObjInToClass = getIntent().getExtras().getParcelable("myCustomerObj");

請確保客戶類實現parcelable

public class Customer implements Parcelable {

    private String firstName, lastName, address;
    int age;

    /* all your getter and setter methods */

    public Customer(Parcel in ) {
        readFromParcel( in );
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public LeadData createFromParcel(Parcel in ) {
            return new Customer( in );
        }

        public Customer[] newArray(int size) {
            return new Customer[size];
        }
    };


    @Override
    public void writeToParcel(Parcel dest, int flags) {

        dest.writeString(firstName);
        dest.writeString(lastName);
        dest.writeString(address);
        dest.writeInt(age);
    }

    private void readFromParcel(Parcel in ) {

        firstName = in .readString();
        lastName  = in .readString();
        address   = in .readString();
        age       = in .readInt();
    }

如果您選擇使用Samuh描述的方式,請記住只能發送原始值。 也就是說,可分區的值。 所以,如果你的對象包含複雜的對象,這些將不會遵循。 例如,像位圖,HashMap等變量......這些都很難通過意圖傳遞。

一般來說,我建議你只發送原始數據類型作為額外的東西,比如String,int,boolean等等。在你的情況下,它會是: String fnameString lnameint ageString address

我的觀點:更複雜的對象可以通過實現ContentProviderSDCard等來更好地共享。也可以使用靜態變量 ,但這可能會導致錯誤發生。

但是,這只是我的主觀意見。


您還可以將對象的數據寫入臨時字符串和整數,並將它們傳遞給活動。 當然,這樣,你可以獲得傳輸的數據,但不是對象本身。

但是,如果你只是想顯示它們,而不是在另一種方法或類似的東西中使用這個對象,那應該就足夠了。 我以同樣的方式做到了在另一個活動中顯示來自一個對象的數據。

String fName_temp   = yourObject.getFname();
String lName_temp   = yourObject.getLname();
String age_temp     = yourObject.getAge();
String address_temp = yourObject.getAddress();

Intent i = new Intent(this, ToClass.class);
i.putExtra("fname", fName_temp);
i.putExtra("lname", lName_temp);
i.putExtra("age", age_temp);
i.putExtra("address", address_temp);

startActivity(i);

您也可以直接將它們傳遞給臨時ivars,但這種方式在我看來更加清晰。 另外,您可以將temp ivars設置為null,以便它們可以更快地被GarbageCollector清除。

祝你好運!

注意:重寫toString()而不是編寫自己的打印方法。

正如下面的評論中所提到的,這是您如何將數據返回到其他活動中的方式:

String fName = getIntent().getExtras().getInt("fname");

我做了一個持有臨時對象的單例助手類。

public class IntentHelper {

    private static IntentHelper _instance;
    private Hashtable<String, Object> _hash;

    private IntentHelper() {
        _hash = new Hashtable<String, Object>();
    }

    private static IntentHelper getInstance() {
        if(_instance==null) {
            _instance = new IntentHelper();
        }
        return _instance;
    }

    public static void addObjectForKey(Object object, String key) {
        getInstance()._hash.put(key, object);
    }

    public static Object getObjectForKey(String key) {
        IntentHelper helper = getInstance();
        Object data = helper._hash.get(key);
        helper._hash.remove(key);
        helper = null;
        return data;
    }
}

而不是將你的對象放入Intent中,使用IntentHelper:

IntentHelper.addObjectForKey(obj, "key");

在您的新活動中,您可以獲取對象:

Object obj = (Object) IntentHelper.getObjectForKey("key");

請記住,一旦加載,該對象將被刪除以避免不必要的引用。


最好的方法是在應用程序中有一個類(稱為Control),該類將保存一個類型為“Customer”的靜態變量(在您的情況下)。 初始化活動A中的變量

例如:

Control.Customer = CustomerClass;

然後轉到活動B並從Control類中獲取它。 不要忘記在使用變量之後分配一個空值,否則內存將被浪費。


有幾種方法可以訪問其他類或Activity中的變量或對象。

A.數據庫

B.共享偏好。

C.對象序列化。

D.可以保存公共數據的類可以命名為Common Utilities。 這取決於你。

E.通過Intents和Parcelable接口傳遞數據。

這取決於您的項目需求。

A. 數據庫

SQLite是嵌入到Android中的開源數據庫。 SQLite支持標準的關係數據庫功能,如SQL語法,事務和預處理語句。

Tutorials

B. 共享偏好

假設你想存儲用戶名。 所以現在有兩件事情,一個關鍵的用戶名, 值的價值。

如何存儲

 // Create object of SharedPreferences.
 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);

 //Now get Editor
 SharedPreferences.Editor editor = sharedPref.edit();

 //Put your value
 editor.putString("userName", "stackoverlow");

 //Commits your edits
 editor.commit();

使用putString(),putBoolean(),putInt(),putFloat()和putLong()可以保存所需的dtatype。

如何獲取

SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String userName = sharedPref.getString("userName", "Not Available");

http://developer.android.com/reference/android/content/SharedPreferences.html

C. 對象序列化

如果我們想要保存一個對象狀態以通過網絡發送它,或者您也可以將它用於您的目的,則使用對象serlization。

使用Java bean並將其存儲為其字段之一,並使用getter和setter來實現。

JavaBeans是具有屬性的Java類。 將屬性視為私有實例變量。 由於他們是私人的,所以他們可以從課外訪問的唯一途徑就是通過課堂中的方法。 更改屬性值的方法稱為setter方法,並且檢索屬性值的方法稱為getter方法。

public class VariableStorage implements Serializable  {

    private String inString;

    public String getInString() {
        return inString;
    }

    public void setInString(String inString) {
        this.inString = inString;
    }
}

通過使用,在郵件方法中設置變量

VariableStorage variableStorage = new VariableStorage();
variableStorage.setInString(inString);

然後使用對象序列化來序列化這個對象,並在你的其他類中反序列化這個對象。

在序列化過程中,對象可以表示為包含對像數據的字節序列,以及有關對像類型和存儲在對像中的數據類型的信息。

序列化對象寫入文件後,可以從文件讀取並反序列化。 也就是說,表示對象及其數據的類型信息和字節可用於在內存中重新創建對象。

如果你想為這個教程引用:

D.共同事業

你可以自己創建一個課程,它可以包含你在項目中經常需要的常用數據。

樣品

public class CommonUtilities {

    public static String className = "CommonUtilities";

}

E. 通過意圖傳遞數據

請參考教程Android - 地塊數據以在使用Parcelable類的活動之間傳遞此數據傳遞選項。


用Serializable實現你的類。 假設這是你的實體類:

import java.io.Serializable;

@SuppressWarnings("serial") //With this annotation we are going to hide compiler warnings
public class Deneme implements Serializable {

    public Deneme(double id, String name) {
        this.id = id;
        this.name = name;
    }

    public double getId() {
        return id;
    }

    public void setId(double id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private double id;
    private String name;
}

我們將名為dene從X活動發送到Y活動。 X活動中的某處;

Deneme dene = new Deneme(4,"Mustafa");
Intent i = new Intent(this, Y.class);
i.putExtra("sampleObject", dene);
startActivity(i);

在Y活動中,我們正在獲取對象。

Intent i = getIntent();
Deneme dene = (Deneme)i.getSerializableExtra("sampleObject");

而已。


public class MyClass implements Serializable{
    Here is your instance variable
}

現在你想在startActivity中傳遞這個類的對象。 只需使用這個:

Bundle b = new Bundle();
b.putSerializable("name", myClassObject);
intent.putExtras(b);

這在這里工作,因為MyClass實現了Serializable





android-activity