Как передать объект из одного действия в другое на Android


781

Я пытаюсь отправить объект моего класса клиентов из одного 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
вероятно, вам следует изменить принятый ответ с учетом массового мнения.
Рохит Випин Мэтьюз

Я использовал для установки объекта значение Pacelable или Serializable, но всякий раз, когда я добавляю другие переменные, мне приходится добавлять все это в функции, чтобы получить и установить для Pacelable или Serializable. поэтому я сделал DataCache для переноса между действиями и фрагментами. github.com/kimkevin/AndroidDataCache Переносить объекты очень просто.
Кимкевин

Ответы:


888

Один из вариантов может позволить вашему пользовательскому классу реализовать 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: В свою защиту я никогда не говорил, что это лучший вариант; ОП просто попросил альтернативы, и я предложил один. В любом случае спасибо.
Самух

83
Почему Serializable не является хорошим вариантом? Это хорошо известный интерфейс, есть большая вероятность, что классы людей уже могут его реализовать (например, ArrayList уже Serializable). Почему вы должны изменить свои объекты данных, чтобы добавить дополнительный код, просто чтобы передать их из одного класса в другой? Это похоже на плохой дизайн. Я могу предположить, что на каком-то уровне это может повлиять на производительность, но я думаю, что в 99% случаев люди передают небольшие объемы данных, и им все равно. Проще и портативнее тоже иногда лучше.
Nate

16
@ Сандер: тогда этот ответ ( stackoverflow.com/questions/2139134/… ) неправильный? Он говорит , что Parcelable IS разработан специально для этой цели (и гораздо быстрее , чем Serializable). Я в замешательстве.
Слаума

41
Parcelableможет быть хорошо для скорости, но это сложно реализовать. Что если у вас есть 8 объектов, которые вам нужно передать между действиями, собираетесь ли вы создавать каждый из них Parcelable? Было бы разумнее использовать Serializableвместо этого. Когда вы реализуете, Parcelableвы должны добавить много кода в класс и упорядочить поля очень специфическим образом; Serializableты не В конечном счете, я думаю, что все сводится к тому, сколько объектов вы проходите и что вы пытаетесь сделать.
BlackHatSamurai

15
Serializableстандартный интерфейс Java Вы просто помечаете класс Serializable, реализуя интерфейс, и Java автоматически сериализует его в определенных ситуациях. Parcelableэто специальный интерфейс для Android, где вы реализуете сериализацию самостоятельно. Он был создан, чтобы быть намного более эффективным, чем Serializable, и обойти некоторые проблемы со стандартной сериализационной схемой Java
Gaurav Arora

312

Реализуйте свой класс с 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 Activity в Y Activity. Где-то в 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
Сериализуемый слишком медленный для больших POJO. Использование шины намного лучше.
Стивен Марк Форд

1
Почему я должен префикс (Serializable)к объекту?
Олстон

123
  • Использование глобальных статических переменных не является хорошей практикой разработки программного обеспечения .
  • Преобразование полей объекта в примитивные типы данных может быть сложной задачей .
  • Использование serializable - это нормально, но оно неэффективно на платформе Android.
  • Parcelable специально разработан для Android, и вы должны его использовать. Вот простой пример: передача пользовательских объектов между действиями Android

Вы можете создать Parcelable код для вашего класса, используя этот сайт .


4
Что если мой объект содержит вложенный Arraylist?
Доктор АНДРО

10
Ну, может быть, но на самом деле нужно воспринимать «производительность» с недоверием. Если это будет стоить реализации, Parcelableя бы предпочел, чтобы мои классы POJO не зависели от Android и не использовались Serializable.
VH-NZZ

Я не согласен, что вы должны использовать Parcelable. Простой шаблон BUS намного эффективнее во время выполнения и экономит много времени на разработку.
Стивен Марк Форд

15
Согласно этому тесту bitbucket.org/afrishman/androidserializationtest Serializable намного быстрее, чем Parcelable. Пожалуйста, прекратите делиться этой 5-летней ерундой о Parcelable.
afrish

7
Как глобальные статические переменные "не являются хорошей практикой разработки программного обеспечения"? Вы можете создать что-то вроде одноэлементного кэша и / или сетки данных, а затем передавать идентификаторы или тому подобное. Когда вы передаете ссылки в Java, вы в любом случае используете глобальные статические переменные, так как они указывают на один и тот же объект.
перерыв

112

Используйте gson, чтобы преобразовать ваш объект в JSON и передать его через намерение. В новом Activity конвертируйте JSON в объект.

В вашем build.gradle, добавьте это к вашим зависимостям

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

В своей деятельности преобразуйте объект в json-строку:

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

Получив Activity, преобразуйте json-строку обратно в исходный объект:

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)

3
Это избыточное решение, gson - это просто тип сериализации строк в json, лучше реализовать Serializable или Paracable.
Джеймс Ройтер

14
Нет необходимости реализовывать сериализуемый в каждом объекте и в каждом проекте (пустая трата времени), если вы можете использовать библиотеку (gson), которая обрабатывает это. Что касается излишних возможностей, то есть двух- и четырехъядерных телефонов, они могут обрабатывать даже список, следуя этой идее ответа.
Сагитс

4
Я также рекомендовал бы использовать gson, потому что gson может также сериализовать arraylists в дополнение к вышеупомянутому.
Нургасеметей

4
Это замечательно! В моем случае я использую библиотеку, в которой объекты не реализуют сериализуемые и не могут быть разобраны. Так что это мой единственный вариант afaik
Чад Бингхам

2
Это «лучший» вариант. Некоторые классы настолько просты, что вам не нужно слишком усложнять их реализацию, реализуя сериализуемые
Ojonugwa Jude Ochalifu

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

Адхаван, у меня есть вопрос. Когда вы создаете первый класс Intent, вы передаете fromClass.this в качестве первого аргумента. Есть ли способ получить этот объект в получающем классе активности?
новичок

1
Милиу, fromClass fr = (fromClass) getParent (); это то, что тебе нужно?
Объявления

Адхава, я на самом деле сделал это, но фр нулевой. Есть идеи почему?
новичок

Милиу, пожалуйста, поделись своим следом исключения, чтобы мы могли его изучить.
Реклама

У Parcelable чертовски много ненужного кода котельной плиты, и, откровенно говоря, это пустая трата времени. Скорее используйте автобус. Смотрите мой пост ниже.
Стивен Марк Форд

89

По моему опыту есть три основных решения, каждое со своими недостатками и преимуществами:

  1. Реализация Parcelable

  2. Реализация Сериализуемый

  3. Использование некоторой облегченной библиотеки шины событий (например, EventBus от Greenrobot или Otto от Square)

Parcelable - быстрый и стандартный для Android, но он имеет много стандартного кода и требует жестко закодированных строк для справки при извлечении значений из намерения (не строго типизированного).

Сериализуемый - близкий к нулю шаблон, но это самый медленный подход, который также требует жестко закодированных строк при извлечении значений из намерения (не строго типизированных).

Шина событий - нулевой шаблон, самый быстрый подход и не требует жестко закодированных строк, но требует дополнительной зависимости (хотя обычно и небольшой, ~ 40 КБ)

Я опубликовал очень подробное сравнение этих трех подходов, включая критерии эффективности.


4
Ссылка на статью мертва. Все еще доступно на webarchive: web.archive.org/web/20160917213123/http://…
OlivierH

Обидно, что ссылка не работает :(
Mauker

Проблема использования Event Bus заключается в том, что целевая активность воссоздается, например, из-за ротации. В этом случае целевой Activity не имеет доступа к переданному объекту, поскольку этот объект был использован из шины при более раннем вызове.
JuliuszJ

1
Parcelable является самым быстрым, и с помощью этого генератора ( parcelabler.com ) вы можете вставить свой класс, и он может сгенерировать код для вас. Просто.
ByWaleed

1
@ByWaleed ... Я абсолютно согласен, я всегда использую этот сайт, делаю вещи без каких-либо проблем. Тем не менее, у меня было много неудачных попыток, когда я пытался использовать POJO, который состоит из другого объекта. По какой-то причине его выход не работает.
Yo Apps

42

Я нашел простой и элегантный метод:

  • НЕТ Parcelable
  • НЕТ Сериализуемый
  • Нет статического поля
  • No 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 создаст глобальную ссылку 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 возвращаемое задание, которое является указателем, мы можем безопасно преобразовать его в int) в ваше намерение (через Intent :: putExtra)
  • для получателя
    1. получить целое число из Intent (через Intent :: getInt)
    2. используйте собственный нативный метод для восстановления вашего Java-объекта из глобальной справочной таблицы JNI (через JNIEnv :: NewLocalRef)
    3. удалить элемент из глобальной справочной таблицы JNI (через JNIEnv :: DeleteGlobalRef),

Но у метода 2 есть небольшая, но серьезная проблема: если получателю не удается восстановить объект Java (например, какое-то исключение происходит до восстановления объекта Java, или действие получателя вообще не существует), тогда объект Java станет утечка памяти или утечка памяти, метод 1 не имеет этой проблемы, потому что Android Binder будет обрабатывать это исключение

Способ 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);

Код для второго занятия:

измените атрибут android: process в 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

Вау .... метод первого этого человека огромна ..... Если у вас есть очень большие / объекты больших размеров , что хорошо работает
Каран

Я пользователь метод один. Итак, вы экономите мое время. Спасибо;
ShweLiam

Большое спасибо за метод ObjectWrapperForBinder, действительно помогает!
Владимир Толстиков

40

Вы также можете записать данные объекта во временные строки и целые и передать их в действие. Конечно, таким образом вы получаете транспортируемые данные, но не сам объект.

Но если вы просто хотите отобразить их, а не использовать объект в другом методе или что-то в этом роде, этого должно быть достаточно. Я сделал это так же, чтобы просто отобразить данные из одного объекта в другой деятельности.

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

Вы также можете передать их напрямую вместо временных иваров, но, на мой взгляд, так будет понятнее. Кроме того, вы можете установить для временных ивров значение null, чтобы они быстрее очищались сборщиком мусора.

Удачи!

На заметку: переписать toString () вместо написания собственного метода печати.

Как упомянуто в комментариях ниже, вот как вы вернете свои данные в другой деятельности:

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

9
вернуть ваши данные снова с помощью: String fName = getIntent (). getExtras (). getInt ("fname");
Алистер

2
Чтобы получить данные обратно: Bundle extras = getIntent().getExtras(); String val = extras.getString("fname");
Эрик Лещинский

1
Это может быстро стать невозможным для больших POJO. Скорее используйте автобус. Смотрите мой пост ниже.
Стивен Марк Форд

как я упоминал в своем ответе, это для простых случаев использования, когда вам не нужен сам объект, а просто некоторые его значения. Нельзя быть подспорьем для сложных случаев использования.
MJB

1
Хорошая идея передать один объект, но я пытаюсь передать массив неизвестного размера моего объекта. Возможно, ваше решение не для передачи массивов объектов.
Мухаммед Сакиб

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; логический перманент; ....} Идея в том, что вы можете передать логическое значение в методе add, если вам нужно сохранить объект постоянным и не удалять при вызове get. Это поможет сохранить некоторые глобальные объекты. Как может быть открытое соединение Bluetooth и т. Д.
Umair

1
Милый, но не изобретай велосипед. Модель автобуса элегантна и мощнее. Смотрите мой пост ниже.
Стивен Марк Форд

@StevenMarkFord, так что шаблон Bus по-прежнему действует до сих пор? Я пытаюсь улучшить кодовую базу с помощью кода, подобного этому, для доступа к данным между действиями: BookActivity.getInstance().recommendationResponseвRoomsActivity
Woppi

Когда принимающая активность воссоздана (например , при повороте экрана) objстановится null. Чтобы этого избежать, objнужно где-то хранить, чтобы получить его снова. Действительно, решение Json хранит данные объекта в Intent.
Сальвадор

25

Есть несколько способов получить доступ к переменным или объектам в других классах или Activity.

А. База данных

Б. Общие предпочтения.

C. Сериализация объектов.

D. Класс, который может содержать общие данные, может называться Common Utilities. Это зависит от тебя.

E. Передача данных через Intents и Parcelable Interface.

Это зависит от потребностей вашего проекта.

А. База данных

SQLite - это база данных с открытым исходным кодом, встроенная в Android. SQLite поддерживает стандартные функции реляционной базы данных, такие как синтаксис SQL, транзакции и подготовленные операторы.

Учебники

Б. Общие предпочтения

Предположим, вы хотите сохранить имя пользователя. Так что теперь будет две вещи: ключевое имя пользователя и значение значения.

Как хранить

 // 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 (), вы можете сохранить желаемый тип данных.

Как получить

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

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

C. Сериализация объекта

Объектная серизация используется, если мы хотим сохранить состояние объекта, чтобы отправить его по сети, или вы также можете использовать его для своих целей.

Используйте Java-бины и сохраняйте их как одно из его полей, а для этого используйте getter и setter.

JavaBeans - это классы Java, которые имеют свойства. Думайте о свойствах как о частных переменных экземпляра. Поскольку они закрыты, единственный доступ к ним за пределами их класса - через методы в классе. Методы, которые изменяют значение свойства, называются методами установки, а методы, которые извлекают значение свойства, называются методами получения.

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 для этой опции передачи данных.


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

..Проверьте код, который вы передаете "bundle" в качестве ключа для put cust obj и получаете из "class" .. Пожалуйста, используйте один ключ "class" или "bundle" ..
AK Joshi

Я сталкиваюсь с ошибкой: Parcelable столкнулся с IOException при записи сериализуемого объекта
Арул Мани

15

Лучший способ - это иметь класс (назовите его Control) в вашем приложении, который будет содержать статическую переменную типа «Клиент» (в вашем случае). Инициализируйте переменную в вашей деятельности А.

Например:

Control.Customer = CustomerClass;

Затем перейдите к занятию B и получите его из класса Control. Не забудьте присвоить значение null после использования переменной, иначе память будет потрачена впустую.


4
@aez Потому что это небрежно с точки зрения дизайна и ужасно сломается, если Intent когда-либо будет в другом процессе.

7
Вы столкнетесь с проблемами при возврате приложения в действие B. Поскольку действие может быть убито Android, и объект не будет сохранен.
Райан R

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

Теперь вы хотите передать объект этого класса в startActivity. Просто используйте это:

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

Это работает здесь, потому что MyClass реализует Serializable.


не могли бы вы объяснить или уточнить подробнее
Амитшарма

HomeworkData homeworkData = homeWorksList.get (position); Intent intent = new Intent (c, HomeWorkActivitydetail.class); Bundle b = новый Bundle (); b.putSerializable ("CompleteData", homeworkData); intent.putExtras (б); c.startActivity (намерение); во время добавления объекта дает мне некоторую ошибку при добавлении элементов объекта, мы можем не передать полный объект с этим
Amitsharma

внутри homeworkData у меня есть некоторые ценности, которые они прибавляют
Amitsharma

12

Если вы решите использовать способ, описанный Samuh, помните, что отправлять можно только примитивные значения. То есть значения, которые могут быть пересчитаны. Таким образом, если ваш объект содержит сложные объекты, они не будут следовать. Например, такие переменные, как Bitmap, HashMap и т. Д. Их сложно передать намерением.

В общем , я бы посоветовал вам послать только примитивные типы данных в качестве статистов, как String, Int, логическое и т.д. В вашем случае это будет: String fname, String lname, int age, и String address.

Мое мнение: более сложные объекты лучше использовать совместно с помощью ContentProvider , SDCard и т. Д. Также можно использовать статическую переменную , но это может быстро привести к подверженному ошибкам коду ...

Но опять же, это только мое субъективное мнение.


8

Я использую 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});
    }
}

В деятельности 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 <> устарел. Что за альтернатива?
Рагавендра М

6

Этот вопрос также обсуждается в другом вопросе переполнения стека. Пожалуйста, обратите внимание на решение для передачи данных через намерение с использованием 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. плагин для Android Studio - Генератор парсерабельного кода Android

5

Создайте класс, такой как bean-класс, и реализуйте 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вместо этого.
Мэтью Кирос

3

Объекты Android Activity могут быть уничтожены и восстановлены. Таким образом, вам нужно будет использовать другой подход, чтобы посмотреть их - или любой объект, который они создают !!! - вверх То есть вы можете передать как ссылку на статический класс, но тогда дескриптор объекта (Java вызывает эти «ссылки», как и SmallTalk; но они не являются ссылками в смысле C или сборки), возможно, будет позже недействительным, потому что «функция» Android OE - это любая Деятельность, которая может быть уничтожена и восстановлена ​​позже.

Первоначальный вопрос был «Как передать объект из одного действия в другое в Android», и никто не ответил на это. Конечно, вы можете сериализовать (Serializable, Parcelable, в / из JSON) и передать копию данных объекта, и новый объект, имеющий те же данные, может быть создан; но он НЕ будет иметь одинаковые ссылки / дескрипторы. Также многие другие упомянули, что вы можете хранить ссылку в статическом хранилище. И это будет работать, если Android не решит удалить вашу активность.

Таким образом, чтобы действительно решить исходный вопрос, вам понадобится статический поиск, и каждый объект обновит свою ссылку, когда / если он будет создан заново. Например, каждое действие Android будет самоотверженным, если вызывается его onCreate. Вы также можете увидеть, как некоторые люди используют список задач для поиска действия по имени. (система временно уничтожает этот экземпляр действия, чтобы сэкономить место. getRunningTasks, список задач - это фактически специализированный список самого последнего экземпляра объекта каждого действия).

Для справки:

Остановлено: «Действие полностью скрыто другим действием (действие теперь находится в« фоновом режиме »). Остановленное действие также все еще живо ( объект действия сохраняется в памяти , он сохраняет всю информацию о состоянии и членах, но не прикреплен к оконному менеджеру). Однако, он больше не виден пользователю и может быть убит системой, когда требуется память в другом месте. "

onDestroy "система временно уничтожает этот экземпляр действия для экономии места."

Итак, шина сообщений является работоспособным решением. Это в основном "каламбуры". Вместо того, чтобы пытаться иметь ссылки на объекты; затем вы перепроектируете свой дизайн, чтобы использовать MessagePassing вместо SequentialCode. Экспоненциально сложнее отлаживать; но это позволяет вам игнорировать такого рода понимание операционной среды. Фактически, каждый метод доступа к объекту инвертируется, поэтому вызывающая сторона публикует сообщение, а сам объект определяет обработчик для этого сообщения. Много кода, но он может быть надежным с ограничениями Android OE.

Если все, что вам нужно, это верхняя активность (типичная вещь в приложениях Android из-за повсеместного «контекста»), тогда вы можете просто указывать каждую активность как «верхнюю» в статическом глобальном пространстве всякий раз, когда вызывается его onResume. Тогда ваш AlertDialog или любой другой, которому нужен контекст, может просто взять его оттуда. Кроме того, немного неприятно использовать глобальный код, но он может упростить передачу контекста вверх и вниз повсюду, и, конечно, когда вы используете MessageBus, тогда он в любом случае глобален.


У Отто есть возможность запускать его внешне в простом старом Java-приложении. Таким образом, хорошо для разработки и тестирования без необходимости связываться с Android. У Otto есть большая кривая обучения, и большая часть того, что он решает, уже решена способами Android (локальная трансляция и т. Д.) Или обычными подходами разработчиков приложений (вы можете написать гораздо более простой глобальный поиск, чем глобальный поиск Otto, нормальные подходы намного более доступным для векторизации / F3 через код и для пошаговой отладки).
TimJowers2

2
  1. Я знаю, что статика плохая, но кажется, что мы вынуждены использовать ее здесь. Проблема с parceables / seriazables заключается в том, что эти два действия имеют повторяющиеся экземпляры одного и того же объекта = потеря памяти и процессора.

    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

Над ответами почти все правильно , но для тех , кто не undestand ответы на эти вопросы 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 на вашем объекте, чтобы разделить действия. Трудно реализовать Parcealbe, а не Serializable интерфейс на объекте, поэтому Android имеет плагин специально для этого. Загрузите его и используйте его


0

Я всегда задавался вопросом, почему это не может быть так просто, как вызов метода другой деятельности. Недавно я написал служебную библиотеку, которая делает его почти таким же простым. Вы можете проверить это здесь ( https://github.com/noxiouswinter/gnlib_android/wiki/gnlauncher ).

GNLauncher делает отправку объектов / данных в Activity из другого Activity и так же просто, как вызов функции в Activity с необходимыми данными в качестве параметров. Он вводит безопасность типов и устраняет все трудности, связанные с сериализацией, присоединением к цели с использованием строковых ключей и отменой того же на другом конце.

Применение

Определите интерфейс с методами, которые вы хотите вызвать в Activity для запуска.

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

Реализуйте вышеуказанный интерфейс в Activity для запуска. Также уведомите 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");


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

    };
}

Эта логика действительно крутая, потому что вы на самом деле передаете ссылку от действия к действию.

Я бы посоветовал проверять наличие нулей, и если экземпляр 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();

Черт возьми, кто-то может сойти с ума и сделать эту присоску настоящим родовым.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.