Cara mengirim objek melalui bundel

119

Saya perlu memberikan referensi ke kelas yang melakukan sebagian besar pemrosesan saya melalui bundel.

Masalahnya adalah ini tidak ada hubungannya dengan maksud atau konteks dan memiliki sejumlah besar objek non-primitif. Bagaimana cara mengemas kelas menjadi parcelable / serializable dan meneruskannya ke startActivityForResult?

ahodder
sumber
2
"Saya perlu memberikan referensi ke kelas yang sebagian besar pemrosesan saya melalui bundel" - mengapa?
CommonsWare
1
Saya memiliki sebuah objek (DataManager), itu menangani server dan menjalankan beberapa backend untuk beberapa GUI. Kapan pun koneksi baru dibuat, saya ingin pengguna dapat memulai aktivitas baru yang mencantumkan semua koneksi aktif di ListView dan meminta pengguna memilih satu. Data yang dihasilkan kemudian akan dikaitkan ke GUI baru. Ini benar-benar hanya pemilih kulit untuk bagian belakang.
Ahodder
3
Jika Anda berurusan dengan contoh objek yang sama pada beberapa aktivitas, Anda mungkin ingin mempertimbangkan pola singleton . Ada tutorial bagus di sini .
sotrh

Jawaban:

55

Mencari tahu jalan mana yang harus diambil membutuhkan jawaban tidak hanya pertanyaan kunci CommonsWare tentang "mengapa" tetapi juga pertanyaan "untuk apa?" apakah kamu melewatinya.

Kenyataannya adalah bahwa satu-satunya hal yang dapat melalui bundel adalah data biasa - yang lainnya didasarkan pada interpretasi dari apa arti atau maksud data itu. Anda tidak dapat benar-benar melewatkan suatu objek, tetapi yang dapat Anda lakukan adalah salah satu dari tiga hal:

1) Anda dapat memecah objek menjadi data penyusunnya, dan jika yang ada di ujung lain memiliki pengetahuan tentang objek yang sama, ia dapat mengumpulkan tiruan dari data serial. Begitulah cara sebagian besar tipe umum melewati bundel.

2) Anda bisa melewati pegangan buram. Jika Anda menyampaikannya dalam konteks yang sama (meskipun orang mungkin bertanya mengapa repot-repot) itu akan menjadi pegangan yang dapat Anda panggil atau dereferensi. Tetapi jika Anda meneruskannya melalui Binder ke konteks yang berbeda, nilai literalnya akan menjadi angka arbitrer (faktanya, angka arbitrer ini dihitung secara berurutan dari permulaan). Anda tidak dapat melakukan apa pun selain melacaknya, sampai Anda meneruskannya kembali ke konteks asli yang akan menyebabkan Binder mengubahnya kembali ke pegangan aslinya, membuatnya berguna lagi.

3) Anda dapat memberikan pegangan ajaib, seperti deskriptor file atau referensi ke objek os / platform tertentu, dan jika Anda menyetel bendera yang benar, Binder akan membuat klon yang menunjuk ke sumber daya yang sama untuk penerima, yang sebenarnya dapat digunakan di ujung lainnya. Tetapi ini hanya berfungsi untuk beberapa jenis objek.

Kemungkinan besar, Anda melewati kelas Anda hanya agar ujung yang lain dapat melacaknya dan memberikannya kembali kepada Anda nanti, atau Anda meneruskannya ke konteks di mana klon dapat dibuat dari data konstituen berseri ... atau yang lain Anda mencoba melakukan sesuatu yang tidak akan berhasil dan Anda perlu memikirkan kembali keseluruhan pendekatan.

Chris Stratton
sumber
1
Terima kasih atas balasan turnya. Hak Anda, yang perlu saya lakukan hanyalah meneruskan referensi daftar objek ke aktivitas baru saya. Aktivitas baru akan mengambil beberapa data dari daftar dan menampilkan ListView yang dapat dipilih. onSelect, aktivitas akan mengembalikan hasil (beberapa data yang berkaitan dengan objek klik) ke aktivitas host. Jika saya mengerti dengan benar, saya yakin opsi 2 Anda menangani ini dengan paling tepat; bagaimana cara mendapatkan pegangan buram ini?
Ahodder
Aktivitas Anda yang lain tidak dapat mengekstrak data apa pun dari objek buram untuk ditampilkan. Apa yang mungkin ingin Anda lakukan adalah membuat dan meneruskan beberapa objek pengganti dari jenis yang didukung yang berisi salinan informasi yang akan ditampilkan.
Chris Stratton
158

Anda juga dapat menggunakan Gson untuk mengonversi objek menjadi JSONObject dan meneruskannya dalam paket. Bagi saya adalah cara paling elegan yang saya temukan untuk melakukan ini. Saya belum menguji bagaimana hal itu memengaruhi kinerja.

Dalam Aktivitas Awal

Intent activity = new Intent(MyActivity.this,NextActivity.class);
activity.putExtra("myObject", new Gson().toJson(myobject));
startActivity(activity);

Dalam Aktivitas Berikutnya

String jsonMyObject;
Bundle extras = getIntent().getExtras();
if (extras != null) {
   jsonMyObject = extras.getString("myObject");
}
MyObject myObject = new Gson().fromJson(jsonMyObject, MyObject.class);
Laranjeiro
sumber
3
Karena ini masalah melewatkan barang di antara aktivitas, itu tidak cukup sering terjadi untuk berdampak besar pada kinerja aplikasi secara keseluruhan. Yang sedang berkata saya ragu itu akan berhasil untuk membuat serial DataManager dari posting asli karena kedengarannya seperti memiliki koneksi soket dan kelas serupa lainnya.
britzl
4
Juga Google menyarankan solusi ini daripada Serialize: lihat bagian terakhir "Alternatif yang Direkomendasikan" dari halaman dokumen ini
TechNyquist
3
hanya sebagai kata peringatan, saya mengikuti teknik ini untuk sementara waktu tetapi ada batas memori untuk apa yang dapat Anda berikan sebagai String jadi pastikan data Anda tidak terlalu besar.
jiduvah
Lihat blog.madadipouya.com/2015/09/21/… untuk mempelajari cara menambahkan dukungan Gson ke proyek Anda.
geekQ
Solusi cerdas, angkat topi untuk Anda!
Rohit Mandiwal
20

The Parcelable antarmuka adalah cara yang baik untuk melewati sebuah objek dengan Intent.

Bagaimana cara membuat objek kustom saya menjadi Parcelable? adalah jawaban yang cukup bagus tentang cara menggunakan Parcelable

Google docs resmi juga menyertakan sebuah contoh

chris
sumber
1
atau mereka juga dapat dibuat bersambung.
Jeffrey Blattman
1
Tapi sangat mengurangi kinerja 10x !! Lihat tolok ukur ini: developerphil.com/parcelable-vs-serializable
saiyancoder
2
Komentar +1 @ Mati, namun untuk memasukkannya ke dalam konteks 10x ketika diterapkan ke satu objek sama dengan 1 ms. Jadi mungkin tidak seburuk kedengarannya.
pinoyyid
1
Setuju. Masalahnya adalah saat Anda menangani koleksi, yang merupakan kasus penggunaan yang sangat umum jika Anda mendapatkan sumber daya dari Rest API. Tetapi untuk satu objek, seharusnya tidak menjadi sesuatu yang terkenal. Bagaimanapun, jika semua kode boilerplate menghalangi Anda, Anda dapat mencoba lib ini yang menghasilkan semuanya untuk Anda: github.com/johncarl81/parceler . Pendekatan yang sangat bagus!
saiyancoder
Tautan rusak: 404 (tidak ditemukan)
Gallal
14

Anda bisa menggunakan status aplikasi global .

Memperbarui:

Sesuaikan lalu tambahkan ini ke AndroidManifest.xml Anda:

<application android:label="@string/app_name" android:debuggable="true" android:name=".CustomApplication"

Dan kemudian buat kelas dalam proyek Anda seperti ini:

package com.example;

import android.app.Application;

public class CustomApplication extends Application {
    public int someVariable = -1;
}

Dan karena " Ini dapat diakses melalui getApplication () dari Aktivitas atau Layanan apa pun ", Anda menggunakannya seperti ini:

CustomApplication application = (CustomApplication)getApplication();
application.someVariable = 123; 

Semoga membantu.

Neil
sumber
1
Terima kasih atas jawabannya, tapi bagaimana caranya?
Ahodder
Saya yakin Anda hanya subclass Aplikasi dan kemudian dapat menyimpan apapun yang Anda suka. Perubahan xml yang Anda butuhkan disebutkan di tautan di atas.
Mark Storer
9
Sebagai prinsipal desain umum, sebaiknya hindari global kecuali Anda benar-benar membutuhkannya. Dalam hal ini ada alternatif yang bagus.
dhaag23
Oke, saya rasa saya mengerti apa yang Anda katakan. Perluas saja Application dan masukkan variabel yang menampung objek yang perlu diteruskan; Saya meninjau halaman referensi dan tidak melihat perubahan xml yang diperlukan.
Ahodder
Saya ingin menulis ini sebagai jawaban juga. Ini pasti salah satu cara untuk melakukannya. Namun perlu diingat bahwa objek ini tetap berada di memori kecuali Anda membatalkan refreinasinya (atau konteks Aplikasi dihancurkan) dan dapat menempati ruang saat Anda tidak membutuhkannya.
Igor Čordaš
12

Anda juga dapat membuat objek Anda Serializable dan menggunakan Bundle ini getSerializable dan putSerializable metode.

dhaag23
sumber
1
Saya mencobanya dan segera menyadari bahwa itu tidak praktis. Saya tidak berpikir sebagian besar objek yang disimpan di kelas yang lulus (utas) dapat bersambung. :) terimakasih Meskipun.
Ahodder
10

Solusi yang mungkin:

Bundle bundle = new Bundle();
bundle.putSerializable("key", new CustomObject());

Kelas CustomObject:

class CustomObject implements Serializable{
 private SubCustomObject1 sc1;
 private SubCustomObject2 sc2;
}

Objek subkustomisasi:

class SubCustomObject1 implements Serializable{ }

class SubCustomObject2  implements Serializable{ }
PraKhar
sumber
7

Satu cara lagi untuk mengirim objek melalui bundel adalah dengan menggunakan bundle.putByteArray
kode Contoh

public class DataBean implements Serializable {
private Date currentTime;

public setDate() {
    currentTime = Calendar.getInstance().getTime();
 }

public Date getCurrentTime() {
    return currentTime;
 }
}

masukkan Object of DataBean ke Bundle:

class FirstClass{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Your code...

//When you want to start new Activity...
Intent dataIntent =new Intent(FirstClass.this, SecondClass.class);
            Bundle dataBundle=new Bundle();
            DataBean dataObj=new DataBean();
            dataObj.setDate();
            try {
                dataBundle.putByteArray("Obj_byte_array", object2Bytes(dataObj));

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();

            }

            dataIntent.putExtras(dataBundle);

            startActivity(dataIntent);
}

Mengonversi objek menjadi array byte

/**
 * Converting objects to byte arrays
 */
static public byte[] object2Bytes( Object o ) throws IOException {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream( baos );
      oos.writeObject( o );
      return baos.toByteArray();
    }

Dapatkan kembali Objek dari Bundel:

class SecondClass{
DataBean dataBean;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Your code...

//Get Info from Bundle...
    Bundle infoBundle=getIntent().getExtras();
    try {
        dataBean = (DataBean)bytes2Object(infoBundle.getByteArray("Obj_byte_array"));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Metode untuk mendapatkan objek dari array byte:

/**
 * Converting byte arrays to objects
 */
static public Object bytes2Object( byte raw[] )
        throws IOException, ClassNotFoundException {
      ByteArrayInputStream bais = new ByteArrayInputStream( raw );
      ObjectInputStream ois = new ObjectInputStream( bais );
      Object o = ois.readObject();
      return o;
    }

Semoga ini bisa membantu sobat lainnya.

Rupesh Yadav
sumber
ini terlihat mulus dan mudah dilihat di kode. Tetapi saya merasa ada sesuatu yang lebih mengapa SDK tidak menawarkan sesuatu seperti ini untuk mengirimkan objek. Dapatkah Anda memberi tahu saya lebih banyak tentang solusi ini?
Mario Lenci
3
Tidak perlu sama sekali untuk semua kode itu! Gunakan bundle.putSerializable (objectImplementingSerializable) - ini dilakukan di bawah apa yang Anda terapkan ulang di sini lagi ...
Risadinha
3

1. Contoh yang sangat langsung dan mudah digunakan, buat objek yang akan dilewatkan mengimplementasikan Serializable.

class Object implements Serializable{
    String firstName;
   String lastName;
}

2. melewati objek dalam bundel

Bundle bundle = new Bundle();
Object Object = new Object();
bundle.putSerializable("object", object);

3. dapatkan objek yang lewat dari bundel sebagai Serializable lalu transmisikan ke Object.

Object object = (Object) getArguments().getSerializable("object");
king_T
sumber
0

Ini adalah jawaban yang sangat terlambat untuk pertanyaan saya sendiri, tetapi terus mendapat perhatian, jadi saya merasa harus menjawabnya. Sebagian besar jawaban ini benar dan menangani pekerjaan dengan sempurna. Namun, itu tergantung dari kebutuhan aplikasinya. Jawaban ini akan digunakan untuk menjelaskan dua solusi untuk masalah ini.

Aplikasi

Yang pertama adalah Aplikasi , karena jawaban yang paling banyak dibicarakan di sini. Aplikasi adalah objek yang baik untuk menempatkan entitas yang membutuhkan referensi ke sebuah Konteks. Sebuah `ServerSocket` tidak diragukan lagi akan membutuhkan konteks (untuk file I / o atau update` ListAdapter` sederhana). Saya, secara pribadi, lebih suka rute ini. Saya suka aplikasi, mereka berguna untuk pengambilan konteks (karena mereka dapat dibuat statis dan tidak mungkin menyebabkan kebocoran memori) dan memiliki siklus hidup yang sederhana.

Layanan

The Service` adalah yang kedua. Sebuah `Layanan` sebenarnya adalah pilihan yang lebih baik untuk masalah saya karena untuk itulah layanan dirancang untuk dilakukan:
Layanan adalah komponen aplikasi yang dapat menjalankan operasi jangka panjang di
latar belakang dan tidak menyediakan antarmuka pengguna.
Layanan rapi karena memiliki siklus hidup yang lebih jelas yang lebih mudah dikendalikan. Lebih lanjut, jika diperlukan, layanan dapat dijalankan secara eksternal dari aplikasi (mis. Saat boot). Ini mungkin diperlukan untuk beberapa aplikasi atau hanya fitur yang rapi.

Ini juga bukan deskripsi lengkap, tapi saya meninggalkan tautan ke dokumen bagi mereka yang ingin menyelidiki lebih lanjut. Secara keseluruhan Servicelebih baik untuk contoh yang saya butuhkan - menjalankan ServerSocket ke perangkat SPP saya.

ahodder
sumber
0

Saya menemukan pertanyaan ini ketika saya sedang mencari cara untuk mengirimkan objek Tanggal. Dalam kasus saya, seperti yang disarankan di antara jawaban, saya menggunakan Bundle.putSerializable () tetapi itu tidak akan berfungsi untuk hal yang kompleks seperti yang dijelaskan DataManager di posting asli.

Saran saya yang akan memberikan hasil yang sangat mirip dengan meletakkan kata DataManager di Aplikasi atau membuatnya menjadi Singleton adalah dengan menggunakan Dependency Injection dan mengikat DataManager ke lingkup Singleton dan menyuntikkan DataManager di mana pun itu dibutuhkan. Anda tidak hanya mendapatkan keuntungan dari peningkatan kemampuan pengujian, tetapi Anda juga akan mendapatkan kode yang lebih bersih tanpa semua kode pelat boiler "meneruskan dependensi antara kelas dan aktivitas". (Robo) Guice sangat mudah digunakan dan kerangka kerja Dagger yang baru juga terlihat menjanjikan.

britzl
sumber
1
Nah, dengan sesuatu seperti Date, Anda bisa memberikan nilai panjang. Tapi, sisanya terdengar bagus. Terima kasih.
Ahodder
0

cara sederhana lain untuk mengirimkan objek menggunakan bundel:

  • di objek kelas, buat daftar statis atau struktur data lain dengan kunci
  • ketika Anda membuat objek, letakkan di daftar / struktur data dengan kunci (yaitu stempel waktu yang lama saat objek dibuat)
  • buat metode getObject statis (kunci panjang) untuk mendapatkan objek dari daftar
  • dalam bundel, berikan kunci, sehingga Anda bisa mendapatkan objek nanti dari titik lain dalam kode
shaolin.dll
sumber