Programing

Android에서 한 활동에서 다른 활동으로 객체를 전달하는 방법

lottogame 2020. 9. 30. 08:39
반응형

Android에서 한 활동에서 다른 활동으로 객체를 전달하는 방법


고객 클래스 의 개체 를 하나 에서 보내고 다른 개체에 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.

어떻게 할 수 있습니까?


한 가지 옵션은 사용자 정의 클래스가 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() {}
    }
}

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

deneX 활동에서 호출 객체 를 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");

그게 다야.


  • 전역 정적 변수를 사용하는 것은 좋은 소프트웨어 엔지니어링 관행 이 아닙니다 .
  • 객체의 필드를 원시 데이터 유형 으로 변환하는 것은 바쁜 작업 일 수 있습니다 .
  • 직렬화 가능을 사용하는 것은 괜찮지 만 Android 플랫폼 에서는 성능 효율적이지 않습니다 .
  • Parcelable은 특별히 Android 용으로 설계되었으며 사용해야합니다. 다음은 간단한 예입니다. Android 활동간에 사용자 지정 개체 전달

사이트를 사용하여 클래스에 대한 Parcelable 코드를 생성 할 수 있습니다 .


활동을 호출하는 동안

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

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

들어 코 틀린 꽤 동일합니다

데이터 전달

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)

내 경험상 세 가지 주요 솔루션이 있으며 각각 단점과 장점이 있습니다.

  1. Parcelable 구현

  2. 직렬화 가능 구현

  3. 일종의 경량 이벤트 버스 라이브러리 사용 (예 : Greenrobot의 EventBus 또는 Square의 Otto)

Parcelable- 빠르고 Android 표준이지만 상용구 코드가 많고 인 텐트에서 값을 가져올 때 참조 용으로 하드 코딩 된 문자열이 필요합니다 (강력하지 않은 유형).

직렬화 가능 -상용구가 0에 가깝지만 가장 느린 접근 방식이며 인 텐트에서 값을 가져올 때 하드 코딩 된 문자열이 필요합니다 (강력하지 않은 형식).

이벤트 버스 -상용구가없고 가장 빠른 접근 방식이며 하드 코딩 된 문자열이 필요하지 않지만 추가 종속성이 필요합니다 (일반적으로 가볍지 만 ~ 40KB).

효율성 벤치 마크를 포함하여이 세 가지 접근 방식에 대한 매우 상세한 비교를 게시했습니다.


또한 개체의 데이터를 임시 문자열 및 정수에 쓰고 활동에 전달할 수도 있습니다. 물론 그렇게하면 데이터가 전송되지만 개체 자체는 전송되지 않습니다.

그러나 그것들을 표시하고 싶고 다른 방법이나 그와 비슷한 것에서 객체를 사용하지 않으려면 충분할 것입니다. 다른 활동에서 한 개체의 데이터를 표시하는 것과 같은 방식으로 수행했습니다.

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

임시 ivar 대신 직접 전달할 수도 있지만이 방법은 제 생각에 더 명확합니다. 또한 임시 ivar를 null로 설정하여 GarbageCollector에서 더 빨리 정리할 수 있습니다.

행운을 빕니다!

참고 : 자체 인쇄 메서드를 작성하는 대신 toString ()을 재정의하십시오.

아래 주석에서 언급했듯이 다른 활동에서 데이터를 다시 가져 오는 방법은 다음과 같습니다.

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

간단하고 우아한 방법을 찾았습니다.

  • 소포 불가
  • 직렬화 불가
  • 정적 필드 없음
  • 이벤트 버스 없음

방법 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것이므로 동일합니다.

그런데 왜 이런 식으로 자바 객체를 전달할 수 있습니까?

실제로 안드로이드 바인더는 자바 객체에 대한 전역 JNI 참조를 생성하고이 자바 객체에 대한 참조가 없을 때이 전역 JNI 참조를 해제합니다. 바인더는이 전역 JNI 참조를 Binder 개체에 저장합니다.

*주의 :이 메서드는 두 활동이 동일한 프로세스에서 실행되지 않는 한만 작동합니다. 그렇지 않으면 (ObjectWrapperForBinder) getIntent (). getExtras (). getBinder ( "object_value")에서 ClassCastException이 발생합니다. *

클래스 ObjectWrapperForBinder 정의

public class ObjectWrapperForBinder extends Binder {

    private final Object mData;

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

    public Object getData() {
        return mData;
    }
}

방법 2

  • 발신자에게는
    1. 사용자 지정 네이티브 메서드를 사용하여 JNI 전역 참조 테이블에 Java 개체를 추가합니다 (JNIEnv :: NewGlobalRef를 통해).
    2. 반환 정수 (실제로는 JNIEnv :: NewGlobalRef 반환 jobject, 포인터 인 포인터, 안전하게 int로 캐스팅 할 수 있음)를 Intent (Intent :: putExtra를 통해)에 넣습니다.
  • 수신기를 위해
    1. Intent에서 정수 가져 오기 (Intent :: getInt를 통해)
    2. 사용자 지정 네이티브 메서드를 사용하여 JNI 전역 참조 테이블에서 Java 개체를 복원합니다 (JNIEnv :: NewLocalRef를 통해).
    3. JNI 전역 참조 테이블에서 항목 제거 (JNIEnv :: DeleteGlobalRef를 통해),

그러나 방법 2에는 약간 심각한 문제가 있습니다. 수신자가 Java 개체를 복원하지 못하면 (예 : Java 개체를 복원하기 전에 일부 예외가 발생하거나 수신자 활동이 전혀 존재하지 않는 경우) Java 개체는 고아 또는 메모리 누수, 방법 1에는이 문제가 없습니다. Android 바인더가이 예외를 처리하기 때문입니다.

방법 3

Java 객체를 원격으로 호출하기 위해 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);

두 번째 활동에 대한 코드 :

AndroidManifest.xml의 android : process 속성을 비어 있지 않은 프로세스 이름으로 변경하여 두 번째 활동이 다른 프로세스에서 실행되도록합니다.

    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는 Handler에서 비동기 및 순차적으로 실행됩니다.

실제로 android.os.Messenger는 보조 인터페이스이기도합니다. Android 소스 코드가 있으면 IMessenger.aidl이라는 파일을 찾을 수 있습니다.

package android.os;

import android.os.Message;

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

임시 객체를 보유하는 싱글 톤 도우미 클래스를 만들었습니다.

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

일단로드되면 불필요한 참조를 피하기 위해 객체가 제거됩니다.


다른 클래스 또는 활동의 변수 또는 개체에 액세스 할 수있는 몇 가지 방법이 있습니다.

A. 데이터베이스

B. 공유 선호도.

C. 객체 직렬화.

D. 공통 데이터를 보유 할 수있는 클래스를 Common Utilities로 명명 할 수 있습니다. 이것은 너에게 달려있어.

E. 인 텐트 및 Parcelable 인터페이스를 통한 데이터 전달.

프로젝트 요구 사항에 따라 다릅니다.

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. 객체 직렬화

개체 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. CommonUtilities

프로젝트에서 자주 필요한 공통 데이터를 포함 할 수있는 클래스를 직접 만들 수 있습니다.

견본

public class CommonUtilities {

    public static String className = "CommonUtilities";

}

E. 인 텐트를 통한 데이터 전달

데이터 전달 옵션에 대해서는 Android – Parcel 데이터를 Parcelable 클래스사용하여 활동간에 전달할 튜토리얼을 참조하십시오 .


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

가장 좋은 방법은 애플리케이션에 '고객'유형의 정적 변수 (귀하의 경우)를 보유 할 클래스 (Control이라고 부름)를 갖는 것입니다. 활동 A에서 변수를 초기화하십시오.

예를 들면 :

Control.Customer = CustomerClass;

그런 다음 활동 B로 이동하여 Control 클래스에서 가져옵니다. 변수를 사용한 후 null을 할당하는 것을 잊지 마십시오. 그렇지 않으면 메모리가 낭비됩니다.


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

이제 startActivity에서이 클래스의 개체를 전달하려고합니다. 다음을 사용하십시오.

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

이것은 MyClass가 Serializable.


Samuh가 설명하는 방식을 사용하도록 선택하는 경우 원시 값만 전송할 수 있음을 기억하십시오. 즉, parcable 값입니다. 따라서 개체에 복잡한 개체가 포함되어 있으면 따르지 않습니다. 예를 들어, Bitmap, HashMap 등과 같은 변수는 인 텐트로 전달하기가 까다 롭습니다.

일반적으로 나는 사건이 될 것에서는 문자열, INT, 부울 등과 같이 엑스트라로만 원시 데이터 유형을 보내 조언을 것입니다 : String fname, String lname, int age,와 String address.

내 의견 : 더 복잡한 객체는 ContentProvider , SDCard을 구현하여 더 잘 공유됩니다 . 정적 변수 를 사용할 수도 있지만 오류가 발생하기 쉬운 코드로 빠르게 이어질 수 있습니다.

그러나 다시 말하지만 그것은 단지 나의 주관적인 의견입니다.


한 활동에서 다른 활동으로 데이터를 보내기 위해 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");

그 클래스를 사용해 볼 수 있습니다. 한계는 하나의 프로세스 외부에서 사용할 수 없다는 것입니다.

하나의 활동 :

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

이 활동에서 다른 활동을 시작하고 번들 개체를 통해 매개 변수를 전달합니다.

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...
}

Google에서 제공하는 Gson lib를 사용하여 다음과 같이 복잡한 데이터를 직렬화 할 수 있습니다.

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

이 질문은 다른 스택 오버플로 질문에서도 논의됩니다. Serializable을 사용하여 의도를 통해 데이터 전달대한 솔루션을 살펴보십시오 . 요점은 Bundle내부에 필요한 데이터를 저장하는 객체를 사용 하는 것 Intent입니다.

 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. Studio 용 플러그인 -Android Parcelable 코드 생성기

빈 클래스와 같은 클래스를 생성하고 Serializable인터페이스를 구현합니다 . 그런 다음 intent메서드를 통해 전달할 수 있습니다 . 예를 들면 다음과 같습니다.

intent.putExtra("class", BeanClass);

그런 다음 다른 활동에서 가져옵니다. 예를 들면 다음과 같습니다.

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

이와 같이 사용자 정의 클래스에 두 가지 메서드를 만듭니다.

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

예, 정적 개체를 사용하는 것이 사용자 지정 비 직렬화 할 수없는 개체를 사용하는 가장 쉬운 방법입니다.


Android 활동 객체는 파괴 및 재구성 될 수 있습니다. 따라서 다른 접근 방식을 사용하여 그들을 보거나 그들이 만드는 모든 개체 를 찾아야 합니다 !!! -위로. 즉, 정적 클래스 참조로 전달할 수 있지만 객체 핸들 (Java는 SmallTalk처럼 이러한 "참조"를 호출하지만 C 또는 어셈블리의 의미에서 참조가 아님)은 나중에 "기능"이 유효하지 않을 수 있습니다. Android OE의 모든 활동은 나중에 소멸되고 재구성 될 수 있습니다.

원래 질문은 "안드로이드에서 한 활동에서 다른 활동으로 객체를 전달하는 방법"이라는 질문에 아무도 대답하지 않았습니다. 확실히 직렬화 가능 (Serializable, Parcelable, JSON으로 /에서)하고 객체 데이터의 사본을 전달할 수 있으며 동일한 데이터를 가진 새 객체를 생성 할 수 있습니다. 그러나 동일한 참조 / 핸들을 가지지 않습니다. 또한 다른 많은 사람들이 참조를 정적 저장소에 저장할 수 있다고 언급했습니다. Android가 활동을 onDestroy로 결정하지 않는 한 작동합니다.

따라서 원래 질문을 실제로 해결하려면 정적 조회가 필요하며 각 객체는 다시 생성 될 때 참조를 업데이트합니다. 예를 들어 각 Android 활동은 onCreate가 호출되면 자체적으로 다시 나열됩니다. 일부 사람들이 작업 목록을 사용하여 이름으로 활동을 검색하는 방법을 볼 수도 있습니다. (시스템은 공간을 절약하기 위해 활동의이 인스턴스를 일시적으로 파괴하고 있습니다. getRunningTasks, 작업 목록은 효과적으로 각 활동의 가장 최근 개체 인스턴스의 전문 목록입니다).

참고로 :

중지됨 : "활동이 다른 활동에 의해 완전히 가려졌습니다 (활동이 이제"백그라운드 "에 있음). 중지 된 활동도 여전히 살아 있습니다 ( 활동 객체는 메모리 에 유지되고 모든 상태 및 구성원 정보를 유지하지만 그렇지 않습니다. 그러나, 더 이상 사용자에게 표시되지 않으며 다른 곳에서 메모리가 필요할 때 시스템에 의해 종료 될 수 있습니다. "

onDestroy "시스템이 공간을 절약하기 위해이 활동 인스턴스일시적으로 파괴 하고 있습니다."

따라서 메시지 버스는 실행 가능한 솔루션입니다. 기본적으로 "펀트"입니다. 객체에 대한 참조를 갖기보다는 그런 다음 SequentialCode 대신 MessagePassing을 사용하도록 디자인을 다시 설계합니다. 디버그하기가 기하 급수적으로 어렵습니다. 그러나 이러한 종류의 OperatingEnvironment 이해를 무시할 수 있습니다. 효과적으로 각 개체 메서드 액세스가 반전되어 호출자가 메시지를 게시하고 개체 자체가 해당 메시지에 대한 처리기를 정의합니다. 더 많은 코드가 있지만 Android OE 제한으로 강력하게 만들 수 있습니다.

원하는 것이 최상위 활동 ( '컨텍스트'가 모든 곳에서 필요하기 때문에 Android 앱에서 일반적으로 사용됨)이면 onResume이 호출 될 때마다 각 활동이 정적 전역 공간에서 '최상위'로 표시되도록 할 수 있습니다. 그런 다음 AlertDialog 또는 컨텍스트가 필요한 모든 것이 거기에서 가져올 수 있습니다. 또한 전역을 사용하기에는 약간 엉뚱하지만 모든 곳에서 Context를 위아래로 전달하는 것을 단순화 할 수 있으며 MessageBus를 사용할 때 IT는 어쨌든 전역입니다.


  1. 나는 정전기가 나쁘다는 것을 알고 있지만 여기서는 그것을 사용해야하는 것 같습니다. parceables / seriazables의 문제점은 두 활동이 동일한 객체의 중복 인스턴스를 가지고 있다는 것입니다 = 메모리 및 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에서 null이 될 수 있음을 잊지 마십시오.

  2. 여전히 활동 수명주기를 처리해야한다는 점을 염두에두고 모든 데이터를 공유 환경 설정에 직접 작성하고 복잡한 데이터 구조를있는 그대로 고통스럽게 할 수 있습니다.


위의 답변은 거의 모두 정확하지만 그 답변을 이해하지 못하는 사람들을 위해 Android에는 강력한 클래스 Intent 가 있습니다. 덕분에 활동뿐만 아니라 Android의 다른 구성 요소간에 데이터를 공유합니다 (broadcasr 수신기, 콘텐츠에 대한 서비스 제공을 제공하는 ContetnResolver 클래스 없음 Intent ). 활동에서 의도를 구축합니다.

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 인터페이스를 구현해야합니다. 객체에 Serializable 인터페이스가 아닌 Parcealbe 를 구현하기가 어렵 기 때문에 Android가 특히 이것을 위해 플러그인을 가지고 있습니다.


나는 이것이 다른 활동의 메소드를 호출하는 것만 큼 간단하지 않은 이유를 항상 궁금해했습니다. 나는 최근에 거의 그렇게 간단하게 만드는 유틸리티 라이브러리를 작성했습니다. 여기 ( https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher ) 에서 확인할 수 있습니다 .

GNLauncher를 사용하면 필요한 데이터를 매개 변수로 사용하여 Activity에서 함수를 호출하는 것처럼 쉽게 다른 Activity에서 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참조하십시오 .


한 활동에서 다른 활동으로 개체를 전달합니다.

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

이전에는 Pacelable 또는 Serializable로 객체를 설정하여 전송했지만 object (model)에 다른 변수를 추가 할 때마다 모두 등록해야합니다. 너무 불편 해요.

활동 또는 조각간에 개체를 전송하는 것은 매우 쉽습니다.

Android DataCache


한 활동에서 다른 활동으로 객체를 전달할 수 있습니다.

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

Pass one activity to another:

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

Get values:

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

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.

참고URL : https://stackoverflow.com/questions/2736389/how-to-pass-an-object-from-one-activity-to-another-on-android

반응형