Apa cara terbaik untuk berbagi data antar kegiatan?

239

Saya memiliki satu aktivitas yang merupakan aktivitas utama yang digunakan di seluruh aplikasi dan memiliki sejumlah variabel. Saya memiliki dua kegiatan lain yang ingin saya dapat menggunakan data dari kegiatan pertama. Sekarang saya tahu saya bisa melakukan sesuatu seperti ini:

GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();

Namun saya ingin berbagi banyak variabel dan beberapa mungkin agak besar sehingga saya tidak ingin membuat salinannya seperti di atas.

Apakah ada cara untuk langsung mendapatkan dan mengubah variabel tanpa menggunakan metode get and set? Saya ingat pernah membaca sebuah artikel di situs dev Google yang mengatakan ini tidak direkomendasikan untuk kinerja di Android.

Crazyfool
sumber
2
Pada Android 2.3 (Gingerbread), optimisasi get / set dilakukan secara otomatis oleh Dalvik; ini hanya relevan jika Anda menargetkan versi Android yang lebih lama.
StellarVortex
Perhatikan bahwa contoh tidak menyalin data string. Melainkan menciptakan referensi ke objek string yang sama.
Code-Apprentice
Sulit dipercaya, mengapa tidak ada kemungkinan untuk memulai suatu aktivitas dari aktivitas lain dan melewatkan objek kompleks dari yang pertama ke yang kedua? Tanpa serialisasi, simpan objek dan semua upaya itu. Apakah ini lubang keamanan atau alasan lain apa yang menentang hanya lewat referensi objek jika kedua aktivitas berada di aplikasi yang sama? (Saya mengerti itu berbeda jika mereka ada di aplikasi yang berbeda)
Droidum
Silakan lihat stackoverflow.com/questions/56521969/…
Levon Petrosyan
LiveData adalah solusi terbaik, terbaru. Periksa jawaban saya di bawah ini.
Amir Uval

Jawaban:

476

Berikut ini kompilasi cara paling umum untuk mencapai hal ini :

  • Kirim data di dalam niat
  • Bidang statis
  • HashMap dari WeakReferences
  • Objek yang bertahan (sqlite, preferensi berbagi, file, dll.)

TL; DR : ada dua cara berbagi data: mengirimkan data dalam ekstra maksud atau menyimpannya di tempat lain. Jika data primitif, string atau objek yang ditentukan pengguna: kirim sebagai bagian dari maksud ekstra (objek yang ditentukan pengguna harus mengimplementasikan Parcelable). Jika melewati objek yang kompleks, simpan instance dalam singleton di tempat lain dan akses mereka dari aktivitas yang diluncurkan.

Beberapa contoh bagaimana dan mengapa menerapkan setiap pendekatan:

Kirim data di dalam maksud

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("some_key", value);
intent.putExtra("some_other_key", "a value");
startActivity(intent);

Pada aktivitas kedua:

Bundle bundle = getIntent().getExtras();
int value = bundle.getInt("some_key");
String value2 = bundle.getString("some_other_key");

Gunakan metode ini jika Anda melewatkan data primitif atau String . Anda juga bisa melewatkan objek yang mengimplementasikan Serializable.

Meskipun menggoda, Anda harus berpikir dua kali sebelum menggunakan Serializable: itu rawan kesalahan dan sangat lambat. Jadi secara umum: menjauhlahSerializable jika memungkinkan. Jika Anda ingin meneruskan objek rumit yang ditentukan pengguna, lihat Parcelableantarmuka . Ini lebih sulit untuk diimplementasikan, tetapi memiliki kecepatan yang lebih baik dibandingkan dengan Serializable.

Bagikan data tanpa tetap ke disk

Dimungkinkan untuk berbagi data antara aktivitas dengan menyimpannya dalam memori mengingat bahwa, dalam kebanyakan kasus, kedua aktivitas berjalan dalam proses yang sama.

Catatan: terkadang, ketika pengguna meninggalkan aktivitas Anda (tanpa berhenti), Android dapat memutuskan untuk membunuh aplikasi Anda. Dalam skenario seperti itu, saya pernah mengalami kasus di mana android mencoba untuk meluncurkan aktivitas terakhir menggunakan maksud yang disediakan sebelum aplikasi terbunuh. Dalam kasus ini, data disimpan dalam singleton (milik Anda atauApplication ) akan hilang dan hal-hal buruk dapat terjadi. Untuk menghindari kasus-kasus seperti itu, Anda bisa tetap objek ke disk atau memeriksa data sebelum menggunakannya untuk memastikan itu valid.

Gunakan kelas singleton

Memiliki kelas untuk menyimpan data:

public class DataHolder {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}

  private static final DataHolder holder = new DataHolder();
  public static DataHolder getInstance() {return holder;}
}

Dari aktivitas yang diluncurkan:

String data = DataHolder.getInstance().getData();

Gunakan aplikasi singleton

Aplikasi singleton adalah sebuah instance android.app.Applicationyang dibuat ketika aplikasi diluncurkan. Anda dapat memberikan yang khusus dengan memperluas Application:

import android.app.Application;
public class MyApplication extends Application {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}
}

Sebelum meluncurkan aktivitas:

MyApplication app = (MyApplication) getApplicationContext();
app.setData(someData);

Kemudian, dari aktivitas yang diluncurkan:

MyApplication app = (MyApplication) getApplicationContext();
String data = app.getData();

Bidang statis

Idenya pada dasarnya sama dengan singleton, tetapi dalam hal ini Anda memberikan akses statis ke data:

public class DataHolder {
  private static String data;
  public static String getData() {return data;}
  public static void setData(String data) {DataHolder.data = data;}
}

Dari aktivitas yang diluncurkan:

String data = DataHolder.getData();

HashMap dari WeakReferences

Gagasan yang sama, tetapi memungkinkan pengumpul sampah untuk menghapus objek yang tidak direferensikan (mis. Ketika pengguna berhenti dari aktivitas):

public class DataHolder {
  Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();

  void save(String id, Object object) {
    data.put(id, new WeakReference<Object>(object));
  }

  Object retrieve(String id) {
    WeakReference<Object> objectWeakReference = data.get(id);
    return objectWeakReference.get();
  }
}

Sebelum meluncurkan aktivitas:

DataHolder.getInstance().save(someId, someObject);

Dari aktivitas yang diluncurkan:

DataHolder.getInstance().retrieve(someId);

Anda mungkin atau mungkin tidak harus melewati id objek menggunakan ekstra maksud. Itu semua tergantung pada masalah spesifik Anda.

Terus objek ke disk

Idenya adalah untuk menyimpan data dalam disk sebelum meluncurkan aktivitas lainnya.

Keuntungan: Anda dapat meluncurkan aktivitas dari tempat lain dan, jika data sudah bertahan, itu akan berfungsi dengan baik.

Kerugian: rumit dan membutuhkan lebih banyak waktu untuk diterapkan. Membutuhkan lebih banyak kode dan dengan demikian lebih banyak kesempatan untuk memperkenalkan bug. Itu juga akan jauh lebih lambat.

Beberapa cara untuk bertahan objek termasuk:

Cristian
sumber
11
Saya berpendapat bahwa itu bukan cara "normal" untuk data yang lebih besar / lebih kompleks. Jauh lebih mudah menggunakan singleton statis atau objek Aplikasi, dan itu berfungsi dengan baik. Sekarang yang mengatakan OP memang menggunakan String dalam contoh, untuk itu, Intent sempurna dan disukai.
Charlie Collins
10
Serializable ternyata memiliki masalah kinerja serius pada model proses Android. Itu sebabnya mereka memperkenalkan Parcelable. Baca Parcelable bukan Serializable dalam jawaban di atas.
Subin Sebastian
3
Itu dilakukan melalui setResultmetode. Juga, dalam hal ini, aktivitas sekunder harus dipanggil menggunakan startActivityForResultmetode.
Cristian
2
Ringkasan hebat! Mengenai masalah lajang yang dihancurkan, ada solusi sederhana untuk aplikasi dengan banyak kegiatan dan objek: Gunakan subkelas dari Activityseluruh, dan dalam onCreate()memeriksa setiap bidang statis dari singleton yang Anda isi saat memulai aplikasi. Jika bidang itu kosong, kembali ke aktivitas mulai menggunakan FLAG_ACTIVITY_CLEAR_TASKatau BroadcastReceiveruntuk menghentikan aktivitas lainnya.
Janosch
1
Saya tidak akan merekomendasikan menyimpan data di kelas aplikasi. Baca lebih lanjut di sini: developerphil.com/dont-store-data-in-the-application-object
Shayan_Aryan
22

Apa yang dapat Anda gunakan:

  1. meneruskan data antar aktivitas (seperti yang dikatakan Cristian)
  2. menggunakan kelas dengan banyak variabel statis (sehingga Anda dapat memanggil mereka tanpa turunan kelas dan tanpa menggunakan pengambil / penyetel)
  3. Menggunakan database
  4. Preferensi Bersama

Apa yang Anda pilih tergantung pada kebutuhan Anda. Mungkin Anda akan menggunakan lebih dari satu cara ketika Anda memiliki "banyak"

Warren Faith
sumber
1
Harap dicatat bahwa statika dihapus pada proses kematian
EpicPandaForce
@EpicPandaForce tentu saja dan juga saat perangkat dimatikan.
WarrenFaith
1
Tetapi jika perangkat dimatikan, aplikasi restart dari MAINtindakan. Setelah proses kematian, Anda memulai kembali aktivitas apa pun yang dibuka terakhir, yang bisa menjadi halaman detail di suatu tempat jauh di dalam aplikasi.
EpicPandaForce
@EpicPandaForce tampaknya Anda melewatkan ironi saya bahkan ketika Anda Cpt Obvious.
WarrenFaith
16

Lakukan apa yang diperintahkan google untuk Anda lakukan! di sini: http://developer.android.com/resources/faq/framework.html#3

  • Tipe Data Primitif
  • Objek Non-Persisten
  • Kelas singleton - favorit saya: D
  • Bidang / metode statis publik
  • HashMap of WeakReferences to Objects
  • Objek Persisten (Preferensi Aplikasi, File, Penyedia konten, DB SQLite)
Tylko Arka Gdynia
sumber
1
Google Link untuk Objek Persisten: developer.android.com/guide/topics/data/data-storage.html
NicoMinsk
Hanya antipattern, kelas Singleton adalah pola desain pertama, kelas dengan bidang / metode statis berperilaku sangat mirip lajang dan membuat basis data untuk objek busniss yang bertahan kadang-kadang bukan hal yang baik, tentu saja bukan kesalahan Anda dan Anda mendaftar mungkin cara untuk mencapainya, tetapi saya ingin tahu mengapa Google telah mempersulit hal yang sangat bodoh, masalah kinerja atau apa ?? !!!! atau saya tidak mengerti cara Android ?? !!!!
La VloZ Merrill
tautan rusak :(
Shayan_Aryan
14

"Namun saya ingin berbagi banyak variabel dan beberapa mungkin agak besar sehingga saya tidak ingin membuat salinannya seperti di atas."

Itu tidak membuat salinan (terutama dengan String , tetapi bahkan objek dilewatkan oleh nilai referensi, bukan objek itu sendiri, dan pengambil seperti itu baik untuk digunakan - bisa dibilang lebih baik untuk digunakan daripada cara lain karena mereka umum dan dimengerti). "Mitos kinerja" yang lebih lama, seperti tidak menggunakan getter dan setter, masih memiliki beberapa nilai, tetapi juga telah diperbarui dalam dokumen .

Tetapi jika Anda tidak ingin melakukan itu, Anda juga bisa membuat variabel publik atau dilindungi di GlobalState dan mengaksesnya secara langsung. Dan, Anda dapat membuat singleton statis sebagai objek Aplikasi JavaDoc menunjukkan :

Biasanya tidak perlu untuk subkelas Aplikasi. Dalam sebagian besar situasi, lajang statis dapat menyediakan fungsionalitas yang sama dengan cara yang lebih modular. Jika singleton Anda memerlukan konteks global (misalnya untuk mendaftarkan penerima siaran), fungsi untuk mengambilnya dapat diberikan Konteks yang secara internal menggunakan Context.getApplicationContext () ketika pertama kali membangun singleton.

Menggunakan data Intent , sebagai jawaban lain di sini perhatikan adalah cara lain untuk meneruskan data, tetapi biasanya digunakan untuk data yang lebih kecil dan tipe sederhana. Anda dapat melewatkan data yang lebih besar / lebih kompleks, tetapi lebih terlibat daripada hanya menggunakan satu statis. The Aplikasi objek masih favorit pribadi saya untuk berbagi / data persisten non lebih kompleks yang lebih besar antara komponen aplikasi Android meskipun (karena memiliki siklus hidup didefinisikan dengan baik dalam sebuah aplikasi Android).

Juga, seperti yang telah dicatat oleh orang lain, jika data menjadi sangat kompleks dan harus gigih maka Anda dapat menggunakan SQLite atau sistem file juga.

Charlie Collins
sumber
1
Sebenarnya, saya menemukan ini di dokumen baru-baru ini: developer.android.com/guide/appendix/faq/framework.html#3 . Untuk "objek kompleks non-persisten" disarankan menggunakan kelas Aplikasi untuk membuat dan menghancurkan singleton statis! Dengan begitu Anda mendapatkan aplikasi siklus hidup yang terdefinisi dengan baik, dan kemudahan penggunaan singleton statis.
Charlie Collins
2
bagian faq itu tampaknya dihapus sekarang (saya hanya melihat "objek non-persisten" dan tidak disebutkan kelas Aplikasi). Lagi pula Anda bisa menguraikan?
Tony Chan
1
Saat ini di developer.android.com/guide/faq/framework.html#3 "Bagaimana cara saya menyampaikan data antara Aktivitas / Layanan dalam satu aplikasi?", Dan tidak menyebutkan kelas Aplikasi.
Jerry101
Saya suka menggunakan objek Aplikasi, mengikuti preseden yang Anda atur di "Android in Action". Tetapi banyak calon majikan tidak suka kalau mereka melihat ini dalam kode tantangan. Mereka mungkin salah, tetapi mereka membuang berat badan mereka. BTW: tautan 'framework.html # 3 tidak lagi berfungsi.
Matt J.
4

Ada cara baru dan lebih baik untuk berbagi data antar kegiatan, dan itu adalah LiveData . Perhatikan kutipan ini dari halaman pengembang Android:

Fakta bahwa objek LiveData sadar siklus hidup berarti bahwa Anda dapat membaginya di antara beberapa aktivitas, fragmen, dan layanan. Agar contohnya sederhana, Anda bisa mengimplementasikan kelas LiveData sebagai singleton

Implikasinya sangat besar - data model apa pun dapat dibagi dalam kelas tunggal umum di dalam LiveDatapembungkus. Itu dapat disuntikkan dari kegiatan ke masing-masing ViewModeldemi testability. Dan Anda tidak perlu lagi khawatir dengan referensi yang lemah untuk mencegah kebocoran memori.

Amir Uval
sumber
2

Menggunakan hashmap dari pendekatan referensi lemah, yang dijelaskan di atas, dan di http://developer.android.com/guide/faq/framework.html tampaknya bermasalah bagi saya. Bagaimana seluruh entri direklamasi, bukan hanya nilai peta? Dalam cakupan apa Anda mengalokasikannya? Karena kerangka kerja mengendalikan siklus hidup Kegiatan, memiliki salah satu Kegiatan yang berpartisipasi memiliki risiko kesalahan runtime ketika pemilik dihancurkan sebelum klien-kliennya. Jika Aplikasi memilikinya, beberapa Kegiatan harus menghapus entri secara eksplisit untuk menghindari hashmap dari berpegang pada entri dengan kunci yang valid dan referensi lemah yang berpotensi dikumpulkan terkumpul. Lebih jauh, apa yang harus dilakukan klien ketika nilai yang dikembalikan untuk kunci adalah nol?

Bagi saya, WeakHashMap yang dimiliki oleh Aplikasi atau dalam singleton adalah pilihan yang lebih baik. Nilai dalam peta diakses melalui objek kunci, dan ketika tidak ada referensi kuat ke kunci (yaitu semua Kegiatan dilakukan dengan kunci dan apa peta itu), GC dapat mengklaim kembali entri peta.

Mark Rosenberg
sumber
2

Ada berbagai cara untuk berbagi data antar kegiatan

1: Mengirim data antar aktivitas menggunakan Intent

Intent intent=new Intent(this, desirableActivity.class);
intent.putExtra("KEY", "Value");
startActivity(intent)

2: Menggunakan kata kunci statis, tentukan variabel sebagai statis publik dan gunakan di mana saja dalam proyek

      public static int sInitialValue=0;

gunakan di mana saja dalam proyek menggunakan classname.variableName;

3: Menggunakan Database

tetapi prosesnya agak panjang, Anda harus menggunakan kueri untuk memasukkan data dan mengulangi data menggunakan kursor saat dibutuhkan. Tetapi tidak ada kemungkinan kehilangan data tanpa membersihkan cache.

4: Menggunakan Preferensi yang dibagikan

jauh lebih mudah daripada database. tetapi ada beberapa batasan Anda tidak dapat menyimpan ArrayList, Daftar dan objek custome.

5: Buat pengambil getter di kelas Aplikasi dan akses di mana saja dalam proyek.

      private String data;
      public String getData() {
          return data;
      }

      public void setData(String data) {
          this.data = data;
      }

di sini diatur dan dapatkan dari kegiatan

         ((YourApplicationClass)getApplicationContext()).setData("abc"); 

         String data=((YourApplicationClass)getApplicationContext()).getData();  
vikas singh
sumber
1

Ya saya punya beberapa ide, tetapi saya tidak tahu apakah itu yang Anda cari.

Anda bisa menggunakan layanan yang menyimpan semua data dan kemudian hanya mengikat aktivitas Anda ke layanan untuk pengambilan data.

Atau kemas data Anda menjadi serial atau parcelable dan tempelkan ke bundel dan berikan bundel di antara aktivitas.

Yang ini mungkin sama sekali bukan yang Anda cari, tetapi Anda juga bisa mencoba menggunakan SharedPreferences atau preferensi secara umum.

Bagaimanapun, beri tahu saya apa yang Anda putuskan.

ahodder
sumber
1

Dengan asumsi Anda memanggil aktivitas dua dari aktivitas satu menggunakan Intent.
Anda dapat mengirimkan data dengan intent.putExtra (),

Ambil ini untuk referensi Anda. Mengirim array dengan Intent.putExtra

Semoga itu yang Anda inginkan.

Manish Khot
sumber
1

Jika niat Anda adalah untuk memanggil Aktivitas lain dari Aktivitas saat ini, Anda harus menggunakan Maksud . Fokus Anda bisa lebih sedikit pada data yang bertahan daripada membagikannya sesuai kebutuhan.

Namun, jika Anda benar-benar perlu mempertahankan nilai-nilai ini maka Anda bisa bertahan dalam beberapa jenis file teks terstruktur atau database pada penyimpanan lokal. File properti, file XML, atau file JSON dapat menyimpan data Anda dan mudah diurai selama pembuatan aktivitas. Jangan lupa juga bahwa Anda memiliki SQLite di semua perangkat Android, sehingga Anda bisa menyimpannya dalam tabel database. Anda juga bisa menggunakan Peta untuk menyimpan pasangan nilai kunci dan membuat serial peta untuk penyimpanan lokal, tetapi ini mungkin terlalu rumit untuk berguna bagi struktur data sederhana.

Mike Yockey
sumber
1

Semua jawaban yang disebutkan di atas sangat bagus ... Saya hanya menambahkan satu yang belum ada yang menyebutkan tentang tetap menggunakan data melalui aktivitas dan itu adalah menggunakan database SQLite android bawaan untuk mempertahankan data yang relevan ... Bahkan Anda dapat menempatkan databaseBantuan dalam status aplikasi dan panggil sesuai kebutuhan di seluruh aktivasi .. Atau buat kelas pembantu dan buat panggilan DB bila diperlukan ... Cukup tambahkan lapisan lain untuk Anda pertimbangkan ... Tapi semua jawaban lain sudah cukup juga .. Benar-benar hanya preferensi

avatar
sumber
1

Berbagi data antara aktivitas misalnya mengirim email setelah login

"email" adalah nama yang dapat digunakan untuk merujuk nilai pada aktivitas yang diminta

1 Kode pada halaman login

Intent openLoginActivity = new Intent(getBaseContext(), Home.class);
    openLoginActivity.putExtra("email", getEmail);

2 kode di halaman beranda

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");
jeff
sumber
1

Dan jika Anda ingin bekerja dengan objek data, dua alat ini sangat penting:

Serializable vs Parcelable

  • Serializable adalah antarmuka penanda, yang menyiratkan pengguna tidak dapat menyusun data sesuai dengan kebutuhan mereka. Jadi ketika objek mengimplementasikan Java Serializable akan secara otomatis membuat cerita bersambung.
  • Parcelable adalah protokol serialisasi sendiri Android. Di Parcelable, pengembang menulis kode khusus untuk marshaling dan unmarshaling. Jadi itu menciptakan lebih sedikit objek sampah dibandingkan dengan Serialisasi
  • Performa Parcelable sangat tinggi bila dibandingkan dengan Serializable karena penerapan kustom-nya. Sangat disarankan untuk menggunakan implantasi Parcelable ketika membuat serial objek di android.

public class User implements Parcelable

periksa lebih lanjut di sini

Diego Venâncio
sumber