Aplikasi tidak selalu terdiri dari satu layar. Misalnya, kami telah membuat sangat program yang bermanfaat dan pengguna ingin tahu siapa penulisnya. Dia mengklik tombol "Tentang" dan membuka layar baru di mana ada informasi berguna tentang versi program, penulis, alamat situs, berapa banyak kucing yang dimiliki penulis, dll. Pikirkan layar aktivitas sebagai halaman web dengan tautan ke halaman lain. Jika Anda melihat kode dalam file MainActivity.java dari pelajaran sebelumnya, Anda akan melihat bahwa kelas kami Aktifitas utama juga berlaku untuk Aktivitas(atau ahli warisnya) atau, lebih tepatnya, diwarisi darinya.
MainActivity kelas publik memperluas AppCompatActivity
Seperti yang Anda duga, kita harus membuat kelas baru yang mungkin terlihat seperti Aktifitas utama dan kemudian entah bagaimana beralih ke klik tombol.
Untuk percobaan, kami akan mengambil program dari pelajaran pertama dan menggunakan tombol untuk percobaan (atau buat proyek baru dengan satu tombol di layar). Selanjutnya, mari kita buat bentuk baru menampilkan informasi berguna. Sebagai contoh, mari kita tunjukkan kepada pengguna apa yang dilakukan kucing saat ia bergerak ke kiri dan ke kanan. Setuju, itu sangat informasi penting, yang memberikan kunci untuk mengungkap alam semesta.
Kami akan membuat aktivitas baru secara manual, meskipun studio memiliki template yang sudah jadi. Tetapi tidak ada yang rumit dan untuk pemahaman yang lebih baik akan berguna untuk melakukan semuanya dengan tangan.
Mari buat file markup XML baru activity_about.xml dalam folder res/tata letak. Klik kanan pada folder tata letak dan pilih dari menu konteks Baru | Tata letak file sumber daya. Sebuah kotak dialog akan muncul. Masukkan nama file di kolom pertama aktivitas_tentang. Yang kedua, Anda harus memasukkan elemen root. Secara default ada di sana Tata Letak Batasan. Hapus teks dan masukkan tampilan gulir. Memasukkan beberapa karakter sudah cukup bagi studio untuk menyarankan opsi yang sudah jadi, Anda dapat langsung menekan Enter tanpa menunggu input penuh kata:
Kami mendapatkan kosong yang sesuai, di mana kami memasukkan elemen tampilan teks.
Informasi akan diambil dari sumber daya, yaitu dari sumber daya string about_text. Sekarang disorot dengan warna merah, menandakan tidak adanya informasi. bisa ditekan Alt+Enter dan masukkan teks di kotak dialog. Tetapi untuk contoh kita, metode ini tidak akan berfungsi, karena teks kita akan menjadi multi-baris, menggunakan karakter kontrol. Jadi mari kita lakukan secara berbeda. Ayo buka filenya res/values/strings.xml dan masukkan teks berikut secara manual:
Kami menggunakan tag pemformatan teks HTML paling sederhana seperti , , . Untuk contoh kita, cukup dengan menebalkan kata-kata yang mengacu pada kucing dan arah gerakan. Untuk menerjemahkan teks menjadi garis baru menggunakan simbol \n. Mari tambahkan sumber string lain untuk judul layar baru:
Dipahami dengan markup. Selanjutnya, Anda perlu membuat kelas untuk jendela TentangAktivitas.java. Pilih dari menu berkas | Baru | kelas jawa dan isi kolom yang diperlukan. Pada awalnya, cukup untuk menentukan nama saja. Kemudian berurusan dengan bidang lain.
Ayo siapkan persiapannya.
Sekarang kelas hampir kosong. Mari tambahkan kode secara manual. Kelas harus mewarisi dari kelas abstrak Aktivitas atau kerabatnya Aktivitas Fragmen, AppCompatActivity dll. menambahkan memperluas Aktivitas. Kelas aktivitas harus memiliki metode diBuat(). Letakkan kursor mouse di dalam kelas dan pilih dari menu kode | Ganti Metode(Ctrl+O). Di kotak dialog, kami mencari kelas yang diinginkan, Anda dapat mengetikkan karakter pertama pada keyboard untuk pencarian Cepat. Dalam metode yang dibuat, Anda perlu memanggil metode setContentView(), yang akan memuat markup yang telah disiapkan di layar. Kami akan memiliki opsi seperti itu.
Paket en.alexanderklimov.helloworld; impor android.app.Activity; impor android.os.Bundle; /** * Dibuat oleh Alexander Klimov pada 12/01/2014. */ public class AboutActivity memperluas Aktivitas ( @Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Sekarang hal yang paling penting dimulai. Tugas kita adalah pindah ke layar baru saat tombol diklik di layar pertama. Ayo kembali ke kelas Aktifitas utama. Mari kita tulis handler klik tombol:
Public void onClick(View view) ( Intent intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); )
Di sini saya menggunakan metode penanganan klik tombol yang dijelaskan dalam pelajaran.
Untuk memulai layar baru, Anda perlu membuat instance kelas Maksud dan tentukan kelas saat ini di parameter pertama, dan kelas untuk transisi di parameter kedua, kami memiliki ini TentangAktivitas. Setelah itu, metode ini disebut mulaiAktivitas(), yang meluncurkan layar baru.
Jika sekarang Anda mencoba menguji aplikasi di emulator, Anda akan menerima pesan kesalahan. Apa yang kita lakukan salah? Kami melewatkan satu langkah penting. Anda harus mendaftar yang baru Aktivitas dalam manifes AndroidManifest.xml. Temukan file ini di proyek Anda dan klik dua kali di atasnya. Jendela pengeditan file akan terbuka. Tambahkan tag baru
Di sinilah sumber daya string berguna about_title. Jalankan aplikasi, klik tombol dan dapatkan jendelanya Tentang program. Jadi, kami belajar cara membuat jendela baru dan memanggilnya dengan mengklik tombol. Dan program mega-nyaman telah muncul untuk kami - sekarang akan selalu ada petunjuk di tangan apa yang dilakukan kucing ketika ia pergi ke kiri.
Sekali lagi, saya menarik perhatian Anda pada fakta bahwa kelas aktivitas yang dibuat kedua harus diwarisi dari kelas Aktivitas atau serupa ( DaftarAktivitas dll.), memiliki file markup XML (jika diperlukan) dan ditulis dalam manifes.
Setelah memanggil metode mulaiAktivitas() aktivitas baru akan dimulai (dalam hal ini TentangAktivitas), itu akan menjadi terlihat dan pindah ke bagian atas tumpukan yang berisi komponen yang sedang berjalan. Saat memanggil metode menyelesaikan() dari aktivitas baru (atau ketika tombol spasi mundur perangkat keras ditekan) aktivitas tersebut akan ditutup dan dihapus dari tumpukan. Pengembang juga dapat menavigasi ke aktivitas sebelumnya (atau lainnya) menggunakan metode yang sama mulaiAktivitas().
Membuat layar ketiga - cara untuk malas
Programmer, seperti kucing, adalah makhluk yang malas. Selalu ingat bahwa untuk aktivitas Anda perlu membuat markup dan kelas yang diwarisi dari Aktivitas, dan kemudian jangan lupa untuk mendaftarkan kelas di manifes - oh well, apa-apaan ini.
Dalam hal ini, pilih dari menu berkas | Baru | aktivitas | aktivitas dasar(atau pola lainnya). Selanjutnya, jendela yang sudah dikenal untuk membuat aktivitas baru akan muncul. Isi bidang yang diperlukan.
Klik pada tombol Menyelesaikan dan aktivitas akan siap. Untuk memverifikasi ini, buka file manifes dan periksa entri baru. Saya tidak berbicara tentang file kelas dan markup, mereka akan muncul di depan Anda.
Tambahkan sendiri tombol baru di layar aktivitas utama dan tulis kode untuk menavigasi ke aktivitas yang dibuat.
Pada awalnya, saya menyarankan Anda untuk secara manual membuat semua komponen yang diperlukan untuk aktivitas baru untuk memahami hubungan antara kelas, markup, dan manifes. Dan ketika Anda mendapatkannya, Anda dapat menggunakan wizard pembuatan aktivitas untuk mempercepatnya.
Melewati data antar aktivitas
Kami menggunakan contoh paling sederhana untuk memanggil layar aktivitas lain. Terkadang diperlukan tidak hanya untuk memanggil layar baru, tetapi juga untuk mentransfer data ke sana. Misalnya, nama pengguna. Dalam hal ini, Anda perlu menggunakan area khusus data tambahan, yang dimiliki kelas Maksud.
Wilayah data tambahan adalah daftar pasangan kunci/nilai, yang diteruskan bersama dengan maksud. String digunakan sebagai kunci, dan untuk nilai Anda dapat menggunakan tipe data primitif, array primitif, objek kelas bundel dan sebagainya.
Untuk meneruskan data ke aktivitas lain, gunakan metode menempatkan Ekstra():
Intent.putExtra("Kunci", "Nilai");
Aktivitas penerima harus memanggil beberapa metode yang sesuai: dapatkanIntEkstra(), dapatkanStringEkstra() dll.:
Int hitung = getIntent().getIntExtra("nama", 0);
Mari kita buat ulang contoh sebelumnya. Kami sudah memiliki tiga kegiatan. Aktivitas pertama akan memiliki dua bidang teks dan sebuah tombol. Penampilan mungkin sebagai berikut:
Pada kegiatan kedua Aktivitas Kedua mengatur elemen tampilan teks, di mana kami akan menampilkan teks yang diterima dari aktivitas pertama. Mari kita tulis kode berikut untuk metodenya diBuat() pada kegiatan kedua.
@Override protected void onCreate(Bundle storedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "Animal"; String gift = "donut hole"; TextView infoTextView = (TextView)findViewById( R .id.textViewInfo); infoTextView.setText(user + " , Anda diberi " + hadiah); )
Jika sekarang kita menjalankan program dan cukup memanggil jendela kedua, seperti yang dijelaskan di bagian pertama artikel, kita akan melihat prasasti default ZhYvotnoe, kamu diberi lubang donat. Setuju, sangat disayangkan menerima pesan seperti itu.
Kami memperbaiki situasi. Tambahkan kode ke aktivitas pertama:
Public void onClick(View view) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (EditText) findViewById(R.id.editTextGift); Intent intent = new Intent(MainActivity.this, SecondActivity. class); // mendorong teks dari bidang teks pertama ke dalam maksud kunci nama pengguna.putExtra("nama pengguna", userEditText.getText().toString()); // mendorong teks dari bidang teks kedua ke dalam kunci hadiah maksud.putExtra("hadiah", giftEditText.getText().toString()); startActivity(maksud); )
Kami ditempatkan di wadah objek khusus Maksud dua kunci dengan nilai yang diambil dari bidang teks. Ketika pengguna memasukkan data ke dalam bidang teks, mereka akan jatuh ke dalam wadah ini dan akan diteruskan ke aktivitas kedua.
Aktivitas kedua harus siap menerima pesan dengan hangat sebagai berikut (disorot dengan huruf tebal).
// Nilai default String user = "LIFE"; String hadiah = "lubang donat"; pengguna = getIntent().getExtras().getString("nama pengguna"); hadiah = getIntent().getExtras().getString("hadiah"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(pengguna + " , Anda diberi " + hadiah);
Sekarang pesan itu tidak terlihat begitu menyinggung, tetapi bahkan menyenangkan bagi sebagian orang. Dalam contoh kompleks, diinginkan untuk menambahkan validasi selama pemrosesan data. Ada situasi ketika Anda memulai aktivitas kedua dengan data kosong seperti batal, yang dapat merusak aplikasi.
Dalam kasus kami, kami tahu bahwa kami sedang menunggu nilai string, sehingga kode dapat ditulis ulang seperti ini:
maksud maksud = getIntent(); pengguna = maksud.getStringExtra("nama pengguna");
Pengguna = getIntent().getStringExtra("nama pengguna");
Program ini memiliki kelemahan - tidak jelas dari siapa kami menerima salam. Monyet yang sopan tidak akan menerima hadiah dari sumber anonim. Jadi untuk pekerjaan rumah, tambahkan bidang teks lain untuk memasukkan nama pengguna yang mengirim pesan.
Google menyarankan untuk menggunakan format kunci berikut: nama paket Anda sebagai awalan, diikuti dengan kunci itu sendiri. Dalam hal ini, Anda dapat yakin bahwa kuncinya unik saat berinteraksi dengan aplikasi lain. Kira-kira seperti ini:
String statis publik terakhir USER = "ru.alexanderklimov.myapp.USER";
Siapa yang membingkai kucing Vaska - kami mendapatkan hasilnya kembali
Tidak selalu cukup hanya dengan melewatkan data ke aktivitas lain. Terkadang Anda perlu mendapatkan informasi kembali dari aktivitas lain saat aktivitas tersebut ditutup. Jika sebelumnya kita menggunakan metode startActivity(Niat niat), maka ada metode terkait startActivityForResult(Intent intent, int RequestCode). Perbedaan antara metode terletak pada parameter tambahan Kode permintaan. Ini pada dasarnya hanya bilangan bulat yang dapat Anda pikirkan tentang diri Anda sendiri. Penting untuk membedakan dari siapa hasilnya datang. Katakanlah Anda memiliki lima layar tambahan dan Anda menetapkan nilai dari 1 hingga 5 untuk mereka, dan dari kode ini Anda dapat menentukan hasil siapa yang perlu Anda proses. Anda dapat menggunakan nilai -1, maka itu akan setara dengan memanggil metode mulaiAktivitas(), yaitu kita tidak akan mendapatkan hasil apapun.
Jika Anda menggunakan metode startActivityForResult(), maka Anda perlu mengganti metode dalam kode untuk menerima hasilnya padaActivityResult() dan memproses hasilnya. Bingung? Mari kita lihat sebuah contoh.
Katakanlah Anda seorang detektif. Informasi diterima bahwa dua potong sosis dan produk lainnya dicuri dari meja orang berpengaruh di restoran. Kecurigaan jatuh pada tiga tersangka - seekor gagak, seekor anjing dan kucing Vaska.
Salah satu pengunjung memberikan serangkaian foto dari iPhone pontonnya:
Ada juga keterangan dari saksi lain: Dan Vaska mendengarkan dan makan.
Kami membuat proyek baru Sherlock dengan dua kegiatan. Pada layar pertama akan ada tombol untuk beralih ke layar kedua dan label teks yang akan menampilkan nama pencuri.
Layar kedua akan memiliki sekelompok tombol radio:
Karena kita akan menunggu respon dari layar kedua, kita perlu menggunakan metode startActivityForResult() pada layar pertama di mana kita akan melewatkan variabel CHOOSE_THIEF sebagai parameter Kode permintaan.
static final private int CHOOSE_THIEF = 0; public void onClick(View v) ( Intent questionIntent = new Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
Lihat kodenya. Saat tombol diklik, kita akan bekerja dengan layar kedua Pilih Aktivitas dan luncurkan layar kedua menunggu hasilnya.
Kami melewati layar kedua dan kami akan menulis kode untuk aktivitas kedua.
String statis terakhir publik THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(View v) ( Intent answerIntent = new Intent(); switch (v.getId()) ( case R.id.radioDog: answerIntent.putExtra(THIEF, "Fucking Dog"); break; case R.id .radioCrow: answerIntent.putExtra(THIEF, "Crow"); break; case R.id.radioCat: answerIntent.putExtra(THIEF, "Przewalski's Horse"); break; default: break; ) setResult(RESULT_OK, answerIntent); selesai (); )
Semuanya sederhana di sini, ketika detektif memilih nama penjahat, maka melalui metode menempatkan Ekstra() kami memberikan nama kunci dan nilainya.
Untuk kenyamanan, setelah pemilihan, kami segera menutup jendela kedua dan memberikan nilai sebelum menutup RESULT_OK untuk memperjelas bahwa pilihan telah dibuat. Jika pengguna menutup layar melalui tombol Kembali, nilainya akan diteruskan RESULT_CANCELED.
metode hasilset() mengambil dua parameter: kode yang dihasilkan dan hasil itu sendiri, direpresentasikan sebagai maksud. Kode yang dihasilkan mengatakan dengan hasil apa aktivitas itu berakhir, sebagai aturan, itu adalah Aktivitas.RESULT_OK, atau Aktivitas.RESULT_CANCELED. Dalam beberapa kasus, Anda perlu menggunakan kode pengembalian Anda sendiri untuk menangani opsi khusus aplikasi. metode hasilset() mendukung nilai integer apa pun.
Jika Anda akan mengirimkan data secara eksplisit melalui tombol, maka akan lebih baik untuk menambahkan metode menyelesaikan() untuk menutup aktivitas kedua karena tidak perlu. Jika transisi terjadi melalui tombol Kembali, maka ini tidak perlu.
Jika aktivitas ditutup oleh pengguna saat tombol kembali perangkat keras ditekan, atau jika metode menyelesaikan() dipanggil sebelum metode hasilset(), kode yang dihasilkan akan disetel ke RESULT_CANCELED dan maksud yang dikembalikan akan menunjukkan nilainya batal.
Kami kembali ke layar pertama. Layar pertama sedang menunggu respons dari layar kedua, jadi Anda perlu menambahkan metode ke kode padaActivityResult().
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) ( super.onActivityResult(requestCode, resultCode, data); TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); if (requestCode == CHOOSE_THIEF) ( if (resultCode == RESULT_OK) ( String nama pencuri = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else ( infoTextView.setText(""); // hapus teks ) ) )
Metode ini mengharapkan data yang masuk dengan kode CHOOSE_THIEF, dan jika data tersebut tiba, maka ekstrak nilainya dari kunci PilihAktivitas.THIEF menggunakan metode dapatkanStringEkstra. Kami menampilkan nilai yang dihasilkan ke tampilan teks(variabel infoTextView). Jika kita kembali ke layar melalui tombol Kembali, maka kita cukup menghapus teksnya.
Saat aktivitas anak ditutup di dalam komponen induk, pawang akan aktif padaActivityResult(). Pawang padaActivityResult() mengambil beberapa parameter.
- Kode permintaan. Kode yang digunakan untuk meluncurkan aktivitas yang mengembalikan hasilnya
- Kode yang dihasilkan. Kode hasil yang disetel oleh aktivitas anak yang menunjukkan bagaimana aktivitas anak berakhir. Itu bisa berupa nilai integer apa pun, tetapi biasanya juga Aktivitas.RESULT_OK, atau Aktivitas.RESULT_CANCELED
- Data. Intent yang digunakan untuk mengemas data yang dikembalikan. Bergantung pada tujuan aktivitas anak, ini mungkin menyertakan jalur URI yang mewakili bagian konten yang dipilih. Atau (atau sebagai tambahan), aktivitas anak dapat mengembalikan informasi sebagai nilai sederhana yang dibungkus dalam parameter maksud tambahan
Jika aktivitas anak berakhir secara tidak terduga, atau jika tidak ada kode hasil yang ditentukan sebelum menutupnya, parameter ini akan menjadi sama dengan Aktivitas.RESULT_CANCELED.
Kami memulai proyek, klik tombol dan pergi ke layar kedua. Di sana kami memilih salah satu opsi. Jika Anda memilih burung gagak, layar akan tertutup dan nama penjahat akan ditampilkan di layar pertama. Jika Anda memilih seekor anjing, namanya akan ditampilkan.
Omong-omong, jika Anda memilih kucing, namanya tidak akan ditampilkan! Periksa dan lihat sendiri. Anda akan bertanya mengapa? Watson dasar! Pelaku tidak memperhitungkan satu detail penting. Restoran itu diawasi dari kamera video, dan rekaman itu menunjukkan siapa yang sebenarnya mencuri sosis dan menjebak kucing itu. Vaska, tunggu!
P.S. Jika pada awalnya sesuatu tampak tidak dapat dipahami, maka dengan banyak latihan akan menjadi jelas. Melewati data antar layar adalah hal biasa dalam aplikasi, dan Anda akan mempelajari contoh lebih dari sekali.
P.P.S. Ikan terbaik adalah sosis. Mengetahui kelemahan ini, tidak sulit untuk menjebak kucing.
Menggunakan filter
Dalam artikel tersebut, saya menunjukkan cara umum untuk beralih ke aktivitas lain, ketika dalam metode mulaiAktivitas() kelas saat ini dan kelas transisi ditunjukkan. Omong-omong, kelas aktivitas tidak harus menjadi bagian dari aplikasi Anda. Jika Anda mengetahui nama kelas dari aplikasi lain, Anda juga dapat beralih ke itu. Tetapi Anda dapat beralih ke aktivitas lain dengan cara yang berbeda.
Kurang umum dalam praktik, tetapi bermanfaat. Katakanlah Anda sudah memiliki aktivitas kedua. Dalam manifes, tambahkan filter khusus ke dalamnya:
Dan kami meluncurkan aktivitas kedua melalui klik tombol dengan cara ini.
Public void onClick(View view) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity"); )
Mari kita ganti string panjang dengan konstanta.
String final statis publik ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick(View view) ( startActivity(new Intent(ACTION_SECOND_ACTIVITY)); )
Jadi apa yang telah kita lakukan. Untuk aktivitas kedua, kami telah mendaftarkan filter dan menentukan nama untuk tindakan dalam atribut android:nama. Untuk kenyamanan, saya hanya memasukkan nama lengkap aktivitas dengan nama paket. Konstruktor kelas Maksud memiliki beberapa versi kelebihan beban. Dalam satu versi, Anda dapat menentukan string untuk tindakan. Kami menunjukkan tindakan yang kami buat, yang terdaftar di aktivitas kedua. Sistem melihat manifes dari semua aplikasi yang diinstal selama operasi. Saat mencari kecocokan, sistem menemukan filter kami dan meluncurkan aktivitas yang diinginkan.
Dengan prinsip yang sama, Anda dapat memulai aktivitas lain. Lihatlah sebuah contoh. Jika Anda menyalin contoh ke diri Anda sendiri dan melihat dokumentasi untuk android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, Anda akan melihat bahwa kode ini sesuai dengan konstanta string public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". Bandingkan dengan kode kami. Anda dapat berasumsi bahwa aktivitas pengaturan untuk mode offline memiliki baris ini di filter.
Filter nama kategori android.intent.category.DEFAULT memberitahu sistem untuk mengambil tindakan default, yaitu memulai aktivitas. Ada nama lain yang belum menarik bagi kami.
Dan sekarang pertanyaan yang rumit. Apa yang terjadi jika Anda membuat aktivitas lain dan menentukan filter yang sama dengan aktivitas kedua? Dan mari kita periksa. Buat aktivitas ketiga untuk Anda sendiri dan salin blok dengan filter dari aktivitas kedua ke dalamnya.
Kami mengklik tombol di aktivitas pertama. Sistem akan meminta Anda untuk memilih opsi yang diinginkan.
Jika Anda memilih item SELALU maka lain kali Anda tidak perlu memilih. Untuk mengatur ulang pilihan, buka properti aplikasi di Pengaturan dan temukan tombol hapus default.
Meluncurkan aktivitas dengan namanya
Dalam konstruktor Maksud Parameter kedua adalah kelas. Tapi mari kita asumsikan bahwa ada semacam database di mana nama aktivitas ditunjukkan dan kita perlu meluncurkan aktivitas yang diinginkan dengan namanya. Kita bisa mendapatkan kelas itu sendiri berdasarkan variabel string dan memulai aktivitas.
Try ( // Nama lengkap kelas aktivitas String activityName = "ru.alexanderklimov.testapplication.SecondActivity"; // dapatkan objek Kelas Kelas>myClass = Kelas.untukNama(NamaAktivitas); Intent intent = new Intent(this, myClass); startActivity(niat); ) tangkap (ClassNotFoundException e) ( e.printStackTrace(); )
Entah bagaimana saya mendapat tugas mentransfer data dari layanan ke aktivitas. Pencarian solusi di SDK standar dimulai, tetapi karena tidak ada waktu, saya membuat keputusan yang buruk dalam bentuk menggunakan database. Tetapi pertanyaannya terbuka dan setelah beberapa saat saya menemukan cara yang lebih benar yaitu di SDK - menggunakan kelas Message, Handler, Messenger.
Ide
Kita perlu mentransfer data dari aktivitas ke layanan dan sebaliknya. Bagaimana kita bisa melakukannya? Untuk mengatasi masalah kita, kita sudah memiliki semua yang kita butuhkan. Yang diperlukan hanyalah mengikat layanan ke aktivitas menggunakan bindService, meneruskan parameter yang diperlukan, dan sedikit keajaiban dalam bentuk penggunaan kelas Pesan. Dan keajaibannya adalah menggunakan variabel instan Message dan khususnya replyTo. Kita memerlukan variabel ini agar kita dapat mengakses instance layanan Messanger dari aktivitas dan dalam layanan ke instance Messanger dari aktivitas tersebut. Sebenarnya, tidak sesederhana itu. Setidaknya untuk pikiran saya yang tidak terlalu berbakat. Sebagian saya hanya meningkatkan dokumentasi yang sudah ada - Layanan Juga, ada contoh bagus di StackOverflow. Bagaimanapun, saya harap artikel itu bermanfaat bagi setidaknya seseorang dan saya tidak bekerja dengan sia-sia.
Contoh
Sebagai contoh, kami akan mengimplementasikan layanan yang akan menambah dan mengurangi nilai penghitung dan mengembalikan hasilnya dalam suatu aktivitas, dalam TextView. Saya akan menghilangkan kode tata letak, karena ada dua tombol dan bidang teks - semuanya sederhana.
Penerapan
Berikut kode aktivasi lengkapnya:
MainActivity kelas publik memperluas Aktivitas ( public static final String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; final utusan utusan= Messenger baru (IncomingHandler baru()); Messenger ke ServiceMessenger; @Override public void onCreate(Bundle storedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); testTxt = (TextView)findViewById(R.id.test_txt); bindService(niat baru(ini, TestService.class ), (testServConn = new TestServiceConnection()), Context.BIND_AUTO_CREATE); ) @Override public void onDestroy()( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(View button)( Message msg = Message. dapatkan(null, TestService.COUNT_PLUS); msg.replyTo = messenger; coba ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(View button)( Message msg = Message.obtain(null, TestService.COUNT_MINUS); msg.replyTo = messenger; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) private class IncomingHandler extends Handler ( @Override public void handleMessage(Pesan pesan)( switch (pesan.what) ( kasus TestServic e.GET_COUNT: Log.d(TAG, "(aktivitas)...dapatkan hitungan"); testTxt.setText(""+msg.arg1); merusak; ) ) ) kelas pribadi TestServiceConnection mengimplementasikan ServiceConnection ( @Override public void onServiceConnected(Nama ComponentName, layanan IBinder) ( toServiceMessenger = new Messenger(service); //send nilai awal counter Pesan pesan = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = utusan; msg.arg1 = 0; // coba counter kami ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName name) ( ) ) )
Mari saya jelaskan. Saat membuat aktivitas, kami segera mengikat ke layanan dengan mengimplementasikan antarmuka ServiceConnection dan mengirim pesan ke layanan "mengatur nilai penghitung" di dalamnya, meneruskan nol dan membuat toServiceMessanger, meneruskan antarmuka IBinder ke konstruktor. Omong-omong, instance ini harus dikembalikan dalam layanan, jika tidak, akan ada NPE. Dengan bantuan kelas ini, kami mengirim pesan ke layanan. Dan inilah keajaiban - dalam variabel replyTo kami menyimpan instance Messenger kami yang lain - yang menerima respons dari server dan melaluinya komunikasi dengan aktivitas akan dilakukan.
Untuk menerima pesan dari layanan, kami menggunakan Handler kami dan cukup mencari variabel yang kami butuhkan dan melakukan tindakan pada variabel tersebut. Pada klik tombol (metode countIncrClick, countDecrClick) kami mengirim permintaan ke layanan, menentukan tindakan yang diinginkan dalam variabel msg.what.
Paket com.example.servicetest; impor android.app.Service; impor android.content.*; impor android.os.*; impor android.os.Process; impor android.util.Log; TestService kelas publik memperluas Layanan ( public static final COUNT_PLUS = 1; public static final COUNT_MINUS = 2; public static final int SET_COUNT = 0; public static final int GET_COUNT = 3; int count = 0; IncomingHandler inHandler; Messenger messenger; Messenger toActivityMessenger; @Override public void onCreate()( super.onCreate(); HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); inHandler = new IncomingHandler(thread.getLooper()); messenger = new Messenger(inHandler); ) @Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); ) @Override public int onStartCommand(Intent intent, int flags, int startId) ( return START_STICKY; ) //message handler aktivitas kelas pribadi IncomingHandler extends Handler ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Pesan pesan)( //super.handleMessage(msg); toActivityMess enger = msg.replyTo; switch (msg.what) ( case SET_COUNT: count = msg.arg1; Log.d(MainActivity.TAG, "(service)...set count"); break; case COUNT_PLUS: count++; Log.d(MainActivity.TAG , "(service)...count plus"); break; case COUNT_MINUS: Log.d(MainActivity.TAG, "(service)...count minus"); count--; break; ) //mengirim penghitung nilai dalam Pesan Aktivitas outMsg = Message.obtain(inHandler, GET_COUNT); outMsg.arg1 = hitung; outMsg.replyTo = pengirim pesan; coba ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) ) )
Semua dengan analogi dengan logika dalam aktivitas. Saya bahkan tidak tahu apakah saya perlu menjelaskan sesuatu. Satu-satunya poin adalah saya segera mengirim permintaan kembali ke aktivitas di handleMessage, menggunakan variabel replyTo ajaib untuk ini dan mengeluarkan Messenger yang diinginkan di atas. Dan poin kedua yang sudah saya sebutkan adalah:
@Override public IBinder onBind(Intent arg0) ( kembalikan messanger.getBinder(); )
tanpanya semuanya akan jatuh. Instance antarmuka inilah yang akan diteruskan ke ServiceConnection
Kesimpulan
Semua seutuhnya. Contoh interaksi yang dibuat-buat antara aktivitas dan layanan. Tampaknya bagi saya interaksi yang agak non-sepele, meskipun mungkin tampak berbeda bagi seseorang.
Pertanyaan, klarifikasi, dll. Mungkin ada ketidakakuratan tentang aspek apa pun, jadi jangan ragu untuk menulis dan mengoreksi.
Semoga postingan ini bermanfaat bagi para pembaca.
Halo.
Penting untuk mentransfer data yang diterima melalui UART ke Aktivitas. Ini dapat dilakukan dengan membuat utas di Aktivitas untuk mengatur loop while (!isInterrupted()) dan membaca data dari buffer UART. Setelah itu, dengan memanggil utas UI Aktivitas - MainActivity.this.runOnUiThread(new Runnable() , lakukan tindakan yang diperlukan dengan Aktivitas ini. Tetapi jika kita memanggil Aktivitas lain dari Aktivitas utama, maka utas terorganisir tidak mengizinkan lewat data ke Aktivitas yang baru dibuat Jika saya memahami dengan benar bahwa agar data dari aliran ditransfer ke Aktivitas apa pun, aliran harus dibuat bukan di Aktivitas, tetapi di Layanan.
Pertanyaan: data datang melalui UART, di utas (yang dibuat di Layanan) perlu mentransfer data ke Aktivitas, yang sekarang aktif, bagaimana ini bisa dilakukan dan apakah itu dilakukan sama sekali?
1 jawaban
Di setiap Aktivitas, buat Handler. Dalam metode onResume() dari Aktivitas ini, bindService() sudah selesai. Di sana, salah satu parameternya adalah antarmuka ServiceConnection. Terapkan dengan setidaknya Aktivitas yang sama. Terapkan metode onServiceConnected() di dalamnya. Dalam panggilan balik ini, Layanan itu sendiri hadir sebagai salah satu parameter. Jadi panggil Layanan ini metode setHandler() Anda sendiri. Berikan Handler yang ada di Aktivitas saat ini. Tapi membuang data yang masuk melalui UART ke Service pada Handler ini. Omong-omong, Handler secara tradisional berjalan di utas utama, jadi runOnUiThread tidak perlu dieksekusi.