Kemahiran perkhidmatan


Pengenalan kepada bahagian ini:

Dalam bahagian ini, kami terus mengkaji komponen Perkhidmatan Dalam bahagian ini, kami akan mempelajari beberapa komunikasi silang proses AIDL dalam Android Konsep ini tidak masuk jauh ke dalam tahap kod sumber Hanya tahu apa itu dan tahu cara menggunakannya! Mulakan bahagian ini~ Bahagian ini sepadan dengan dokumen rasmi: Pengikat


1 Pengenalan pertama kepada mekanisme Pengikat


1) Apakah IBinder dan pengikat?

Mari kita lihat apa yang dinyatakan oleh dokumentasi rasmi:

1.png

Terjemahan Cina:

IBinder ialah antara muka asas untuk objek jauh Ia adalah bahagian teras mekanisme panggilan jauh ringan yang direka untuk prestasi tinggi. Tetapi dia Bukan sahaja untuk panggilan jauh, tetapi juga untuk panggilan dalam proses. Antara muka ini mentakrifkan protokol untuk interaksi dengan objek jauh. Tetapi tidak melaksanakannya secara langsung Antara muka ini, sebaliknya, mewarisi (lanjutkan)Pengikat.

API utama IBinder ialah transact(), dan API yang sepadan ialah Binder.onTransact(). Melalui bekas, anda boleh Menghantar panggilan ke objek IBinder jauh, yang membolehkan objek jauh anda membalas panggilan masuk. API IBinder semuanya Segerak dilaksanakan, seperti transact() sehingga kaedah Binder.onTransact() pihak satu lagi dipanggil. Dipulangkan kemudian. Ini sudah pasti berlaku apabila panggilan berlaku dalam proses, dan apabila ia adalah antara proses, dengan bantuan IPC, kesan yang sama dicapai.

Data yang dihantar melalui transact() ialah Parcel sebagai tambahan kepada data, ia juga mengandungi Beberapa metadata yang menerangkan kandungannya. Metadata digunakan untuk mengurus rujukan kepada objek IBinder supaya penimbal boleh dialihkan dari satu proses ke proses yang lain. Simpan rujukan ini apabila pergi ke proses lain. Ini memastikan bahawa apabila IBinder ditulis kepada Petak dan dihantar ke proses lain, Jika proses lain menghantar rujukan kepada IBinder yang sama kembali ke proses asal, maka proses asal boleh menerima yang dihantar Rujukan kepada IBinder itu. Mekanisme ini membolehkan IBinder dan Binder diurus merentas proses seperti pengecam unik.

Sistem ini mengekalkan kumpulan benang untuk setiap proses untuk menyimpan benang interaktif. Benang interaktif ini digunakan untuk menghantar semua IPC yang dihantar daripada proses lain panggil. Contohnya: apabila IPC dihantar dari proses A ke proses B, benang panggilan dalam A (ini tidak sepatutnya berada dalam kumpulan benang) disekat. Dalam transact(). Satu utas dalam kumpulan utas interaktif dalam proses B menerima panggilan ini Binder.onTransact() dan mengembalikan Parcel sebagai hasilnya selepas selesai. Kemudian benang menunggu dalam proses A Pelaksanaan boleh diteruskan selepas menerima Bungkusan yang dipulangkan. Malah, proses lain kelihatan seperti benang proses semasa, Tetapi ia tidak dicipta oleh proses semasa.

Mekanisme Pengikat juga menyokong panggilan rekursif antara proses. Sebagai contoh, proses A melaksanakan panggilan transact() IBinder sendiri untuk memproses B. Binder dan proses B menggunakan transact() dalam Binder.onTransact() untuk memulakan panggilan untuk memproses A, kemudian memproses A Semasa menunggu panggilan yang dikeluarkan untuk dipulangkan, ia juga akan bertindak balas untuk memproses transact() B dengan Binder.onTransact(). Ringkasnya, hasil Binder ialah kami merasakan bahawa tiada perbezaan antara panggilan silang proses dan panggilan dalam proses.

Apabila mengendalikan objek jauh, anda selalunya perlu menyemak sama ada ia sah Terdapat tiga kaedah yang boleh anda gunakan:

  • 1 Kaedah transaksi() akan membuang apabila proses di mana. IBinder terletak tidak wujud RemoteException berlaku.
  • 2 Jika proses sasaran tidak wujud, maka false dikembalikan apabila memanggil pingBinder().
  • 3 Anda boleh menggunakan kaedah linkToDeath() untuk mendaftarkan IBinder.DeathRecipient dengan IBinder. Dipanggil apabila proses yang diwakili oleh IBinder keluar.

PS: Terjemahan bahasa Cina dipetik daripada: Pembangunan Android: Apakah itu IBinder

Baiklah, saya rasa anda mungkin keliru selepas membaca senarai ini of things Dalam kabus, berikut ialah ringkasan ringkas:

IBinder ialah antara muka untuk komunikasi antara proses yang disediakan oleh Android, dan kami biasanya tidak melaksanakan antara muka ini secara langsung, Sebaliknya, komunikasi antara proses dicapai dengan mewarisi kelas Binder! Ia adalah satu cara untuk melaksanakan IPC (komunikasi antara proses) dalam Android!


2) Analisis ringkas mekanisme Pengikat

2.png

Mekanisme Pengikat dalam Android terdiri daripada satu siri komponen sistem: Klien, Pelayan, Pengurus Perkhidmatan dan pemandu Pengikat

Anggaran proses panggilan adalah seperti berikut, Pengurus Perkhidmatan lebih rumit dan tidak akan dikaji secara terperinci di sini.

Analisis proses:

-> Apabila Pelanggan memanggil kaedah dalam antara muka proksi, kaedah antara muka proksi akan Parameter yang diluluskan oleh Klien dibungkus ke dalam objek Parcel;
-> Kemudian antara muka proksi menghantar objek Parcel kepada pemacu Pengikat dalam kernel;; ;
Kemudian Pelayan akan membaca data permintaan dalam Pemacu Pengikat Jika ia dihantar kepada dirinya sendiri, bongkarkan objek Parcel. Proses dan kembalikan keputusan; PS: Kaedah yang ditakrifkan dalam antara muka proksi sepadan dengan kaedah yang ditakrifkan dalam Pelayan. Di samping itu, keseluruhan proses panggilan adalah segerak, iaitu, semasa Pelayan sedang memproses, Pelanggan akan Disekat (dikunci)! Takrifan antara muka proksi yang dinyatakan di sini ialah AIDL
(Bahasa Penerangan Antara Muka Android) yang akan dibincangkan kemudian!


3) Mengapakah Android menggunakan mekanisme Pengikat untuk mencapai komunikasi antara proses?

  1. Kebolehpercayaan: Pada peranti mudah alih, komunikasi berasaskan Pelayan Pelanggan biasanya digunakan untuk mencapai komunikasi dalaman antara Internet dan peranti. Pada masa ini, Linux menyokong IPC termasuk paip tradisional, Sistem V IPC, iaitu baris gilir mesej/memori kongsi/semaphore, dan hanya soket yang menyokong kaedah komunikasi Pelayan-Pelanggan. Sistem Android menyediakan pembangun dengan antara muka berfungsi yang kaya untuk komunikasi antara proses, main balik media, penderia dan penghantaran wayarles. Fungsi ini diuruskan oleh pelayan yang berbeza. Pembangun hanya mengambil berat tentang mewujudkan komunikasi antara klien dan pelayan aplikasi mereka sendiri untuk menggunakan perkhidmatan ini. Tidak syak lagi bahawa jika satu set protokol disediakan di bahagian bawah untuk melaksanakan komunikasi Klien-Pelayan, ia akan meningkatkan kerumitan sistem. Apabila melaksanakan persekitaran yang kompleks ini pada telefon mudah alih dengan sumber terhad, kebolehpercayaan sukar untuk dijamin.
  2. Prestasi penghantaran: Soket digunakan terutamanya untuk komunikasi antara proses merentasi rangkaian dan komunikasi antara proses pada mesin tempatan, tetapi kecekapan penghantaran adalah rendah dan overhed adalah tinggi. Baris gilir mesej dan saluran paip menggunakan kaedah simpan-dan-majukan, iaitu, data mula-mula disalin dari kawasan penimbal penghantar ke kawasan penimbal yang dibuka oleh kernel, dan kemudian disalin dari kawasan penimbal kernel ke kawasan penimbal penerima. Proses ini melibatkan sekurang-kurangnya dua salinan. Walaupun memori yang dikongsi tidak memerlukan penyalinan, kawalannya adalah rumit. Bandingkan bilangan salinan data pelbagai kaedah IPC. Memori dikongsi: 0 kali. Pengikat: 1 kali. Soket/Saluran Paip/Barisan Mesej: 2 kali.
  3. Keselamatan: Android ialah platform terbuka, jadi adalah penting untuk memastikan keselamatan aplikasi. Android memberikan UID/PID kepada setiap aplikasi yang dipasang dan UID proses boleh digunakan untuk mengenal pasti identiti proses. Secara tradisinya, pengguna hanya boleh mengisi UID/PID dalam paket data, yang tidak boleh dipercayai dan mudah dieksploitasi oleh program berniat jahat. Sebaliknya kami memerlukan kernel untuk menambah UID yang boleh dipercayai. Oleh itu, untuk kebolehpercayaan, penghantaran dan keselamatan. Android telah mewujudkan kaedah baharu komunikasi antara proses. ——Dipetik daripada:Pemahaman ringkas tentang mekanisme Binder dalam Android

Sudah tentu, sebagai pembangun junior kami tidak mengambil berat tentang perkara di atas, Binder Mekanisme membawa kita Manfaat paling langsung ialah: Kami tidak perlu mengambil berat tentang cara pelaksanaan asas dilaksanakan Kami hanya perlu menyesuaikan fail antara muka mengikut peraturan AIDL, dan kemudian. panggil kaedah dalam antara muka untuk menyelesaikan dua tugasan komunikasi antara proses!


2. Penjelasan terperinci tentang penggunaan AIDL


1) Apakah itu AIDL?

Hei, kita bercakap tentang istilah IPC tadi, nama penuhnya ialah: komunikasi antara proses, Kerana dalam sistem Android, setiap aplikasi berjalan dalam prosesnya sendiri, data umumnya tidak boleh ditukar terus antara proses. Untuk mencapai proses silang, Android membekalkan kami mekanisme Pengikat yang disebutkan di atas, dan bahasa antara muka yang digunakan oleh mekanisme ini ialah: AIDL (Bahasa Definisi Antara Muka Android adalah sangat mudah, dan ini antara muka Bahasa bukanlah pengaturcaraan sebenarnya Bahasa hanya mentakrifkan antara muka komunikasi antara dua proses! Kod Java yang mematuhi protokol komunikasi dijana oleh Android SDK Alat aidl.exe dalam direktori platform-tools dijana dan fail antara muka yang sepadan dijana dalam direktori :gen, biasanya antara muka: Xxx.java! Antara muka mengandungi kelas dalaman Stub, yang melaksanakan antara muka IBinder dan antara muka komunikasi tersuai. Kelas ini akan digunakan sebagai kelas panggil balik Perkhidmatan jauh - ia melaksanakan antara muka IBinder, jadi ia boleh digunakan sebagai nilai pulangan kaedah onBind() Perkhidmatan!


2) AIDL melaksanakan komunikasi mudah antara dua proses

Sebelum mula menulis fail antara muka AIDL, kita perlu memahami beberapa nota tentang menulis AIDL:

Nota tentang AIDL:

  • Kata nama antara muka perlu sama dengan nama fail aidl
  • Jangan tambah akses di hadapan antara muka dan kaedah pengubah kebenaran : awam, peribadi, dilindungi, dsb., statik akhir tidak boleh digunakan
  • Jenis lalai yang disokong AIDL termasuk Jenis asas Java , String, Senarai, Peta, CharSequence, semua jenis lain adalah Penyata import diperlukan untuk menggunakan jenis tersuai sebagai parameter atau nilai pulangan, jenis tersuai perlu melaksanakan antara muka Boleh. Untuk butiran, sila lihat Melepasi Jenis Data Kompleks
  • Jenis tersuai dan jenis antara muka lain yang dijana oleh AIDL harus diimport secara eksplisit dalam fail perihalan aidl, walaupun dalam kelas dan definisi daripada pakej dalam pakej yang sama.
Selain itu, jika pengkompil yang anda gunakan untuk menulis aidl ialah: Eclipse, sila ambil perhatian: Jangan buat fail baharu secara langsung Dalam kes ini, fail tidak boleh dibuka dan kod tidak boleh ditulis!

① Buat fail txt baharu secara terus, simpan dalam format .aidl selepas menulis, dan kemudian salin ke laluan yang sepadan
② Kerana aidl adalah serupa dengan antara muka, jadi secara langsung antara muka baharu, selepas menulis kandungan, datang ke fail java yang sepadan Ubah suai nama akhiran fail dalam direktori; Jika anda menggunakan Android Studio, tidak seperti Eclipse, jika anda mencipta fail AIDL seperti Eclipse, anda akan dapati Fail XXX.java yang sepadan tidak disusun dan dijana Untuk mencipta AIDL di bawah AS, anda perlu mencipta folder aidl baharu dalam direktori utama dan kemudian mentakrifkan Untuk pakej dengan nama yang sama dengan pakej aidl, akhirnya buat fail aidl, kemudian tekan ctrl + f9 untuk menyusun semula, dan itu sahaja!

3.png

Hasil penyusunan berjaya kedua-dua di atas adalah seperti berikut Anda boleh mencari fail AIDL yang sepadan dalam direktori yang sepadan

4.png5.png<🎜. >


1. Pelayan:

Langkah 1: Buat fail AIDL:

IPerson. aidl

pakej com.jay.aidl;

antara muka IPerson {
String queryPerson(int num);
}

Mari buka IPerson.java dan lihat kod di dalam:

IPerson.java

/*
 * Fail ini dijana secara automatik.  JANGAN UBAHSUAI.
 * Fail asal: C:\Code\ASCode\AIDLServer\app\src\main\aidl\com\jay\aidl\IPerson.aidl
 */
pakej com.jay. aidl;
antara muka awam IPerson melanjutkan android.os.IInterface
{
/** Kelas pelaksanaan IPC sebelah tempatan. */
kelas abstrak statik awam Stub melanjutkan android.os.Binder melaksanakan com.jay.aidl IPPerson
{
private static final java.lang.String DESCRIPTOR = "com.jay.aidl.IPerson";
/** Bina stub di lampirkannya ke antara muka. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Hantar objek IBinder ke antara com.jay.aidl.IPerson ,
 * menjana proksi jika diperlukan.
 */
public static com.jay.aidl.IPerson asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if ((iin !=null)&&(iin instanceof com.jay.aidl.IPerson))) {
return ((com.jay.aidl.IPerson)iin);
}
return new com.jay.aidl .IPerson.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
kembali ini;
}
@Override public boolean onTransact (int kod, data android.os.Parcel , android.os.Parcel reply, int flags) melempar android.os.RemoteException
{
tukar (kod)
{
case ANTARA MUKA:<🎜TRANSAKSI: >{
reply.writeString(DESCRIPTOR);
kembali benar;
}
kes TRANSACTION_queryPerson:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.queryPerson(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true ;
}
}
kembali super.onTransact(kod, data, balas, bendera);
}
peribadi kelas statik Proksi melaksanakan com.jay.aidl.IPerson
{
peribadi android.os.IBinder mRemote;
Proksi(android.os.IBinder jarak jauh)
{
mRemote = jauh;
}
@Override public android.os.IB(inder )
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java. .String queryPerson(int num) melempar android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
cuba {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(num);
mRemote.transact(Stub.TRANSACTION_queryPerson, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
akhirnya {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
statik akhir int TRANSACTION_queryPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String queryPerson(int num) throws android.osception.
}

Di sini kami hanya mengambil berat tentang **asInterface(IBinder)** dan kaedah **queryPerson()** dalam antara muka yang kami takrifkan!

Kaedah ini akan menukar objek jenis IBinder kepada IPPerson type , jana objek proksi untuk mengembalikan hasilnya jika perlu!

Kita boleh melangkau selebihnya dan meneruskan ke langkah seterusnya.

Langkah 2: **Sesuaikan kelas Perkhidmatan kami dan lengkapkan operasi berikut:

1) Warisi kelas Perkhidmatan dan juga sesuaikan kelas PersonQueryBinder untuk digunakan Untuk mewarisi kelas IPerson.Stub adalah untuk melaksanakan antara muka IPerson dan antara muka IBinder

2) Menghidupkan kelas Stub tersuai dan mengatasi kaedah Perkhidmatan onBind, Kembalikan objek pengikat !

AIDLService.java

pakej com.jay.aidlserver;

import android.app.Service;
import android .content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import com.jay.aidl.IPerson.Stub;

/ **
 * Dibuat oleh Jay pada 2015/8/18 0018.
 */
AIDLService kelas awam melanjutkan Perkhidmatan {

pengikat IBinder peribadi = new PersonQueryBinder();
nama Rentetan[] peribadi = {"B神","艹神" ,"Ji Shen ","J God","Xiang Shen"};

pertanyaan Rentetan peribadi(int num)
{
if(num > 0 && num < 6){
return names[num - 1];
}
return null;
}

@Override
public IBinder onBind(Intent intent) {
return null;

PersonQueryBinder kelas akhir persendirian memanjangkan Stub{
@Override
query String awamPerson(int num) melontar RemoteException {
return query(num);
}
}
}

Langkah 3:在AndroidManifest.xml文件中注册Perkhidmatan

<service android:name=".AIDLService"><🎜 >      tent  ;
                <action android:name="android.intent.action.AIDLService" />
                <kategori android.                                                                                                                                                                                                     .       < /intent-filter>
        </service>

Kami tidak menyediakan antara muka Aktiviti di sini, tetapi Perkhidmatan yang disediakan oleh aplikasi yang diubah suai boleh dipanggil oleh apl lain!


2. Pelanggan
terus menyalin fail aidl daripada pelayan, dan kemudian kami melengkapkannya terus dalam MainActivity dan mengikat Perkhidmatan setempat
Agak serupa, prosesnya adalah seperti berikut:
1) Sesuaikan kelas PersonConnection untuk melaksanakan antara muka ServiceConnection
2) Menggunakan objek PersonConnection sebagai parameter, panggil bindService untuk mengikat Perkhidmatan jauh
bindService(service ,conn,BIND_AUTO_CREATE);
ps: Parameter ketiga adalah untuk menetapkan penciptaan automatik jika perkhidmatan tidak dimulakan
3) Berbeza daripada Perkhidmatan setempat, ServiceConnection terikat kepada perkhidmatan jauh tidak boleh secara langsung Untuk mendapatkan objek IBinder yang dikembalikan oleh kaedah onBind() Perkhidmatan
, anda hanya boleh mengembalikan objek proksi yang dikembalikan oleh onBind( ) kaedah. Anda perlu melakukan pemprosesan berikut:
iPerson = IPPerson.Stub.asInterface(service);
Kemudian lengkapkan permulaan, acara butang, dll.

Kod khusus adalah seperti berikut:

MainActivity.java

pakej com.jay.aidlclient;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.jay.aidl.IPerson;

kelas awam MainActivity melanjutkan AppCompatActivity melaksanakan View.OnClickListener{

    pribadi EditText edit_num;
    pribadi Button btn_query;    priva View tex;  pribadi IPerson iPerson;
    private PersonConnection conn = baharu PersonConnection();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState activity);      . 🎜 >         bindViews();
        //绑定远程Perkhidmatan
        Perkhidmatan Niat = Niat baharu("android.intent.action.AIDLService");<   id     age. er");

        bindService(service, conn, BIND_AUTO_CREATE);
         btn_query.setOnClickListener(this);
    }
<🎜  View       edit_num = (EditTeks) findViewById (R.id.edit_num);
        btn_query = (Button) findViewById(R.id.btn_query);
        txt_name = (TextView) findViewById_name(R.id. .txt);<🎜 🎜>    @Override
    public void onClick(Lihat v) {
        Nombor rentetan = edit_num.getText().toString();
                                                                                                                    cuba {
            txt_name.settext (iperson.queryperson (num));
}} tangkapan (remoteException e) {
e.printstackTrace ();

    kelas akhir peribadi PersonConnection melaksanakan ServiceConnection {
        public void onServiceConnected(ComponentName name, IBinder service) {
 as I face    tub. );
        }
        kosong awam onServiceDisconnected(ComponentName name) {
             iPerson = null;
        }
    }
}

Seterusnya, mulakan AIDLServivce, kemudian mulakan AIDLClient, masukkan nombor siri pertanyaan, dan anda boleh mendapatkan nama yang sepadan! Sudah tentu, anda juga boleh memulakan AIDLClient secara langsung dan mendapat kesan yang sama:

Rendering adalah seperti berikut:

6.gif


3) Perkhidmatan AIDL yang menghantar data kompleks

Dalam contoh di atas, kami hanya lulus parameter jenis int, dan kemudian pelayan mengembalikan parameter jenis String, yang nampaknya memuaskan Keperluan asas kami, tetapi dalam pembangunan sebenar, kami mungkin perlu mempertimbangkan untuk menghantar jenis data yang kompleks! Mari belajar seterusnya Bagaimana untuk menghantar data jenis data kompleks ke pelayan! Sebelum kita mula, mari kita fahami dahulu Antara muka boleh parcel!

——Pengenalan kepada antara muka Boleh Dibungkus:

Saya percaya bahawa mereka yang telah menggunakan bersiri pada asasnya mengetahui antara muka ini, selain itu, terdapat satu lagi Serializable , yang sama digunakan untuk bersiri, Cuma Parcelable lebih ringan dan lebih pantas! Tetapi ia agak menyusahkan untuk menulis Sudah tentu, jika anda menggunakan sebagai, anda boleh menggunakannya. Pemalam untuk melengkapkan penyirian, seperti: Penjana Kod Parcelable AndroidSudah tentu, di sini kami akan mengajar anda cara melaksanakan antara muka ini~

Pertama sekali, perlu dilaksanakan: kaedah writeToParcel dan readFromPacel Kaedah tulis menulis objek pada petak, manakala kaedah baca membaca objek daripada petak. Sila ambil perhatian bahawa susunan atribut penulisan perlu sama dengan susunan bacaan

Kemudian anda perlu menambah akhir statik< bernama PENCIPTA ke kelas: 🎜>Hartanah Untuk menukar atribut, anda perlu melaksanakan: android.os.Parcelable.Creatorantara muka

dan kemudian perlu menulis dua kaedah dalam antara muka: createFromParcel Kaedah (Sumber bungkusan): melaksanakan fungsi mencipta contoh JavaBean daripada sumber newArray(saiz int): mencipta tatasusunan jenis T dan saiz panjang, dengan hanya mengembalikan saiz T baharu yang mudah ]; (T di sini ialah kelas Orang)

Akhir sekali, describeContents(): Saya tidak tahu untuk apa ini, hanya kembalikan 0! Abaikan dia

- Selain itu, , jenis bukan primitif , kecuali String dan CharSequence, selebihnya adalah penunjuk arah diperlukan. Penunjuk arah termasuk masuk, keluar, dan masuk. in bermakna ia ditetapkan oleh klien, out bermakna ia ditetapkan oleh pelayan, dan inout bermakna nilai ditetapkan oleh kedua-dua pelanggan dan pelayan.


Baiklah, mari cuba menulis kod (ada masalah dengan jenis tersuai di sini dalam AS, yang masih belum diselesaikan, jadi saya akan menggunakan Eclipse~):

Contoh kod :

Sesuaikan dua jenis objek: Orang dan Gaji Orang digunakan sebagai parameter untuk memanggil Perkhidmatan jauh, dan Gaji digunakan sebagai nilai pulangan. Kemudian perkara pertama yang perlu dilakukan ialah membuat kelas Orang dan Gaji, dan juga perlu melaksanakan antara muka Parcelable

1. - Pelayan

Langkah 1: Buat fail Person.aidl dan Salary.aidl, kerana mereka perlu melaksanakan antara muka Parcelable, jadi Perkara berikut pernyataan:

Person.aidl:     parcelable Person; 
Salary.aidl:     parcelable Salary;
Langkah 2: Wujudkan kelas Orang dan kelas Gaji masing-masing Anda perlu melaksanakan antara muka Parcelable dan tulis semula kaedah yang sepadan!


<. 🎜 >PS: Oleh kerana kami kemudiannya memperoleh data dalam koleksi Peta berdasarkan objek Person, kami menulis semula kod cincang dan sama dalam Person.java kaedah; manakala kelas Gaji tidak perlu!

Person.java:

pakej com.jay.example.aidl;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Dibuat oleh Jay pada 2015/8/18 0018.
  */
orang kelas awam melaksanakan Parcelable{

id Integer peribadi;
nama Rentetan peribadi;

Orang awam() {}

Orang awam(Integer id, String name) {
this.id = id;
this.name = name;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

public String getName() {
kembalikan nama;
}


//Kaedah yang mesti dilaksanakan untuk melaksanakan Parcelable, saya tidak tahu untuk menggunakannya untuk Ya, kembalikan 0 terus
@Override
public int describeContents() {
return 0;
}


//Kaedah menulis data ke dalam Parcel
@Override
public void writeToParcel(Parcel dest, int flags) {
//Tulis data yang terkandung dalam objek ke dalam parcel
dest.writeInt(id);
dest . writeString(name);
}

//Atribut akhir statik bernama CREATOR mesti disediakan Atribut ini perlu dilaksanakan
//android.os.Parcelable.Creator<T>interface<. .public Person createFromParcel(Parcel source) {
return new Person(source.readInt(),source.readString());
}
@Override
public Person[] newArray(int size ) {
          kembalikan Orang baharu[saiz]; Kita perlu mengatasi kaedah hashCode() dan equals()
@Override
public int hashCode()
{
final int prime = 31;
int hasil = 1;
hasil = perdana * hasil + ((nama == nol) ? 0 : nama.hashCode());
kembalikan hasil;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (o bj == null)
return false;
if ( getClass() != obj .getClass())
return false;
Orang lain = (Orang) obj;
if (nama == null)
{
if (other.name != null)
return false;
}
Jika (! Nama.sama dengan (Nama.Lain))
Kembalikan palsu;
Kembalikan benar;
<pra><p><strong>Gaji.java</strong>~照葫芦画瓢</p>

<pra>
pakej com.jay.exa ; 

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Dibuat oleh Jay pada 2015/8/18 0018.
 */
Gaji golongan awam melaksanakan Parcelable {

    jenis String swasta;
     gaji Integer swasta;

    Gaji awam() {
    }

        Gaji                    awam   ini.jenis = type;
        this. salary = gaji;
    }

    public String getType() {
        return type;
                                                                  awam () {
        gaji pulangan;
    }

    public void setType(String type) {
        this.type = type;
              set                                                         set gaji teger) { this.salary = gaji;

@Override
public int gambarkanContents () {
return 0;
}

@Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(type);
        dest.writeInt(gaji);
                            akhir mampu.Pencipta< Gaji> CREATOR = baharu Parcelable.Creator<Gaji>() {
        //从Parc el中读取数据,返回Person对象
                                                                                                                                      FromParcel(Sumber Parcel) {
             memulangkan Gaji baharu( source.readString(), source.readInt());
        }

@Override
Gaji awam[] newArray(int size) {
kembalikan Gaji baharu[saiz];
}
};

public String toString() {
return "Pekerjaan:" + taip + " Gaji: " + gaji;
}
}

Langkah 3: Buat fail ISalary.aidl di dalamnya Tulis a kaedah mudah untuk mendapatkan maklumat gaji:

pakej com.jay.example.aidl;

import com.jay.example.aidl.Gaji; example.aidl.Person;
antara muka IGaji
{
//Tentukan objek Orang sebagai parameter masuk
//Apabila mentakrifkan kaedah dalam antara muka, anda perlu merumuskan mod penghantaran parameter baru, di sini Ia diluluskan, jadi terdapat di hadapan
Gaji getMsg(pemilik Orang Dalam);

ps:Anda boleh ingat di sini bahawa jika anda menggunakan jenis data tersuai, anda perlu mengimportnya! ! ! Ingat! ! !

Langkah 4: Penulisan Perkhidmatan teras: Tentukan kelas SalaryBinder yang mewarisi Stub untuk melaksanakan antara muka ISalary dan IBinder; Tetapkan semula kaedah onBind dan kembalikan contoh objek kelas SalaryBinder!

AidlService.java

pakej com.jay.example.aidl_complexservice;

import java.util.HashMap;
import java.util.Map; ISalary.Stub;
import com.jay.example.aidl.Person;
import com.jay.example.aidl.Gaji; os.IBinder;
import android.os.RemoteException;

AidlService kelas awam melanjutkan Perkhidmatan {

Gaji Binder swasta
Peta statik swasta< HashMap<Person, Salary>();
//Memulakan koleksi Peta, di sini ia dimulakan dalam blok kod statik, sudah tentu anda juga boleh melengkapkan permulaan dalam pembina
statik
{
ss.put(Orang baharu(1, "Jay"), Gaji baharu("petani kod", 2000));
ss.put(Orang baharu(2, "PERMATA"), Gaji baharu("Penyanyi" , 20000));
ss.put(Orang baharu(3, "XM"), Gaji baharu("Pelajar", 20)); Gaji baru("Guru", 2000));
}

super.onCreate();
GajiBinder baru();
}

@Override
public IBinder onBind(Intent intent) {
return salaryBinder;
}


//Ia juga mewarisi Stub, iaitu, ia melaksanakan kedua-dua antara muka ISalary dan antara muka IBinder.
SalaryBinder kelas awam melanjutkan Stub
{
        @Override  
        Gaji awam getMsg(Pemilik orang) membuang RemoteException {  
            return ss.get(owner);  
        }  
    }  
      
    @Override  
    public void on Destroy() {  
    stem y"!>    stem y.  
        super.onDestroy();  
    }  
}

注册下Perkhidmatan:

<service android:name=".AidlService">  
    <penapis niat>    
        <action android:name="android.intent.action.AIDLService" />  
        <kategori android:name="android.intent.category.DEFAULT" />  
    </intent-filter>    
</service>

2 - Tulisan pelanggan

Langkah 1: Salin fail AIDL sebelah pelayan Direktori yang disalin adalah seperti berikut:

7.jpg

Langkah 2: Tulis reka letak yang mudah, dan kemudian laksanakan teras MainActvitiy Tentukan objek ServiceConnection dan ganti kaedah yang sepadan, serupa dengan data biasa sebelumnya Kemudian dalam bindService, kemudian dapatkan objek Gaji dalam acara klik Button dan paparkannya!

MainActivity.java

pakej com.jay.example.aidl_complexclient;  
  
import com.jay.example.aidl.ISgaji;  
import com.jay.example.aidl.Person;  
import com.jay.example.aidl.Gaji;  
  
import android.app.Aktiviti;  
import android.app.Service;  
import android.content.ComponentName;  
import android.content.Intent;  
import android.content.ServiceConnection;  
import android.os.Bundle;  
import android.os.IBinder;  
import android.os.RemoteException;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.EditText;  
import android.widget.TextView;  
  
  
Aktiviti Utama kelas awam melanjutkan Aktiviti {  
  
    Perkhidmatan gaji swasta Gaji;  
    peribadi Butang btnquery;  
    nama edit EditText peribadi;  
    pertunjukan teks TextView peribadi;  
ServiceConnection swasta conn = new ServiceConnection () {

@Override
public void onServiceDisconnected (componentName name) {
salaryService = null;  
        }  
          
        @Override   
         public void onServiceConnected(ComponentName nama,                                                                                     返回的是代理对象,要调用这个方法哦!  
            gajiService = ISGaji.Stub.asInterface(service);  
        }  
    };  
      
      
    @Override  
    dilindungi void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
          
         btnquery = (Butang) findViewById(R.id.btnquery);  
        editname = (EditText) findViewById(R.id.editname);  
        textshow = (TextView) findViewById(R.id.textshow);  
           
         Niat itu = Niat baru();  
        it.setAction("com.jay.aidl.AIDL_SERVICE");  
        bindService(it, conn, Service.BIND_AUTO_CREATE);  
          
         btnquery.setOnClickListener(new OnClickListener() {            
             @OnClickListener ( baru OnClickListener() {           
             @OnClickListener         @OnClickListener v) {  
                 cuba  
                 {  
                     String name = edit name.get Text .toString() 🎜>                } tangkapan (RemoteException e){ e.printStackTrace();}  
            }  
        });  
          
    }  
    @Override   
    dilindungi kosong onDestroy() {  
        super.onDestroy();  
        this.unbindService(conn);  
    }  
      
}

Tangkapan skrin sedang berjalan:

8.jpg

PS: Kod di sini ditulis sebelum menggunakan Kod Eclipse , terdapat masalah dengan jenis tersuai di bawah Android Studio. Saya belum menemui penyelesaian lagi Jika sesiapa tahu, sila beritahu saya! ! ! Bersyukur sangat! ! ! Masalah yang timbul adalah seperti berikut:

9.png

Muat turun kod untuk dua keadaan (berdasarkan Eclipse):
1) Gunakan AIDL untuk melengkapkan komunikasi mudah antara proses
2) Pelaksanaan Perkhidmatan AIDL yang memindahkan data kompleks


3 Selesaikan komunikasi silang proses secara langsung melalui Binder's onTransact

Seperti yang dinyatakan di atas, Android boleh melengkapkan komunikasi melalui kaedah onTrensact Binder Di sini ialah Mari cuba secara ringkas, berdasarkan yang sebelumnya Contoh nama pertanyaan nombor siri:

Pelaksanaan bahagian pelayan :

/**
 * Dibuat oleh Jay pada 2015/8/18 0018.
 */
IPCService kelas awam melanjutkan Perkhidmatan{

    String akhir statik pribadi DESCRIPTOR = "IPCService";
       privasi akhir "B神","艹神","基神","J神","翔神"};
    pribadi MyBinder mBinder = new MyBinder();


    pribadi kelas My Binder melanjutkan Pengikat {
        @Override
        dilindungi boolean onTransact(int kod, data Parcel, Parcel reply, int flags) melempar RemoteException {<  >      code           kes 0x001: {
                    data. enforceInterface(DESCRIPTOR);
                    int num = data.readInt();
                    reply.write NoException();<🎜 >                                                                                                                                                            mes[num]);
                    return true;
                 
            }
            return super.onTransact(kod, data, reply, bendera);
        }
    }

        
       
       < (Niat niat) {
kembalikan mBinder;
    }
}

Pelaksanaan pelanggan:

kelas awam MainActivity melanjutkan AppCompatActivity melaksanakan View.OnClickListener{

    pribadi EditText edit_num;
    pribadi Button private; bt pertanyaan sendiri ult;
    pribadi IBinder mIBinder;
private ServiceConnection PersonConnection  = new ServiceConnection()
    {
        @Override
        public void onServiceDisconnected(Component Name  >                                                                                                  mIBinder = null;
         }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            mIBinder = service;
          ;
              @Override
    dilindungi void onCreate(Bundle savedInstanceState ) {
         super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();

   /翜眑行       Perkhidmatan niat = baharu Intent("android.intent.action.IPCService");
        service.setPackage("com.jay.ipcserver");
        bindService(perkhidmatan, PersonConnection, BIND_AUTO_CREATE>          CREATE ;   Listen O_CREATE ini) ;
    }

    private void bindViews() {
        edit_num = (EditText) findViewById(R.id.edit_num);
  b t    But View d(R.id.btn_query) ;
        txt_result = (TextView) findViewById(R.id.txt_result);
    }

    @Override
    public void onClick > <🎜int num = Integer.parseInt(edit_num.getText().toString());
if (mIBinder == null)
{
Toast.makeText(ini, "Pelayan tidak disambungkan atau pelayan disekat "Bunuh secara tidak normal", toast.Length_short) .show ();
} else {
Android.OS Parcel _data = Android.os.parcel.obtain (); );
          Rentetan _hasil = null; 
                                       _data.writeInt(bilangan);
mIB ,_0.0 > _reply.readException();
_result = _reply.readString();
txt _result.setText(_result);
       edit_num.setText("" ; {
_reply.recycle( );
_data
                                                                   

Kod ini agak mudah, jadi saya tidak akan menerangkannya dengan banyak~cuma gunakannya dan ubah suai sendiri! PS: Rujukan kod: Analisis ringkas rangka kerja Android aidl Binder


4. Beberapa perkara yang perlu diberi perhatian dalam Perkhidmatan selepas Android 5.0:

Hari ini, apabila saya memulakan Perkhidmatan secara tersirat, saya menghadapi masalah seperti itu

10.png

Kemudian program ranap sebaik sahaja ia dimulakan, dan ia mengambil masa yang lama untuk membetulkannya. Inilah masalahnya dengan Android 5.0, Ternyata terdapat ciri baharu selepas 5.0, iaitu: Niat Perkhidmatan mestilah eksplisit! Nah, Perkhidmatan tidak boleh dimulakan secara tersirat, dan penyelesaiannya sangat mudah! Contohnya, StartService:

startService(new Intent(getApplicationContext(), "com.aaa.xxxserver"));Jika anda menulis program seperti ini, ia akan ranap secara langsung hendaklah ditulis seperti berikut: startService(new Intent(getApplicationContext(), LoadContactsService.class));

Jika ia BindService: Intent service = new Intent("android. intent.action.AIDLService");< Atas dasar 🎜>, tambahkan nama pakej: service.setPackage("com.jay.ipcserver");Itu sahaja~

Dokumen rasmi:

http://developer.android.com/intl/zh-cn/guide/components/intents-filters.html#TypesDokumentasi:

11.png


Ringkasan bahagian ini:

Baiklah, ini bahagian terakhir tentang Perkhidmatan Bahagian ini menerangkan konsep asas Binder dan cara melaksanakan komunikasi antara proses. Dua cara: komunikasi silang proses melalui AIDL dan Binder.onTransact()! Akhir sekali, kami juga menerangkan post-Android 5.0 Ambil perhatian bahawa Perkhidmatan tidak boleh dimulakan secara tersirat! Itu sahaja, terima kasih~