日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > ChatGpt >内容正文

ChatGpt

跨进程访问(AIDL服务)

發布時間:2025/3/21 ChatGpt 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 跨进程访问(AIDL服务) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們都知道Service的主要的作用是后臺運行跨進程訪問
關于Service后臺運行請查看鄙人的另外一篇文章Service基礎

本篇博文主要探討的是跨進程訪問~

什么是AIDL

Android系統中的進程之間是不能共享內存,因此,需要提供一些機制在不同的進程之間進行數據通信,Activity BroadCast 和 Content Provider都可以跨進程通信,Service同樣也可以跨進程通信。

其中Activity可以跨進程調用其他應用程序的Activity 看看這里;還有這里

Content Provider可以跨進程訪問其他應用程序中的數據(以Cursor對象形式返回),當然,也可以對其他應用程序的數據進行增、刪、改操 作;

Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播;

Service和Content Provider類似,也可以訪問其他應用程序中的數據,但不同的是,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫AIDL服務。

為了使其他應用程序也可以訪問本應用程序提供的服務,Android系統采用了遠程過程調用(Remote Procedure Call,RPC)方式來實現。 與很多其他基于RPC的解決方案一樣,Android使用了一種接口定義語言(Interface Definition Lanuage)來公開服務的接口,因此可以將這種跨進程訪問的服務稱為 AIDL (Android Interface Definition Language);


建立AIDL的步驟

建立AIDL服務要比建立普通服務的步驟要復雜一些,工具:AS
具體步驟如下
看看這里
看看這里
1. New —-AIDL—-AIDL File ,建立AIDL文件
2. 如果aidl文件正確,Build–Rebulild Project之后,會自動生成一個Java接口文件


3. 建立一個服務類(Service子類)
4. 實現有aidl文件生成的java接口
5. 在AndroidManifest.xml中配置AIDL服務,尤其要注意的是,action標簽中android:name的屬性值就是客戶端要引用該服務的id,也就是Intent類構造方法的參數值。

<service android:name=".activity.service.aidl.AIDLService"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.turing.base.activity.service.aidl.AIDLService" /></intent-filter></service>

建立AIDL服務

首先需要明確,兩個工程。ProjectAIDL 和ProjectAIDLClient 。這樣就可以實現跨進程訪問啦。


功能說明:

建立一個簡單的AIDL服務,這個AIDL服務只有一個getValue的方法,改方法返回一個字符串, 在安裝完服務后,會在客戶端調用這個getValue方法,并將返回值在TextView控件顯示。


ProjectAIDL:

A. 建立AIDL文件

// IMyService.aidl package com.turing.base.activity.service.aidl;// Declare any non-default types here with import statementsinterface IMyService {String getValue(); }

但是此時并沒有AIDL的java文件產生,其實android studio也是帶有自動生成的,只不過需要確認一些信息后才能生成。此時,我們可以在目錄 build–>generated–>source–>aidl–>test–>debug下面發現還沒有任何文件

此時,打開AndroidManifest.xml,確認package的值,
關鍵性的一步,確認aidl文件所在的包名和AndroidMainifest.xml的package名是否一致。如果一致,點擊
Build–>Make Project,生成相應的java文件。

經驗證,貌似不一樣也沒問題


同樣生成了IMyService.java文件

B. 編寫Service子類,在子類中定義一個內部類,該內部類繼承自 IMyService.Stub

import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException;public class AIDLService extends Service {public class MyServiceImpl extends IMyService.Stub {@Overridepublic String getValue() throws RemoteException {return "AIDL.....";}}@Overridepublic IBinder onBind(Intent intent) {return new MyServiceImpl();} }

注意事項:
I: IMyService.Stub是根據IMyService.aidl文件自動生成的,一般不需要了解這個類的內容,只需要編寫一個繼承自IMyService.Stub的類即可
II:onBind方法必須返回MySeviceImpl對象,否則客戶端無法獲取服務對象。

C: 在AndroidManifest.xml中配置MyService類

<service android:name=".activity.service.aidl.AIDLService"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.turing.base.activity.service.aidl.AIDLService" /></intent-filter></service>

其中com.turing.base.activity.service.aidl.AIDLService是客戶端訪問AIDL服務的ID

至此 ,AIDL服務端的工作完成。


ProjectAIDLClient:

A. 建立AIDLClient工程,并將服務端自動生成的IMyService.java文件連通同包目錄一起復制到該工程的src目錄下。

首先要拷貝AIDL文件,這里要保證文件的內容一模一樣,包括包的名稱,比如本例子中服務器端AIDL文件所在包的名稱是com.sysu.aidlclient.aidlcilent,如何做到這一點,先新建一個項目,然后在:項目文件夾/app/src/main目錄下建立一個aidl文件夾,與java文件夾同級,在Android Studio中就可以看到這個目錄,在這個目錄上右鍵New>Package,建立一個com.sysu.aidlclient.aidlclient的包,再將aidl文件拷進去。這樣才能保證生成的java接口文件完全一樣,否則會提示找不到接口。

B 調用AIDL服務,首先要綁定服務,然后才可以獲得服務對象

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.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast;import com.turing.base.R;public class AIDLActivityDemo extends AppCompatActivity implements View.OnClickListener {private Button btn_bindAIDL, btn_callAIDL;private TextView tv_aidlResult;private IMyService myService ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_aidlactivity_demo);initView();initEvents();}/*** 初始化組件*/private void initView() {btn_bindAIDL = (Button) findViewById(R.id.id_btn_aidl_bind);btn_callAIDL = (Button) findViewById(R.id.id_btn_aidl_call);// 現將調用AIDL按鈕設置為灰色禁用,等初始化AIDL服務之后在設置為可點擊btn_callAIDL.setEnabled(false);tv_aidlResult = (TextView) findViewById(R.id.id_tv_aidl_result);}/*** 按鈕注冊監聽事件*/private void initEvents() {btn_bindAIDL.setOnClickListener(this);btn_callAIDL.setOnClickListener(this);tv_aidlResult.setOnClickListener(this);}/*** 按鈕監聽事件** @param v*/@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.id_btn_aidl_bind:bindService(new Intent("com.turing.base.activity.service.aidl.AIDLService"),serviceConnection,Service.BIND_AUTO_CREATE);break;case R.id.id_btn_aidl_call:// 調用服務端getValue方法try {tv_aidlResult.setText(myService.getValue().toString());} catch (RemoteException e) {e.printStackTrace();}break;case R.id.id_tv_aidl_result:Toast.makeText(this,"鬧著玩",Toast.LENGTH_SHORT).show();break;}}private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 獲取服務對象myService = IMyService.Stub.asInterface(service);btn_callAIDL.setEnabled(true);}@Overridepublic void onServiceDisconnected(ComponentName name) {}} ; }

注意事項:

  • 使用bindService方法綁定AIDL服務,其中需要使用Intent對象指定AIDL服務的ID,也就是action標簽中android:name屬性的值
  • 在綁定時需要一個ServiceConnection對象,創建ServiceConnection對象的過程中如果綁定成功,系統會調用ServiceConnection.onServiceConnected方法,通過改方法的service參數值可以獲得AIDL服務對象。

  • 運行效果演示:

    首先,運行AIDL服務程序,然后運行客戶端程序,單擊綁定AIDL服務按鈕,如果綁定成功,調用AIDL按鈕 會變成可點擊狀態,單擊此按鈕,輸出getValue方法的返回值,


    傳遞復雜數據的AIDL服務

    AIDL服務只支持有限的數據類型,因此如果使用AIDL傳遞復雜的數據就需要做進一步的處理。

    AIDL服務支持的數據類型

    • Java簡單類型(int 、char 、boolean等),無需import
    • String 和 CharSequence,無需import
    • List 和 Map,但是List和Map對象的元素類型必須是AIDL服務支持的數據類型,不需要import
    • AIDL指定生成的接口,需要import
    • 實現android.os.Parcelable接口的類,需要import

    工程目錄:


    傳遞不需要import的數據類型值的方式相同,傳遞一個需要import的數據類型值(例如實現android.os.Parceable接口的類)的步驟略顯復雜,除了要建一個實現android.os.Parceable接口的類外,還需要為這個類單獨建立一個aidl文件,并使用parceable關鍵字進行定義,具體的實現步驟如下:

    ComplexTypeAIDL:

    建立一個IMyService.aidl文件

    IMyService.aidl

    package mobile.android.ch12.complex.type.aidl; import mobile.android.ch12.complex.type.aidl.Product;interface IMyService { Map getMap(in String country, in Product product);Product getProduct(); }

    注意事項:

    • Product是一個實現了android.os.Parcelable接口的類,需要使用import導入這個類
    • 如果方法的類型是非簡單類型,例如String、List或者自定義的類,需要使用in 、out或者inout 進行修飾,其中in表示這個值被客戶端設置,out表示這個值被服務端設置;inout表示這個值既被客戶端設置,又要被服務端設置。
    • -

    編寫Product類,該類用于傳遞的數據類型

    Produt.java

    package mobile.android.ch12.complex.type.aidl;import android.os.Parcel; import android.os.Parcelable;public class Product implements Parcelable {private int id;private String name;private float price;public static final Parcelable.Creator<Product> CREATOR = new Parcelable.Creator<Product>(){public Product createFromParcel(Parcel in){return new Product(in);}public Product[] newArray(int size){return new Product[size]; }};public Product(){}private Product(Parcel in){readFromParcel(in);}@Overridepublic int describeContents(){// TODO Auto-generated method stubreturn 0;}public void readFromParcel(Parcel in){id = in.readInt();name = in.readString();price = in.readFloat();}@Overridepublic void writeToParcel(Parcel dest, int flags){dest.writeInt(id);dest.writeString(name);dest.writeFloat(price);}public int getId(){return id;}public void setId(int id){this.id = id;}public String getName(){return name;}public void setName(String name){this.name = name;}public float getPrice(){return price;}public void setPrice(float price){this.price = price;}}

    注意事項:

    • Product類必須實現android.os.Parcelable接口。該接口用于序列化對象。在Android中之所以使用Parcelable接口序列化,而不是使用java.io.Serializable接口,主要是為了提高效率。
    • 在Product類中必須有一個靜態常量,常量名必須是CREATOR,而且CREATOR常量的數據類型必須是Parcelable.Creator.
    public static final Parcelable.Creator<Product> CREATOR = new Parcelable.Creator<Product>(){public Product createFromParcel(Parcel in){return new Product(in);}public Product[] newArray(int size){return new Product[size]; }};
    • 在writeToParcel方法中需要將序列化的值寫入Parcel對象
    public void readFromParcel(Parcel in){id = in.readInt();name = in.readString();price = in.readFloat();}@Overridepublic void writeToParcel(Parcel dest, int flags){dest.writeInt(id);dest.writeString(name);dest.writeFloat(price);}

    建立一個Proudct.aidl

    Proudct.aidl

    parcelable Product;

    編寫MySevice類

    MyService.java

    import java.util.HashMap; import java.util.Map;import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException;public class MyService extends Service { public class MyServiceImpl extends IMyService.Stub{@Overridepublic Product getProduct() throws RemoteException{Product product = new Product();product.setId(1234);product.setName("汽車");product.setPrice(31000); return product;}@Overridepublic Map getMap(String country, Product product)throws RemoteException{Map map = new HashMap<String, String>();map.put("country", country);map.put("id", product.getId());map.put("name", product.getName());map.put("price", product.getPrice());map.put("product", product);return map;}}@Overridepublic IBinder onBind(Intent intent){ return new MyServiceImpl();}}

    在AndroidManifest.xml文件中配置MyService類

    <service android:name=".MyService" ><intent-filter> <action android:name="mobile.android.ch12.complex.type.aidl.IMyService" /></intent-filter></service>

    至此,服務端的AIDL服務已經完成,下面看下客戶端的操作


    ComplexTypeAIDLClient:

    將IMyservice.java和Product.java文件連同目錄一起復制到客戶端工程

    綁定AIDL服務,并獲取AIDL服務,最后調用AIDL服務中的方法

    Main.java

    package mobile.android.ch12.complex.type.aidlclient;import mobile.android.ch12.complex.type.aidl.IMyService; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView;public class Main extends Activity implements OnClickListener {private IMyService myService = null;private Button btnInvokeAIDLService;private Button btnBindAIDLService;private TextView textView;private ServiceConnection serviceConnection = new ServiceConnection(){ @Overridepublic void onServiceConnected(ComponentName name, IBinder service){ // 獲取AIDL服務對象myService = IMyService.Stub.asInterface(service);btnInvokeAIDLService.setEnabled(true);}@Overridepublic void onServiceDisconnected(ComponentName name){// TODO Auto-generated method stub}};@Overridepublic void onClick(View view){switch (view.getId()){case R.id.btnBindAIDLService:// 綁定AIDL服務bindService(new Intent("mobile.android.ch12.complex.type.aidl.IMyService"),serviceConnection, Context.BIND_AUTO_CREATE);break;case R.id.btnInvokeAIDLService:try{String s = "";// 調用AIDL服務中的方法s = "Product.id = " + myService.getProduct().getId() + "\n";s += "Product.name = " + myService.getProduct().getName()+ "\n";s += "Product.price = " + myService.getProduct().getPrice()+ "\n";s += myService.getMap("China", myService.getProduct()).toString();textView.setText(s);}catch (Exception e){}break;}}@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService);btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService);btnInvokeAIDLService.setEnabled(false);textView = (TextView) findViewById(R.id.textview);btnInvokeAIDLService.setOnClickListener(this);btnBindAIDLService.setOnClickListener(this);} }

    運行效果演示:

    首選運行服務端,在運行客戶端,即可在客戶端獲取如下信息


    AIDL與來去電自動掛斷

    真機親測有效

    概述

    雖然可以通過Activity Action來撥打電話,但是使用常規的方法卻無法掛斷電話,不過我們可以利用反射,使用AIDL文件自動生成接口來實現。

    在Android SDK 源碼中可以找到如下接口

    com.android.internal.telephony.ITelephony

    這個接口在外部是無法訪問的,只有將程序嵌入到Android SDK 內部才可以訪問,這個接口提供了一個endCall方法可以掛斷電話,現在我們就想辦法來調用ITelephony.endCall方法。

    盡管不能直接訪問ITelephony接口,但是我們發現在TelephonyManager類中有一個getITelephhony方法,可以返回一個ITelephony對象,不過改方法是private方法,so..我們可以通過反射來調用改方法

    private ITelephony getITelephony() {return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));}

    在調用getITelephony方法獲得ITelephony對象之前,我們需要在SDK源碼中找到 NeighboringCellInfo.aidl和 ITelephony.aidl,并將這兩個文件連同所在的包復制到我們自己的工程中來。

    目錄如下:

    ADT會根據ITelephony.aidl文件自動生成ITelephony.java文件,在gen目錄下。

    下面我們編寫一個接收來電的廣播接收器,并在這個廣播中自動掛斷指定號碼的來電,

    Code

    InCallReceiver.java

    package mobile.android.ch12.call.aidl;import java.lang.reflect.Method; import com.android.internal.telephony.ITelephony; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.telephony.TelephonyManager; import android.widget.Toast;public class InCallReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent){TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);switch (tm.getCallState()){case TelephonyManager.CALL_STATE_RINGING: // 響鈴// 獲得來電的電話號String incomingNumber = intent.getStringExtra("incoming_number");if ("1234576".equals(incomingNumber)){try{// 獲取TelephoneManager對象TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);// 獲取TelephoneManager的class對象Class<TelephonyManager> telephonyManagerClass = TelephonyManager.class;// 獲得getITelephony方法Method telephonyMethod = telephonyManagerClass.getDeclaredMethod("getITelephony",(Class[]) null);// 允許訪問private方法telephonyMethod.setAccessible(true);// 調用getITelephony方法返回ITelephony對象ITelephony telephony = (com.android.internal.telephony.ITelephony) telephonyMethod.invoke(telephonyManager, (Object[]) null);// 掛斷電話telephony.endCall();}catch (Exception e){Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();}}break;}}}

    配置權限

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/><uses-permission android:name="android.permission.CALL_PHONE"/>

    小結

    服務除了可以在內部調用,還可以使用AIDL服務實現跨應用的調用,其中的AIDL文件應用很廣泛,可以利用AIDL文件自動生成接口文件,并可以將相應的對象轉換成指定的接口,這大大方便了服務的調用。

    總結

    以上是生活随笔為你收集整理的跨进程访问(AIDL服务)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。