วิธีส่งผ่านวัตถุจากกิจกรรมหนึ่งไปอีกกิจกรรมหนึ่งบน Android


779

ฉันกำลังพยายามส่งวัตถุของคลาสลูกค้าของฉันจากที่หนึ่ง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
บางทีคุณควรเปลี่ยนคำตอบที่ยอมรับในมุมมองของความคิดเห็นจำนวนมาก
Rohit Vipin Mathews

ฉันเคยตั้งค่าวัตถุเป็น Pacelable หรือ Serializable แต่เมื่อใดก็ตามที่ฉันเพิ่มตัวแปรอื่น ๆ ฉันต้องเพิ่มมันทั้งหมดไปยังฟังก์ชั่นเพื่อรับและตั้งค่าสำหรับ Pacelable หรือ Serializable ดังนั้นฉันทำ DataCache เพื่อถ่ายโอนระหว่างกิจกรรมและชิ้นส่วน github.com/kimkevin/AndroidDataCacheง่ายในการถ่ายโอนออบเจ็กต์
kimkevin

คำตอบ:


886

ทางเลือกหนึ่งอาจให้คลาสที่คุณกำหนดเองใช้Serializableอินเทอร์เฟซและจากนั้นคุณสามารถผ่านอินสแตนซ์ของวัตถุในเจตนาพิเศษโดยใช้putExtra(Serializable..)ตัวแปรของIntent#putExtra()วิธีการ

รหัสเทียม :

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

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

หมายเหตุ: ตรวจสอบให้แน่ใจว่าแต่ละคลาสที่ซ้อนกันของคลาสแบบกำหนดเองหลักของคุณใช้อินเตอร์เฟส Serializable เพื่อหลีกเลี่ยงข้อยกเว้นการทำให้เป็นอนุกรม ตัวอย่างเช่น:

class MainClass implements Serializable {

    public MainClass() {}

    public static class ChildClass implements Serializable {

        public ChildClass() {}
    }
}

126
@OD: ในการป้องกันของฉันฉันไม่เคยพูดว่านี่เป็นตัวเลือกที่ดีที่สุด; OP เพิ่งขอทางเลือกและฉันแนะนำ ขอบคุณมาก
Samuh

83
เหตุใด Serializable จึงไม่ใช่ตัวเลือกที่ดี มันเป็นอินเทอร์เฟซที่รู้จักกันดีมีโอกาสดีที่คลาสของผู้คนอาจนำไปใช้งานได้แล้ว (ตัวอย่างเช่น ArrayList เป็น Serializable แล้ว) ทำไมคุณต้องเปลี่ยนวัตถุข้อมูลของคุณเพื่อเพิ่มรหัสพิเศษเพื่อส่งต่อจากคลาสหนึ่งไปอีกคลาสหนึ่ง ดูเหมือนว่าการออกแบบที่ไม่ดี ฉันสามารถจินตนาการได้ว่าอาจมีผลกระทบต่อประสิทธิภาพในบางระดับ แต่ฉันคิดว่าใน 99% ของกรณีผู้คนกำลังส่งผ่านข้อมูลจำนวนเล็กน้อยและพวกเขาจะไม่สนใจ บางครั้งเรียบง่ายและพกพาก็ดีขึ้นเช่นกัน
เนท

16
@Sander: คำตอบนี้ ( stackoverflow.com/questions/2139134/… ) ผิดใช่ไหม? เขาบอกว่าParcelable ถูกออกแบบมาโดยเฉพาะสำหรับวัตถุประสงค์ที่ (และเร็วกว่าSerializable) ฉันสับสน
Slauma

41
Parcelableอาจดีสำหรับความเร็ว แต่มีความซับซ้อนในการใช้งาน ถ้าคุณมีวัตถุ 8 อย่างที่คุณต้องผ่านระหว่างกิจกรรมคุณจะทำแต่ละอย่างParcelableหรือไม่ มันจะทำให้รู้สึกมากกว่าที่จะใช้Serializableแทน เมื่อคุณใช้งานParcelableคุณจะต้องเพิ่มโค้ดจำนวนมากลงในคลาสและสั่งซื้อฟิลด์ในลักษณะที่เฉพาะเจาะจงมาก Serializableคุณทำไม่ได้ ในที่สุดฉันคิดว่ามันลงมากับจำนวนวัตถุที่คุณกำลังผ่านและสิ่งที่คุณพยายามทำ
BlackHatSamurai

15
Serializableเป็นอินเตอร์เฟส Java มาตรฐาน คุณเพียงแค่ทำเครื่องหมายคลาสที่ Serializable ได้โดยการฝังอินเทอร์เฟซและ Java จะทำให้เป็นอันดับโดยอัตโนมัติในบางสถานการณ์ Parcelableเป็นอินเทอร์เฟซเฉพาะสำหรับ Android ที่คุณใช้การทำให้เป็นอนุกรม มันถูกสร้างขึ้นเพื่อให้มีประสิทธิภาพมากกว่าที่ Serializable และเพื่อแก้ไขปัญหาบางอย่างเกี่ยวกับโครงร่างการทำให้เป็นอันดับเริ่มต้นของ Java
Gaurav Arora

311

ใช้คลาสของคุณกับ 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");

แค่นั้นแหละ.


1
มันเป็นประโยชน์สำหรับฉันจริงๆ ขอบคุณ ... แต่เมื่อได้รับวัตถุที่ผ่านแล้วไวยากรณ์ควรเป็น [Deneme dene = (Deneme) i.getSerializableExtra ("sampleObject"); ] ... ใช่ไหม ???
JibW

1
@ MustafaGüven แต่ฉันก็classCastException: java.lang.Longทำได้โดยทำเช่นนั้น คุณช่วยอธิบายได้ไหม
Shajeel Afzal

ไม่มีความสัมพันธ์ใด ๆ กับคำตอบของฉัน มันแตกต่างกันมากที่คุณได้รับ คุณสามารถแบ่งปันรหัสของคุณได้ไหม
มุสตาฟากูเว่น

1
Serializable ช้าเกินไปสำหรับ POJO ขนาดใหญ่ การใช้ Bus เป็นรูปแบบที่ดีกว่ามาก
Steven Mark Ford

1
เหตุใดฉันจึงต้องนำหน้า(Serializable)วัตถุ
Alston

123
  • การใช้ตัวแปรคงที่ทั่วโลกนั้นไม่ใช่วิธีการทางวิศวกรรมซอฟต์แวร์ที่ดี
  • แปลงทุ่งวัตถุเข้าไปดั้งเดิมชนิดข้อมูลที่สามารถเป็นงานที่น่าตื่นเต้น
  • การใช้ซีเรียลไลซ์ไลซ์นั้นใช้ได้ แต่ก็ไม่มีประสิทธิภาพในแพลตฟอร์ม Android
  • พัสดุถูกออกแบบมาโดยเฉพาะสำหรับ Android และคุณควรใช้ นี่คือตัวอย่างง่ายๆ: การส่งวัตถุที่กำหนดเองระหว่างกิจกรรม Android

คุณสามารถสร้างรหัสพัสดุสำหรับชั้นเรียนของคุณโดยใช้เว็บไซต์นี้


4
ถ้าวัตถุของฉันมี Arraylist ซ้อนอยู่
ดร. aNdRO

10
บางทีอาจจะ แต่เราควรใช้การแสดง `` '' พร้อมเม็ดเกลือ imo หากสิ่งนั้นมาพร้อมกับราคาของการนำไปใช้Parcelableฉันก็ควรที่จะสอน POJO ให้กับผู้ที่ไม่เชื่อเรื่องพระเจ้าและใช้Serializableมัน
VH-NZZ

ฉันไม่เห็นด้วยที่คุณควรใช้ Parcelable รูปแบบ BUS ที่เรียบง่ายมีประสิทธิภาพมากขึ้นในขณะใช้งานจริงและประหยัดเวลาได้มาก
Steven Mark Ford

15
ตามมาตรฐานนี้bitbucket.org/afrishman/androidserializationtest Serializable นั้นเร็วกว่า Parcelable กรุณาหยุดแบ่งปันเรื่องไร้สาระ 5 ปีนี้เกี่ยวกับพัสดุ
afrish

7
ตัวแปรแบบคงที่ทั่วโลกเป็นอย่างไร "ไม่ดีการปฏิบัติทางวิศวกรรมซอฟต์แวร์ที่ดี"? คุณสามารถทำอะไรบางอย่างเช่นแคชแบบซิงเกิลและ / หรือตารางข้อมูลจากนั้นส่งผ่าน ID หรือที่คล้ายกัน เมื่อคุณส่งต่อการอ้างอิงใน Java คุณกำลังใช้ตัวแปรสแตติกโกลบอลในแง่ที่ว่าพวกเขาชี้ไปที่วัตถุเดียวกัน
breakline

112

ใช้gsonเพื่อแปลงวัตถุของคุณเป็น JSON และส่งผ่านความตั้งใจ ในกิจกรรมใหม่แปลง JSON เป็นวัตถุ

ในของคุณbuild.gradleเพิ่มสิ่งนี้ในการอ้างอิงของคุณ

implementation 'com.google.code.gson:gson:2.8.4'

ในกิจกรรมของคุณแปลงวัตถุเป็น json-string:

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

ในกิจกรรมการรับของคุณแปลง json-string กลับไปเป็นวัตถุดั้งเดิม:

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

สำหรับKotlinมันค่อนข้างเหมือนกัน

ส่งผ่านข้อมูล

val gson = Gson()
val intent = Intent(this, YourActivity::class.java)
intent.putExtra("identifier", gson.toJson(your_object))
startActivity(intent)

รับข้อมูล

val gson = Gson()
val yourObject = gson.fromJson<YourObject>(intent.getStringExtra("identifier"), YourObject::class.java)

3
มัน overkill, gson เป็นเพียงประเภทของสตริงอนุกรมเพื่อ json มันจะดีกว่าที่จะใช้ Serializable หรือ Paracable
James Roeiter

14
ไม่มีความจำเป็นที่จะต้องใช้อนุกรมในทุกวัตถุและในทุกโครงการ (เสียเวลา) ถ้าคุณสามารถใช้ไลบรารี (gson) ที่จัดการสิ่งนั้นได้ และเกี่ยวกับ overkill นั้นมีโทรศัพท์แบบ dual และ quadcore อยู่ที่นั่นพวกเขาสามารถจัดการรายการได้ตามแนวคิดคำตอบนี้
sagits

4
ฉันอยากจะแนะนำให้ใช้ gson เพราะ gson ยังสามารถเรียงลำดับรายการอาร์เรย์เป็นลำดับเพิ่มเติมจากด้านบน
nurgasemetey

4
มันเยี่ยมมาก! ในกรณีของฉันฉันใช้ห้องสมุดที่วัตถุไม่ได้ใช้เป็นอนุกรมหรือพัสดุ ดังนั้นนี่เป็นตัวเลือกเดียวของฉัน afaik
Chad Bingham

2
นี่คือตัวเลือก "ดีที่สุด" บางคลาสนั้นง่ายมากคุณไม่จำเป็นต้องทำให้ยุ่งยากมากเกินไปในการปรับใช้งานโดยใช้ซีเรียล
ไลซ์เซชั่น

98

ในขณะที่เรียกกิจกรรม

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

ใน toClass.java ได้รับกิจกรรมโดย

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

โปรดตรวจสอบให้แน่ใจว่าชั้นลูกค้าดำเนินการพัสดุ

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();
    }

Adhavan ฉันมีคำถาม เมื่อคุณสร้างคลาส Intent แรกคุณจะส่งผ่าน fromClass.th เป็นอาร์กิวเมนต์แรก มีวิธีดึงวัตถุนี้ในคลาสกิจกรรมที่รับหรือไม่
นิวแมน

1
ไม่ทราบ, fromClass fr = (fromClass) getParent (); นี่คือสิ่งที่คุณต้องการหรือไม่
โฆษณา

Adhava ฉันทำอย่างนี้จริง แต่ fr เป็นโมฆะ มีความคิดอะไรบ้าง
นิวแมน

ตอนนี้โปรดแบ่งปันข้อยกเว้นของคุณโดยที่เราสามารถตรวจสอบได้
โฆษณา

พัสดุมีจำนวนมากของรหัสจานหม้อไอน้ำที่ไม่จำเป็นและค่อนข้างตรงไปตรงเสียเวลา ค่อนข้างใช้รถบัส ดูโพสต์ของฉันด้านล่าง
Steven Mark Ford

89

จากประสบการณ์ของฉันมีวิธีแก้ปัญหาหลักสามข้อแต่ละข้อมีข้อเสียและข้อดี:

  1. การใช้พัสดุ

  2. การใช้งาน Serializable

  3. ใช้ไลบรารีบัสเหตุการณ์น้ำหนักเบาบางประเภท (ตัวอย่างเช่น EventBus ของ Greenrobot หรืออ็อตโตของ Square)

Parcelable - มาตรฐานที่รวดเร็วและ Android แต่มันมีรหัสสำเร็จรูปจำนวนมากและต้องใช้สตริงแบบเข้ารหัสเพื่อการอ้างอิงเมื่อดึงค่าออกเจตนา (ไม่ได้พิมพ์อย่างรุนแรง)

Serializable - ใกล้กับศูนย์ boilerplate แต่มันเป็นวิธีที่ช้าที่สุดและยังต้องใช้สตริงที่มีการกำหนดรหัสแบบยากเมื่อดึงค่าที่ต้องการออกมา (ไม่ได้พิมพ์อย่างรุนแรง)

รถบัสกิจกรรม - ศูนย์ boilerplate วิธีที่เร็วที่สุดและไม่จำเป็นต้องใช้สตริงที่มีการเข้ารหัส แต่จะต้องมีการพึ่งพาเพิ่มเติม (แม้ว่าโดยทั่วไปจะมีน้ำหนักเบา ~ 40 KB)

ฉันโพสต์การเปรียบเทียบรายละเอียดมากเกี่ยวกับวิธีการทั้งสามนี้รวมถึงการวัดประสิทธิภาพ


4
ลิงก์ไปที่บทความนั้นตายแล้ว ยังคงมีอยู่ใน webarchive: web.archive.org/web/20160917213123/http://…
OlivierH

เป็นเรื่องน่าละอายที่ลิงก์ไม่ทำงาน :(
Mauker

ปัญหาการใช้งาน Event Bus คือเมื่อกิจกรรมเป้าหมายถูกสร้างขึ้นใหม่เนื่องจากการหมุนตัวอย่างเช่น ในกรณีนี้เป้าหมายกิจกรรมไม่สามารถเข้าถึงวัตถุที่ส่งผ่านได้เนื่องจากวัตถุนี้ถูกใช้จากบัสโดยการโทรก่อนหน้านี้
JuliuszJ

1
Parcelable นั้นเร็วที่สุดและด้วยตัวสร้างนี้ ( parcelabler.com ) คุณสามารถวางคลาสของคุณและมันสามารถสร้างรหัสให้คุณได้ ง่าย
ByWaleed

1
@ByWaleed ... ฉันเห็นด้วยอย่างยิ่งฉันมักจะใช้เว็บไซต์นี้สร้างเนื้อหาโดยไม่ต้องยุ่งยากใด ๆ อย่างไรก็ตามฉันมีความพยายามที่ไม่สำเร็จจำนวนมากเมื่อฉันพยายามใช้ POJO ที่ประกอบด้วยวัตถุอื่น ด้วยเหตุผลบางอย่างออกวางไม่ทำงานจริงๆ
Yo Apps

42

ฉันพบวิธีการง่าย ๆ & หรูหรา:

  • ไม่มีพัสดุ
  • ไม่สามารถจัดลำดับได้
  • ไม่มีสนามไฟฟ้าสถิต
  • ไม่มี Event Bus

วิธีที่ 1

รหัสสำหรับกิจกรรมแรก:

    final Object objSent = new Object();
    final Bundle bundle = new Bundle();
    bundle.putBinder("object_value", new ObjectWrapperForBinder(objSent));
    startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));        
    Log.d(TAG, "original object=" + objSent);

รหัสสำหรับกิจกรรมที่สอง:

    final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData();
    Log.d(TAG, "received object=" + objReceived);

คุณจะพบobjSentและobjReceivedมีเหมือนกันhashCodeดังนั้นจึงเหมือนกัน

แต่ทำไมเราสามารถส่งผ่านวัตถุ java ด้วยวิธีนี้

ที่จริงแล้ว Android binder จะสร้างการอ้างอิง JNI ทั่วโลกสำหรับวัตถุ Java และปล่อยการอ้างอิง JNI ทั่วโลกนี้เมื่อไม่มีการอ้างอิงสำหรับวัตถุ Java นี้ binder จะบันทึกการอ้างอิง JNI ทั่วโลกในวัตถุ Binder

* ข้อควรระวัง: วิธีนี้ใช้ได้เฉพาะกับสองกิจกรรมที่ดำเนินการในกระบวนการเดียวกันมิฉะนั้นให้โยน ClassCastException ที่ (ObjectWrapperForBinder) getIntent (). getExtras (). getBinder ("object_value") *

การกำหนดคลาส ObjectWrapperForBinder

public class ObjectWrapperForBinder extends Binder {

    private final Object mData;

    public ObjectWrapperForBinder(Object data) {
        mData = data;
    }

    public Object getData() {
        return mData;
    }
}

วิธีที่ 2

  • สำหรับผู้ส่ง
    1. ใช้วิธีเนทีฟแบบกำหนดเองเพื่อเพิ่มออบเจ็กต์ java ของคุณไปยังตารางอ้างอิงทั่วโลกของ JNI (ผ่าน JNIEnv :: NewGlobalRef)
    2. ใส่จำนวนเต็มคืน (ที่จริงแล้ว JNIEnv :: NewGlobalRef return jobject ซึ่งเป็นตัวชี้เราสามารถส่งมันไปยัง int อย่างปลอดภัย) เพื่อ Intent ของคุณ (ผ่าน Intent :: putExtra)
  • สำหรับผู้รับ
    1. รับจำนวนเต็มจาก Intent (ผ่าน Intent :: getInt)
    2. ใช้วิธีเนทีฟแบบกำหนดเองเพื่อกู้คืนอ็อบเจ็กต์ java ของคุณจากตารางอ้างอิงโกลบอล JNI (ผ่าน JNIEnv :: NewLocalRef)
    3. ลบรายการออกจากตารางอ้างอิงทั่วโลกของ JNI (ผ่าน JNIEnv :: DeleteGlobalRef)

แต่วิธีที่ 2 มีปัญหาเล็กน้อย แต่ร้ายแรงหากผู้รับไม่สามารถกู้คืนออบเจ็กต์ java (ตัวอย่างเช่นมีข้อยกเว้นเกิดขึ้นก่อนที่จะกู้คืนออบเจ็กต์จาวาหรือกิจกรรมที่ผู้รับไม่มีอยู่เลย) จากนั้นวัตถุจาวาจะกลายเป็น เด็กกำพร้าหรือหน่วยความจำรั่ววิธีที่ 1 ไม่มีปัญหานี้เนื่องจาก Android binder จะจัดการข้อยกเว้นนี้

วิธีที่ 3

ในการเรียกใช้อ็อบเจกต์ java จากระยะไกลเราจะสร้าง data contract / interface เพื่ออธิบายอ็อบเจกต์ java เราจะใช้ไฟล์ aidl

IDataContract.aidl

package com.example.objectwrapper;
interface IDataContract {
    int func1(String arg1);
    int func2(String arg1);
}

รหัสสำหรับกิจกรรมแรก

    final IDataContract objSent = new IDataContract.Stub() {

        @Override
        public int func2(String arg1) throws RemoteException {
            // TODO Auto-generated method stub
            Log.d(TAG, "func2:: arg1=" + arg1);
            return 102;
        }

        @Override
        public int func1(String arg1) throws RemoteException {
            // TODO Auto-generated method stub
            Log.d(TAG, "func1:: arg1=" + arg1);
            return 101;
        }
    };
    final Bundle bundle = new Bundle();
    bundle.putBinder("object_value", objSent.asBinder());
    startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));
    Log.d(TAG, "original object=" + objSent);

รหัสสำหรับกิจกรรมที่สอง:

เปลี่ยน android: attribute attribute ใน AndroidManifest.xml เป็นชื่อกระบวนการที่ไม่ว่างเปล่าเพื่อให้แน่ใจว่ากิจกรรมที่สองทำงานในกระบวนการอื่น

    final IDataContract objReceived = IDataContract.Stub.asInterface(getIntent().getExtras().getBinder("object_value"));
    try {
        Log.d(TAG, "received object=" + objReceived + ", func1()=" + objReceived.func1("test1") + ", func2()=" + objReceived.func2("test2"));
    } catch (RemoteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

ด้วยวิธีนี้เราสามารถผ่านส่วนต่อประสานระหว่างสองกิจกรรมแม้ว่าพวกเขาจะทำงานในกระบวนการที่แตกต่างกันและเรียกวิธีการอินเทอร์เฟซจากระยะไกล

วิธีที่ 4

วิธีที่ 3 ดูไม่ง่ายพอเพราะเราต้องใช้อินเตอร์เฟสช่วยเหลือ หากคุณต้องการทำงานง่ายๆและวิธีการคืนค่าเป็นสิ่งที่ไม่จำเป็นเราสามารถใช้ android.os.Messenger

รหัสสำหรับกิจกรรมแรก (ผู้ส่ง):

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";

    public static final int MSG_OP1 = 1;
    public static final int MSG_OP2 = 2;

    public static final String EXTRA_MESSENGER = "messenger";

    private final Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            Log.e(TAG, "handleMessage:: msg=" + msg);
            switch (msg.what) {
            case MSG_OP1:

                break;
            case MSG_OP2:
                break;

            default:

                break;
            }
            super.handleMessage(msg);
        }

    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startActivity(new Intent(this, SecondActivity.class).putExtra(EXTRA_MESSENGER, new Messenger(mHandler)));
    }
}

รหัสสำหรับกิจกรรมที่สอง (ผู้รับ):

public class SecondActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        final Messenger messenger = getIntent().getParcelableExtra(MainActivity.EXTRA_MESSENGER);
        try {
            messenger.send(Message.obtain(null, MainActivity.MSG_OP1, 101, 1001, "10001"));
            messenger.send(Message.obtain(null, MainActivity.MSG_OP2, 102, 1002, "10002"));
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

Messenger.send ทั้งหมดจะดำเนินการในตัวจัดการแบบอะซิงโครนัสและตามลำดับ

ที่จริงแล้ว android.os.Messenger ยังเป็นส่วนต่อประสานช่วยเหลือหากคุณมีซอร์สโค้ด android คุณสามารถค้นหาไฟล์ชื่อ IMessenger.aidl

package android.os;

import android.os.Message;

/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}

ขออภัยฉันไม่เห็นว่าคุณมีผลผูกพันกับคำตอบของคุณเช่นกันฉันรู้สึกว่าคำตอบของคุณนั้นสง่างามมากเช่นกัน
SkidRunner

ว้าว .... วิธีที่ 1 ของชายคนนี้ใหญ่มาก ..... เมื่อคุณมีวัตถุขนาดใหญ่ / ขนาดใหญ่มากที่ทำงานได้ดี
:

ฉันใช้วิธีการหนึ่งดังนั้นคุณประหยัดเวลาของฉัน ขอบคุณ;
ShweLiam

ขอบคุณมากสำหรับวิธี ObjectWrapperForBinder ช่วยได้จริงๆ!
Vladimir Tolstikov

40

คุณสามารถเขียนข้อมูลของวัตถุลงใน Strings และ ints ชั่วคราวและส่งต่อไปยังกิจกรรม แน่นอนว่าคุณจะได้รับข้อมูลที่ส่งผ่าน แต่ไม่ใช่วัตถุ

แต่ถ้าคุณต้องการแสดงมันและไม่ใช้วัตถุในวิธีอื่นหรืออะไรทำนองนั้นมันก็น่าจะเพียงพอแล้ว ฉันทำแบบเดียวกับที่แสดงข้อมูลจากวัตถุหนึ่งในกิจกรรมอื่น

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);

คุณสามารถส่งต่อพวกเขาโดยตรงแทนที่จะเป็นไอวอรี่เทมเปิล แต่วิธีนี้มันชัดเจนกว่าในความคิดของฉัน นอกจากนี้คุณสามารถตั้งค่า temars ivars เป็น null เพื่อให้ GarbageCollector ทำความสะอาดได้เร็วขึ้น

โชคดี!

ในหมายเหตุด้าน: แทนที่ toString () แทนที่จะเขียนวิธีการพิมพ์ของคุณเอง

ดังที่ได้กล่าวไว้ในความคิดเห็นด้านล่างนี่คือวิธีที่คุณได้รับข้อมูลของคุณกลับมาในกิจกรรมอื่น:

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

9
รับข้อมูลของคุณกลับมาอีกครั้งด้วย: String fName = getIntent (). getExtras (). getInt ("fname");
Alister

2
ในการรับข้อมูลกลับมา: Bundle extras = getIntent().getExtras(); String val = extras.getString("fname");
Eric Leschinski

1
สิ่งนี้จะกลายเป็นไปไม่ได้อย่างรวดเร็วสำหรับ POJO ขนาดใหญ่ ค่อนข้างใช้รถบัส ดูโพสต์ของฉันด้านล่าง
Steven Mark Ford

ดังที่ฉันได้กล่าวไว้ในคำตอบของฉันนี่คือการดำเนินการแบบง่าย ๆ ที่คุณไม่ต้องการวัตถุ แต่เป็นเพียงค่าบางอย่าง มันไม่ได้หมายความว่าจะเป็น soslution สำหรับ usecases ที่ซับซ้อน
MJB

1
ความคิดที่ดีที่จะผ่านวัตถุชิ้นเดียว แต่ฉันพยายามที่จะส่งผ่านขนาดที่ไม่รู้จักของวัตถุของฉัน บางทีวิธีการแก้ปัญหาของคุณไม่ได้สำหรับการส่งผ่านอาร์เรย์วัตถุ
มูฮัมหมัด Saqib

25

ฉันสร้างคลาสตัวช่วยเดี่ยวที่เก็บวัตถุชั่วคราว

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");

โปรดทราบว่าเมื่อโหลดแล้ววัตถุจะถูกลบออกเพื่อหลีกเลี่ยงการอ้างอิงที่ไม่จำเป็น


1
ความคิดที่ดี! นอกจากนี้อาจเป็นคุณสามารถสร้างคลาสเพิ่มเติม ObjectContainer {Object, obj; บูลีนถาวร .... } ความคิดคือคุณสามารถส่งบูลีนในวิธีการเพิ่มหากคุณต้องการให้วัตถุคงอยู่และไม่ลบเมื่อเราเรียกใช้ มันจะช่วยรักษาวัตถุระดับโลกเอาไว้ Like อาจเป็นการเชื่อมต่อบลูทู ธ ที่เปิดอยู่เป็นต้น
Umair

1
น่ารัก แต่อย่าคิดค้นล้อใหม่ รูปแบบบัสมีความสง่างามและทรงพลัง ดูโพสต์ของฉันด้านล่าง
Steven Mark Ford

@StevenMarkFord รูปแบบรถบัสยังคงเป็นจริงจนถึงทุกวันนี้หรือไม่? ฉันพยายามที่จะปรับปรุง codebase ด้วยรหัสเช่นนี้การเข้าถึงข้อมูลระหว่างกิจกรรม: BookActivity.getInstance().recommendationResponseในRoomsActivity
Woppi

เมื่อกิจกรรมที่ได้รับถูกสร้าง (เช่นในการหมุนหน้าจอ) จะกลายเป็นobj nullเพื่อหลีกเลี่ยงปัญหานี้objควรเก็บไว้ที่อื่นเพื่อรับมันอีกครั้ง อันที่จริงโซลูชัน Json เก็บข้อมูลวัตถุไว้ในเจตนา
ซัลวาดอ

25

มีสองวิธีที่คุณสามารถเข้าถึงตัวแปรหรือวัตถุในคลาสหรือกิจกรรมอื่น ๆ

A. ฐานข้อมูล

B. ค่ากำหนดที่แชร์

C. การทำให้เป็นอันดับวัตถุ

D. คลาสที่สามารถเก็บข้อมูลทั่วไปสามารถตั้งชื่อเป็น Common Utilities ได้ มันขึ้นอยู่กับคุณ.

E. การส่งข้อมูลผ่าน Intents และ Parcelable Interface

ขึ้นอยู่กับความต้องการของโครงการของคุณ

A. ฐานข้อมูล

SQLiteเป็นฐานข้อมูลโอเพนซอร์ซที่ฝังอยู่ใน Android SQLite รองรับคุณสมบัติฐานข้อมูลเชิงสัมพันธ์มาตรฐานเช่นไวยากรณ์ SQL ธุรกรรมและข้อความสั่งที่เตรียมไว้

สอน

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. การทำให้เป็นอันดับวัตถุ

การรวมวัตถุนั้นใช้หากเราต้องการบันทึกสถานะวัตถุเพื่อส่งผ่านเครือข่ายหรือคุณสามารถใช้เพื่อวัตถุประสงค์ของคุณได้เช่นกัน

ใช้ Java beans และเก็บไว้เป็นหนึ่งในฟิลด์ของเขาและใช้ getters และ 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);

จากนั้นใช้วัตถุ serialzation เพื่อทำให้เป็นอันดับวัตถุนี้และในชั้นอื่น ๆ ของคุณ deserialize วัตถุนี้

ในการทำให้เป็นอันดับวัตถุสามารถแสดงเป็นลำดับของไบต์ที่มีข้อมูลของวัตถุรวมทั้งข้อมูลเกี่ยวกับประเภทของวัตถุและประเภทของข้อมูลที่เก็บไว้ในวัตถุ

หลังจากที่วัตถุที่เป็นอนุกรมได้รับการเขียนลงในไฟล์ก็สามารถอ่านได้จากไฟล์และ deserialized นั่นคือข้อมูลประเภทและไบต์ที่เป็นตัวแทนของวัตถุและข้อมูลที่สามารถใช้ในการสร้างวัตถุในหน่วยความจำ

หากคุณต้องการกวดวิชาสำหรับสิ่งนี้อ้างถึง:

D. CommonUtilities

คุณสามารถสร้างคลาสได้ด้วยตัวเองซึ่งสามารถมีข้อมูลทั่วไปที่คุณต้องการบ่อยในโครงการของคุณ

ตัวอย่าง

public class CommonUtilities {

    public static String className = "CommonUtilities";

}

E. การส่งผ่านข้อมูลผ่านความตั้งใจ

โปรดอ้างอิงบทช่วยสอนAndroid - ข้อมูลพัสดุเพื่อส่งผ่านระหว่างกิจกรรมโดยใช้คลาส Parcelableสำหรับตัวเลือกการส่งผ่านข้อมูลนี้


22

สร้างคลาสของคุณเองCustomerดังต่อไปนี้:

import import java.io.Serializable;
public class Customer implements Serializable
{
    private String name;
    private String city;

    public Customer()
    {

    }
    public Customer(String name, String city)
    {
        this.name= name;
        this.city=city;
    }
    public String getName() 
    {
        return name;
    }
    public void setName(String name) 
    {
        this.name = name;
    }
    public String getCity() 
    {
        return city;
    }
    public void setCity(String city) 
    {
        this.city= city;
    }

}

ในonCreate()วิธีการของคุณ

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_top);

    Customer cust=new Customer();
    cust.setName("abc");
    cust.setCity("xyz");

    Intent intent=new Intent(abc.this,xyz.class);
    intent.putExtra("bundle",cust);
    startActivity(intent); 
}

ในxyz activityชั้นเรียนคุณต้องใช้รหัสต่อไปนี้:

Intent intent=getIntent();
Customer cust=(Customer)intent.getSerializableExtra("bundle");
textViewName.setText(cust.getName());
textViewCity.setText(cust.getCity());

.. ตรวจสอบรหัสของคุณว่าคุณกำลังผ่าน "บันเดิล" เป็นกุญแจสำหรับใส่ obj และรับจาก "คลาส" .. กรุณาใช้คีย์เดียวอย่างใดอย่างหนึ่ง "คลาส" หรือ "มัด" ..
AK Joshi

ฉันเผชิญกับข้อผิดพลาด: พบพัสดุที่ IOException เขียนวัตถุที่สามารถทำให้เป็นอนุกรมได้
Arul Mani

15

วิธีที่ดีที่สุดคือการมีคลาส (เรียกว่าการควบคุม) ในแอปพลิเคชันของคุณซึ่งจะเก็บตัวแปรคงที่ประเภท 'ลูกค้า' (ในกรณีของคุณ) เริ่มต้นตัวแปรในกิจกรรม A ของคุณ

ตัวอย่างเช่น:

Control.Customer = CustomerClass;

จากนั้นไปที่กิจกรรม B และดึงข้อมูลจากคลาสควบคุม อย่าลืมกำหนดค่าว่างหลังจากใช้ตัวแปรมิฉะนั้นหน่วยความจำจะสูญเปล่า


4
@aez เพราะมันเลอะเทอะจากมุมมองการออกแบบและจะทำลายอย่างน่ากลัวหากเจตนาอยู่ในกระบวนการอื่น

7
คุณจะพบปัญหาเมื่อดำเนินการแอปต่อไปที่กิจกรรม B. เนื่องจาก Android สามารถฆ่ากิจกรรมและวัตถุจะไม่ถูกบันทึก
Ryan R

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

ตอนนี้คุณต้องการส่งผ่านวัตถุของคลาสนี้ใน startActivity ใช้สิ่งนี้:

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

Serializableนี้ทำงานที่นี่เพราะการดำเนินการ MyClass


คุณช่วยอธิบายหรืออธิบายเพิ่มเติมได้
ไหม

HomeworkData homeworkData = homeWorksList.get (ตำแหน่ง); เจตนาเจตนา = เจตนาใหม่ (c, HomeWorkActivitydetail.class); Bundle b = ใหม่ Bundle (); b.putSerializable ("CompleteData", homeworkData); intent.putExtras (ข); c.startActivity (เจตนา); ในช่วงเวลาของวัตถุเพิ่มให้ฉันผิดบางอย่างสำหรับการเพิ่มองค์ประกอบวัตถุเราไม่สามารถผ่านวัตถุที่สมบูรณ์แบบด้วยนี้
Amitsharma

ด้านในของการบ้านข้อมูลที่ฉันมีค่าบางอย่างเหล่านี้จะมาเพิ่ม
Amitsharma

12

หากคุณเลือกใช้วิธีที่ Samuh อธิบายให้จำไว้ว่าสามารถส่งค่าดั้งเดิมได้เท่านั้น นั่นคือค่าที่ parcable ดังนั้นหากวัตถุของคุณมีวัตถุที่ซับซ้อนสิ่งเหล่านี้จะไม่ติดตาม ตัวอย่างเช่นตัวแปรเช่นบิตแมป HashMap ฯลฯ ... สิ่งเหล่านี้เป็นเรื่องยากที่จะผ่านเจตนา

โดยทั่วไปผมจะแนะนำให้คุณส่งประเภทข้อมูลเท่านั้นดั้งเดิมเป็นของแถมเช่น String, int, บูล ฯลฯ ในกรณีของคุณมันจะเป็น: String fname, String lname, และint ageString address

ความคิดเห็นของฉัน: วัตถุที่ซับซ้อนมากขึ้นจะถูกใช้ร่วมกันได้ดีขึ้นโดยการใช้ContentProvider , SDCardฯลฯ นอกจากนี้ยังเป็นไปได้ที่จะใช้ตัวแปรแบบคงที่แต่สิ่งนี้อาจนำไปสู่รหัสผิดพลาดได้อย่างรวดเร็ว ...

แต่อีกครั้งมันเป็นเพียงความเห็นส่วนตัวของฉัน


8

ฉันใช้พัสดุเพื่อส่งข้อมูลจากกิจกรรมหนึ่งไปยังอีกกิจกรรมหนึ่ง นี่คือรหัสของฉันที่ทำงานได้ดีในโครงการของฉัน

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});
    }
}

ในกิจกรรม A ใช้อย่างนี้:

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");

7

คุณสามารถลองใช้คลาสนั้นได้ ข้อ จำกัด คือไม่สามารถใช้ภายนอกกระบวนการเดียว

กิจกรรมเดียว:

 final Object obj1 = new Object();
 final Intent in = new Intent();
 in.putExtra(EXTRA_TEST, new Sharable(obj1));

กิจกรรมอื่น ๆ :

final Sharable s = in.getExtras().getParcelable(EXTRA_TEST);
final Object obj2 = s.obj();

public final class Sharable implements Parcelable {

    private Object mObject;

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


        @Override
        public Sharable[] newArray(int size) {
            return new Sharable[size];
        }
    };

    public Sharable(final Object obj) {
        mObject = obj;
    }

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

    Object obj() {
        return mObject;
    }


    @Override
    public int describeContents() {
        return 0;
    }


    @Override
    public void writeToParcel(final Parcel out, int flags) {
        final long val = SystemClock.elapsedRealtime();
        out.writeLong(val);
        put(val, mObject);
    }

    private void readFromParcel(final Parcel in ) {
        final long val = in .readLong();
        mObject = get(val);
    }

    /////

    private static final HashMap < Long, Object > sSharableMap = new HashMap < Long, Object > (3);

    synchronized private static void put(long key, final Object obj) {
        sSharableMap.put(key, obj);
    }

    synchronized private static Object get(long key) {
        return sSharableMap.remove(key);
    }
}

6

เริ่มกิจกรรมอื่นจากกิจกรรมนี้และส่งพารามิเตอร์ผ่านทาง Bundle Object

Intent intent = new Intent(getBaseContext(), YourActivity.class);
intent.putExtra("USER_NAME", "xyz@gmail.com");
startActivity(intent);

ดึงข้อมูลในกิจกรรมอื่น (YourActivity)

String s = getIntent().getStringExtra("USER_NAME");

มันก็โอเคสำหรับประเภทข้อมูลที่เรียบง่าย แต่ถ้าคุณต้องการส่งผ่านข้อมูลที่ซับซ้อนในระหว่างกิจกรรม คุณต้องทำให้มันเป็นอันดับแรก

ที่นี่เรามีรูปแบบพนักงาน

class Employee{
    private String empId;
    private int age;
    print Double salary;

    getters...
    setters...
}

คุณสามารถใช้ Gson lib ที่จัดทำโดย google เพื่อจัดทำข้อมูลที่ซับซ้อนเช่นนี้

String strEmp = new Gson().toJson(emp);
Intent intent = new Intent(getBaseContext(), YourActivity.class);
intent.putExtra("EMP", strEmp);
startActivity(intent);

Bundle bundle = getIntent().getExtras();
String empStr = bundle.getString("EMP");
            Gson gson = new Gson();
            Type type = new TypeToken<Employee>() {
            }.getType();
            Employee selectedEmp = gson.fromJson(empStr, type);

TypeToken <> เลิกใช้แล้ว ทางเลือกคืออะไร?
Ragavendra M

6

คำถามนี้ถูกกล่าวถึงในคำถาม Stack Overflow อื่น โปรดดูที่วิธีการแก้ปัญหาในการส่งผ่านข้อมูลผ่านเจตนาใช้ Serializable จุดหลักคือเกี่ยวกับการใช้วัตถุที่เก็บภายในข้อมูลที่จำเป็นBundleIntent

 Bundle bundle = new Bundle();

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

 intent.putExtras(bundle);

ในการแยกค่า:

 Bundle bundle = new Bundle();

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

ข้อดีของSerializableมันคือความเรียบง่าย อย่างไรก็ตามคุณควรพิจารณาใช้Parcelableวิธีการถ้าคุณต้องการข้อมูลจำนวนมากจะถูกโอนย้ายเพราะParcelableถูกออกแบบมาเฉพาะสำหรับ Android Serializableและมันจะมีประสิทธิภาพมากกว่า คุณสามารถสร้างParcelableคลาสโดยใช้:

  1. เครื่องมือออนไลน์ - parcelabler
  2. ปลั๊กอินสำหรับ Android Studio - เครื่องกำเนิดรหัส Android ที่ทำแผนที่ได้

5

สร้างคลาสเช่น bean class และใช้Serializableอินเตอร์เฟส จากนั้นเราสามารถส่งผ่านintentวิธีการตัวอย่างเช่น:

intent.putExtra("class", BeanClass);

จากนั้นรับจากกิจกรรมอื่นตัวอย่างเช่น:

BeanClass cb = intent.getSerializableExtra("class");

5

สร้างสองวิธีในคลาสที่คุณกำหนดเองเช่นนี้

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();
        } 
    }
}

ตอนนี้ในกิจกรรมผู้ส่งของคุณทำเช่นนี้

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

และในกิจกรรมรับสัญญาณของคุณ

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

3

ใช่การใช้วัตถุคงเป็นวิธีที่ง่ายที่สุดในการทำเช่นนี้กับวัตถุที่ไม่สามารถกำหนดเองได้


ใช่ฉันคิดว่าฉันเห็นด้วยกับคุณ การทำให้วัตถุเหล่านั้นstaticเป็นวิธีแก้ปัญหาที่ดีกว่าถ้ามันเป็นไปไม่ได้เลยที่จะเรียกใช้putExtra()สำหรับทุก ๆ ทรัพย์สินที่คุณต้องการส่งต่อ ตัวอย่างเช่นตอนนี้ฉันต้องการผ่านArrayListวัตถุที่มี ฉันอาจทำ ArrayList ของฉันstaticแทน
Matthew Quiros

3

วัตถุกิจกรรม Android สามารถทำลายและสร้างใหม่ได้ ดังนั้นคุณจะต้องใช้วิธีอื่นในการมองพวกเขา - หรือวัตถุใด ๆ ที่พวกเขาสร้าง !!! - ขึ้น นั่นคือคุณสามารถส่งผ่านการอ้างอิงคลาสแบบคงที่ แต่จากนั้นการจัดการวัตถุ (Java เรียก "การอ้างอิง" เหล่านี้เช่นเดียวกับ SmallTalk แต่พวกเขาไม่ได้อ้างอิงในแง่ของ C หรือแอสเซมบลี) จะไม่ถูกต้องในภายหลังเนื่องจาก "คุณสมบัติ" ของ Android OE เป็นกิจกรรมใด ๆ ที่สามารถทำลายและสร้างขึ้นใหม่ในภายหลัง

คำถามเดิมถามว่า "วิธีส่งผ่านวัตถุจากกิจกรรมหนึ่งไปอีกกิจกรรมหนึ่งใน Android" และไม่มีใครตอบว่า แน่นอนคุณสามารถทำให้เป็นอนุกรม (Serializable, Parcelable, ถึง / จาก JSON) และส่งสำเนาของข้อมูลของวัตถุและวัตถุใหม่ที่มีข้อมูลเดียวกันสามารถสร้าง; แต่มันจะไม่ได้มีการอ้างอิง / จับเดียวกัน นอกจากนี้ยังมีอีกหลายคนที่กล่าวถึงคุณสามารถจัดเก็บข้อมูลอ้างอิงในที่จัดเก็บแบบคงที่ และจะใช้งานได้ยกเว้นว่า Android จะตัดสินใจที่จะทำลายกิจกรรมของคุณ

ดังนั้นเพื่อแก้คำถามเดิมคุณจะต้องมีการค้นหาแบบสแตติกรวมถึงแต่ละวัตถุจะอัปเดตการอ้างอิงเมื่อ / ถ้ามันถูกสร้างขึ้นใหม่ เช่นกิจกรรม Android แต่ละรายการจะ relist ตัวเองถ้า onCreate ถูกเรียก คุณยังสามารถดูว่าบางคนใช้รายการงานเพื่อค้นหากิจกรรมตามชื่อ (ระบบกำลังทำลายอินสแตนซ์ของกิจกรรมนี้ชั่วคราวเพื่อประหยัดพื้นที่ .. getRunningTasks รายการงานเป็นรายการพิเศษของอินสแตนซ์วัตถุล่าสุดของแต่ละกิจกรรม)

สำหรับการอ้างอิง:

หยุด: "กิจกรรมถูกบดบังอย่างสมบูรณ์โดยกิจกรรมอื่น (กิจกรรมอยู่ใน" แบ็คกราวน์ ") กิจกรรมที่หยุดยังมีชีวิตอยู่ ( วัตถุกิจกรรมจะถูกเก็บไว้ในหน่วยความจำมันเก็บข้อมูลสถานะและสมาชิกทั้งหมด แต่ไม่ใช่ ติดกับตัวจัดการหน้าต่าง) อย่างไรก็ตามผู้ใช้จะไม่สามารถมองเห็นได้อีกต่อไปและสามารถถูกฆ่าโดยระบบเมื่อจำเป็นต้องใช้หน่วยความจำที่อื่น "

onDestroy "ระบบกำลังทำลายอินสแตนซ์ของกิจกรรมนี้ชั่วคราวเพื่อประหยัดพื้นที่"

ดังนั้น Message Bus จึงเป็นโซลูชันที่ใช้การได้ มันเป็น "เรือท้องแบน" แทนที่จะพยายามอ้างอิงถึงวัตถุ จากนั้นคุณออกแบบสถาปัตยกรรมของคุณใหม่เพื่อใช้ MessagePassing แทน SequentialCode การดีบักยากขึ้นแบบทวีคูณ แต่มันจะช่วยให้คุณเพิกเฉยต่อการทำความเข้าใจ OperatingEnvironment อย่างมีประสิทธิภาพการเข้าถึงวิธีการของแต่ละวัตถุจะถูกคว่ำเพื่อให้ผู้โทรโพสต์ข้อความและวัตถุนั้นกำหนดตัวจัดการสำหรับข้อความนั้น รหัสมากขึ้น แต่สามารถทำให้แข็งแกร่งด้วยข้อ จำกัด Android OE

หากสิ่งที่คุณต้องการคือกิจกรรมอันดับต้น ๆ (สิ่งทั่วไปในแอพ Android เนื่องจากจำเป็นต้องใช้ "บริบท" ทุกที่) จากนั้นคุณสามารถให้แต่ละกิจกรรมแสดงรายการเป็น "ยอดนิยม" ในพื้นที่ส่วนกลางคงที่เมื่อใดก็ตามที่เรียกว่า onResume จากนั้น AlertDialog ของคุณหรือสิ่งใดก็ตามที่ต้องการบริบทก็สามารถทำได้จากที่นั่น นอกจากนี้ยังเป็นเรื่องเล็กน้อยที่จะใช้ทั่วโลก แต่สามารถลดความซับซ้อนของการส่งบริบทได้ทุกที่และแน่นอนเมื่อคุณใช้ MessageBus ก็จะเป็นไปได้


อ็อตโตมีความสามารถในการใช้งานภายนอกได้ในแอพ Java ธรรมดา ดังนั้นเหมาะสำหรับการพัฒนาและทดสอบโดยไม่ต้องยุ่งกับ Android อ็อตโตมีความโค้งการเรียนรู้ที่ยิ่งใหญ่และสิ่งที่แก้ได้ส่วนใหญ่แก้ไขแล้วในวิธี Android (ออกอากาศในท้องถิ่น ฯลฯ ) หรือในวิธีการพัฒนาแอพปกติ (คุณสามารถเขียนการค้นหาทั่วโลกที่ง่ายกว่าการค้นหาทั่วโลกของอ็อตโต เข้าถึงได้ง่ายขึ้นสำหรับ vectoring / F3 ผ่านโค้ดและสำหรับการก้าวผ่านการดีบั๊ก)
TimJowers2

2
  1. ฉันรู้ว่าคงไม่ดี แต่ดูเหมือนว่าเราถูกบังคับให้ใช้ที่นี่ ปัญหาของ parceables / seriazables คือทั้งสองกิจกรรมมีอินสแตนซ์ที่ซ้ำกันของ object เดียวกัน = เสียหน่วยความจำและ CPU

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

กิจกรรมการโทร

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

กิจกรรมที่เรียกว่า (โปรดทราบว่าonCreate ()และonResume ()อาจถูกเรียกหลายครั้งเมื่อระบบทำลายและสร้างกิจกรรมใหม่)

if (IntentMailBox.content.size()>0)
    level = (Level) IntentMailBox.content.poll();
else
    // Here you reload what you have saved in onPause()
  1. อีกวิธีคือการประกาศฟิลด์คงที่ของคลาสที่คุณต้องการส่งผ่านในคลาสนั้น มันจะให้บริการเฉพาะเพื่อจุดประสงค์นี้ อย่าลืมว่ามันอาจจะเป็นโมฆะใน onCreate เนื่องจากแพคเกจแอปของคุณถูกยกเลิกการโหลดจากหน่วยความจำโดยระบบและโหลดใหม่ในภายหลัง

  2. โปรดทราบว่าคุณยังคงต้องจัดการวงจรชีวิตของกิจกรรมคุณอาจต้องการเขียนข้อมูลทั้งหมดไปยังการตั้งค่าที่ใช้ร่วมกันเจ็บปวดกับโครงสร้างข้อมูลที่ซับซ้อนเหมือนเดิม


1

คำตอบข้างต้นเกือบทั้งหมดถูกต้อง แต่สำหรับผู้ที่ไม่ได้ยกเลิกคำตอบเหล่านั้น Android มีความตั้งใจระดับที่มีประสิทธิภาพด้วยความช่วยเหลือของคุณแบ่งปันข้อมูลระหว่างกิจกรรมไม่เพียง แต่ส่วนประกอบอื่น ๆ ของ Android (รับสัญญาณ Broadcasr servises สำหรับเนื้อหา ) ในกิจกรรมของคุณคุณสร้างความตั้งใจ

Intent intent = new Intent(context,SomeActivity.class);
intent.putExtra("key",value);
startActivity(intent);

ในกิจกรรมการรับของคุณคุณมี

public class SomeActivity extends AppCompactActivity {

    public void onCreate(...){
    ...
          SomeObject someObject = getIntent().getExtras().getParceable("key");
    }

}

คุณต้องใช้อินเตอร์เฟส Parceable หรือ Serializable บนวัตถุของคุณเพื่อแบ่งปันระหว่างกิจกรรม เป็นการยากที่จะติดตั้งParcealbe แทนที่จะเป็น Serializableบนวัตถุซึ่งเป็นสาเหตุให้ android มีปลั๊กอินสำหรับการนี้โดยเฉพาะดาวน์โหลดและใช้งาน


0

ฉันสงสัยมาตลอดว่าทำไมเรื่องนี้ไม่ง่ายเหมือนการเรียกวิธีการของกิจกรรมอื่น ฉันเพิ่งเขียนไลบรารียูทิลิตี้ที่ทำให้มันเกือบจะง่ายเหมือนที่ คุณสามารถตรวจสอบได้ที่นี่ ( https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher )

GNLauncherทำให้การส่งวัตถุ / ข้อมูลไปยังกิจกรรมจากกิจกรรมอื่น ๆ เป็นเรื่องง่ายเหมือนกับการเรียกใช้ฟังก์ชันใน tha Activity ด้วยข้อมูลที่ต้องการเป็นพารามิเตอร์ มันแนะนำประเภทความปลอดภัยและกำจัดความเร่งรีบทั้งหมดของการเป็นอันดับ, แนบกับเจตนาโดยใช้คีย์สตริงและการเลิกทำเหมือนกันที่ปลายอีกด้าน

การใช้

กำหนดอินเทอร์เฟซด้วยวิธีการที่คุณต้องการเรียกใช้บนกิจกรรมเพื่อเรียกใช้

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

ใช้อินเทอร์เฟซข้างต้นบนกิจกรรมเพื่อเรียกใช้ แจ้งให้ GNLauncher ทราบเมื่อกิจกรรมพร้อม

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);
    }
}

ในกิจกรรมอื่นรับพร็อกซีไปที่กิจกรรมด้านบนและเรียกใช้วิธีการใด ๆ พร้อมพารามิเตอร์ที่ต้องการ

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

กิจกรรมแรกจะเริ่มขึ้นและวิธีการที่เรียกใช้ด้วยพารามิเตอร์ที่ต้องการ

ข้อกำหนดเบื้องต้น

โปรดดูที่https://github.com/noxiouswinter/gnlib_android/wiki#prerequisitesสำหรับข้อมูลเกี่ยวกับวิธีเพิ่มการอ้างอิง


0

ส่งผ่านวัตถุจากกิจกรรมหนึ่งไปยังกิจกรรมอื่น

(1) กิจกรรมที่มา

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

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

(2) ความเป็นปลายทางปลายทาง

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

0

ฉันเคยตั้งค่าวัตถุด้วย Pacelable หรือ Serializable เพื่อถ่ายโอน แต่เมื่อใดก็ตามที่ฉันเพิ่มตัวแปรอื่น ๆ ลงในวัตถุ (รุ่น) ฉันต้องลงทะเบียนทั้งหมด มันช่างน่ากลัวเหลือเกิน

มันง่ายสุด ๆ ในการถ่ายโอนวัตถุระหว่างกิจกรรมหรือชิ้นส่วน

Android DataCache


0

เราสามารถส่งผ่านวัตถุจากกิจกรรมหนึ่งไปยังกิจกรรมอื่น:

SupplierDetails poSuppliersDetails = new SupplierDetails();

ข้างในpoSuppliersDetailsเรามีค่าบางอย่าง ตอนนี้ฉันกำลังส่งวัตถุนี้ไปยังเป้าหมายกิจกรรม:

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

วิธีรับสิ่งนี้ใน ACtivityTwo:

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

0

ผ่านหนึ่งกิจกรรมไปยังกิจกรรมอื่น:

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

รับค่า:

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

-1

สวัสดีทุกคนเห็นตัวเลือกที่ดีมากมาย แต่ฉันสงสัยว่าทำไม Binding ไม่ถูกใช้?

การผ่านการอ้างอิงไปยังวัตถุดูเหมือนว่าจะมีประสิทธิภาพมากกว่าสำหรับฉันมากกว่าการทำให้เป็นอันดับและวัตถุที่ทำให้เสื่อมเสีย แต่ฉันยังไม่ได้ดำน้ำลึกเพื่อดูว่าเป็นสิ่งที่เกิดขึ้นเบื้องหลังหรือไม่

การสร้าง Binder นั้นง่ายพอ ...

public class MyBinder extends Binder {

    private Object myObject;

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

    public Object getObject() {
        return myObject;
    }

}

และการสร้างพัสดุที่จะใช้ไม่ใช่อีเธอร์ที่แย่

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];
        }

    };
}

ตรรกะนี้เจ๋งจริงๆเพราะคุณผ่านการอ้างอิงจากกิจกรรมหนึ่งไปอีกกิจกรรมหนึ่ง

ฉันจะแนะนำให้ตรวจสอบ nulls และถ้าอินสแตนซ์ของ Binder คือ MyBinder!

และเพื่อดำเนินการนี้คุณเพียงแค่ ...

ส่งออกไป

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

intent.putExtra("MyParcelable", myParcelable);

ไปเอามันกลับมา

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

Heck ใครบางคนอาจคลั่งไคล้และทำให้ผู้ดูดนี้เป็นคนสามัญอย่างแท้จริง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.