編輯:關於Android編程
1、概述
AIDL在android系統中的作用
AIDL,Android Interface definition language的縮寫,它是一種android內部進程通信接口的描述語言,通過它我們可以定義進程間的通信接口。最近看了下AIDL在Android系統中的用法,在網上看到很多初學的朋友不太明白AIDL的實際作用,android提供了很多進程間通信的組件,像action、broadcast、contentprovide都可以實現進程間的通信,為什麼還要用AIDL這個東西呢?我在android源碼中實現了一個自己寫的AIDL例子,用以簡單解釋下AIDL的作用。
有開發過藍牙或者WIFI應用的朋友肯定都知道,要去操作它必須先獲得一個管理類,比如WIFI的管理類是WifiManager,通過getSystemService(Context.WIFI_SERVICE)就可以得到wifi的管理權限,這個提供了很多的方法可以讓用戶去操作它,比如打開wifi可以調用setWifiEnabled(true)方法。那這個Manager到底做了什麼工作呢?是怎樣實現打開wifi的呢?其實這個Manager只是一個管理類,真正干活的另有其人,是一個叫WifiService的系統服務。在Android系統中有很多的Manager,wifi的管理類叫WifiManager,藍牙的管理類叫BluetoothManager,但是,只要有xxxManager.java,就會有Ixxx.aidl,並且有xxxService.java。這個aidl類就是實現Manager和Service通信的橋梁。
Binder驅動,Binder客戶端、服務端這三者之間的關系:
binder通信的四個角色應該是client組件,server組件,serviceManager和binder驅動。client組件和server組件進行通信,要通過ServiceManager查詢server組件的引用。server向ServiceManager注冊一個binder屍體,client通過ServiceManager獲得binder實體的一個引用,這樣client和server就可以通信了
在eclipse裡面操作時aidl文件個java文件都放在一個包下, 客戶端直接將該包復制到自己的目錄下,然後可以另外建另外一個包放其他代碼。但在android studio下面這樣是不可以的,需要在src單獨建一個AIDL文件夾,將aidl文件放在裡面,java文件在另外的包下,這樣就導致服務端項目與客戶端項目的包名必須相同。在as中project相當於es的workspace,moudle相當於es的project,在eclipse裡面是兩個project在通信,so 我猜測在as中是兩個mould在通信,因此建了一個project(裡面自帶一個app module),讓app moulde作為客戶端然後又另外加了一個服務端moudle 叫aidlserver。在aidlserver的project視圖下面的src下面右鍵new 選擇AIDL ,AIDL Folder ,然後將自己的aidl文件放入其中。
在Android Studio下創建AIDL Serivce。
建立ADIL Service的步驟比建立普通Service要多一些,主要有:
1、創建AIDL文件,在這裡面定義遠程接口。
2、生成Java接口文件。
3、建立一個Service的子類,並且記得在AndroidManifest.xml文件中配置。
在客戶端調用ADIL Servie:
1、拷貝服務器端的AIDL文件,並生成Java接口文件。
2、用BindService來調用Service,與調用普通Serivce相類似,只是獲取IBinder的方式有點不一樣。
下面是一個簡單的例子
在項目名稱上右鍵>NEW>AIDL>AIDL File,這樣就創建了一個ADIL文件,命名為AIDLServerService.aidl
package com.test.huangxingli.aidlserver; import com.test.huangxingli.aidlserver.Girl; // Declare any non-default types here with import statements interface AIDLServerService { String sayHello(); Girl getGirl(); }再創建Girl.aidl
package com.test.huangxingli.aidlserver; parcelable Girl;
建好這兩個文件後再編寫Girl.java .注意要先寫Girl.aidl然後再寫Girl.java 剛開始時 我先寫的Girl.java 然後再寫Girl.aidl時提示不能創建重名的文件。
Girl.java如下:
package com.test.huangxingli.aidlserver; import android.os.Parcel; import android.os.Parcelable; /** * Created by huangxingli on 2015/3/27. */ public class Girl implements Parcelable{ String name; int age; public Girl() { } public String getName() { return name; } public int getAge() { return age; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } public static final CreatorCREATOR=new Creator () { @Override public Girl createFromParcel(Parcel source) { Girl girl=new Girl(); girl.setName(source.readString()); girl.setAge(source.readInt()); return girl; } @Override public Girl[] newArray(int size) { return new Girl[size]; } }; }
然後菜單中選擇Build>Rebulid Project,這樣就生成了java接口文件,地址在項目文件夾/app/build/generated/aidl裡面
如圖
接著寫Service類MAIDLServerService,如下:
package com.test.huangxingli.aidlserver; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; public class MAIDLServerService extends Service { public MAIDLServerService() { } AIDLServerService.Stub binder=new AIDLServerService.Stub() { @Override public String sayHello() throws RemoteException { return "hello, i am from AIDLServerService"; } @Override public Girl getGirl() throws RemoteException { Girl girl=new Girl(); girl.setAge(25); girl.setName("lily"); return girl; } }; @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return binder; } }然後在AndroidManifest.xml中裡面將該服務器端的Service注冊一下:如下
server端結構如圖
首先要拷貝AIDL文件,這裡要保證文件的內容一模一樣,包括包的名稱,比如本例子中服務器端AIDL文件所在包的名稱是com.test.huangxingli.aidlserver,如何做到這一點,先新建一個項目,然後在:項目文件夾/app/src/main目錄下建立一個aidl文件夾,與java文件夾同級,在Android Studio中就可以看到這個目錄,在這個目錄上右鍵New>Package,建立一個com.test.huangxingli.aidlserver的包,再將aidl文件拷進去。這樣才能保證生成的java接口文件完全一樣,否則會提示找不到接口。參照下圖操作
核心部分: 在網上很多aidl程序客戶端無法綁定Service,因為Android5.0以後,也就是說從Lollipop開始,service服務必須采用顯示方式啟動,否則會報錯Service Intent must be explitict如何解決Android 5.0中出現的警告:Service Intent must be expli 該鏈接中,第一種在添加setpackage這句代碼後提示AIDL的service的綁定失敗,第二種方式解決了改問題,我也是用第二種方法解決 結合我們的項目該怎麼寫了,如下:
Intent mIntent = new Intent(); mIntent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService"); Intent eintent = new Intent(createExplicitFromImplicitIntent(MainActivity.this, mIntent)); bindService(eintent,connection,BIND_AUTO_CREATE); MainActivity.this.startService(eintent);請注意,bindService 應在 startService之前 下面是我的客戶端MainActivity.java的代碼:
package com.test.huangxingli.aidlserver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.util.List; public class MainActivity extends ActionBarActivity { TextView textView; Button button; AIDLServerService aidlServerService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button= (Button) findViewById(R.id.button); textView= (TextView) findViewById(R.id.textView); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Intent intent=new Intent(); // intent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService");//你定義的service的action // intent.setPackage(getPackageName()); // // bindService(intent,connection,BIND_AUTO_CREATE); Intent mIntent = new Intent(); mIntent.setAction("com.test.huangxingli.aidlserver.MAIDLServerService"); Intent eintent = new Intent(createExplicitFromImplicitIntent(MainActivity.this, mIntent)); bindService(eintent,connection,BIND_AUTO_CREATE); MainActivity.this.startService(eintent); } }); } /*** * Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent, * "java.lang.IllegalArgumentException: Service Intent must be explicit" * * If you are using an implicit intent, and know only 1 target would answer this intent, * This method will help you turn the implicit intent into the explicit form. * * Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466 * @param context * @param implicitIntent - The original implicit intent * @return Explicit Intent created from the implicit original intent */ public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) { // Retrieve all services that can match the given intent PackageManager pm = context.getPackageManager(); ListresolveInfo = pm.queryIntentServices(implicitIntent, 0); // Make sure only one match was found if (resolveInfo == null || resolveInfo.size() != 1) { return null; } // Get component info and create ComponentName ResolveInfo serviceInfo = resolveInfo.get(0); String packageName = serviceInfo.serviceInfo.packageName; String className = serviceInfo.serviceInfo.name; ComponentName component = new ComponentName(packageName, className); // Create a new intent. Use the old one for extras and such reuse Intent explicitIntent = new Intent(implicitIntent); // Set the component to be explicit explicitIntent.setComponent(component); return explicitIntent; } ServiceConnection connection=new ServiceConnection() { String content; @Override public void onServiceConnected(ComponentName name, IBinder service) { aidlServerService=AIDLServerService.Stub.asInterface(service); try { content=aidlServerService.sayHello()+"\n"; Girl girl=aidlServerService.getGirl(); content +="my name is "+girl.getName(); textView.setText(content); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { aidlServerService=null; } }; }
本節引言: 本節主要介紹的是Android系統服務中的---AlarmManager(鬧鐘服務), 除了開發手機鬧鐘外,更多的時候是作為一個全
一、為什麼要使用異步任務類? Handler模式需要為每一個任務創建一個新的線程,任務完成後通過Handler對象向UI線程發送消息,完成界面的更新, 這種方式對整
一、問題描述 為提高圖片加載的效率,需要對圖片的采用緩存和異步加載策略,編碼相對比較復雜,實際上有一些優秀的框架提供了解決方案,比如近期在git上比較活躍的xut
不願意看啰嗦的可以直接去 實現步驟 最近公司項目用到https的接口形式,對於一般的網絡請求 我們用的是http://****** 使用