[java]
[java]
最近今天在學習service控件,前面的後台service和綁定本地控件的service的很容易理解,幾乎沒遇到什麼問題,但看到遠程調用service的時候模仿書上的例題,結果發現竟然得不到想要的結果,把書上的例子源碼弄進去,還是會有問題,於是經過好幾天的自己摸索和網上參考一些資料,主要得到幫助的來自http://www.cnblogs.com/TerryBlog/archive/2010/08/24/1807605.html http://ericchan2012.iteye.com/blog/1554197 這2個網址。接下來直接進入正題,對這幾天對遠程綁定調用service的學習結果。
遠程綁定調用service主要是用來不同進程的信息共享。就比如服務器和客戶端,在服務器端設置好一個service提供方法或信息,然後客戶端可以直接調用服務器端service提供方法或信息。這裡有個前提是客戶端必須有和服務器端一份一樣的AIDL,然後服務器端在客戶端使用的系統上有注冊過(也就是安裝運行過一次),之後客戶端就可以遠程綁定調用服務器端的service了。
具體的步驟如下:
1.首先,是服務器的
1)創建一個android應用工程
2) 在主Aitivity所在的包裡新建個AIDL文件,這是ADT會自動幫你在gen目錄下生成一個和AIDL文件同名的JAVA文件(這裡的AidlService.java是下一步驟生成的,這裡可以先忽略)
3)如上圖所示,創建一個用來使用service的類(AidlService.java)
具體每個文件的代碼如下:
AidlServerActivity.java
[java]
package com.ds.server;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class AidlServerActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent service = new Intent(AidlServerActivity.this,
AidlService.class);
startService(service);
Toast.makeText(AidlServerActivity.this, "service started",
Toast.LENGTH_LONG).show();
}
});
}
}
IAidlService.aidl
[java]
package com.ds.server;
interface IAidlService {
int getType();
}
AidlService.java
[java]
package com.ds.server;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class AidlService extends Service {
private boolean unrunnable;
private int count;
private class MyBinder extends IAidlService.Stub {
@Override
public int getType() throws RemoteException {
// TODO Auto-generated method stub
return 100;
}
}
private void Log(String str) {
Log.d("AidlService", "------ " + str + "------");
}
@Override
public void onCreate() {
super.onCreate();
/*
new Thread(new Runnable(){
@Override
public void run(){
while(!unrunnable){
try{
Thread.sleep(1000);
}catch(InterruptedException e){
}
count++;
Log.v("AidlService","count:"+count);
}
}
}).start();
*/
Log.v("RemoteCountService","onCreate");
Log("service create");
}
/*
@Override
public void onStart(Intent intent, int startId) {
Log("service start id=" + startId);
}
*/
@Override
public IBinder onBind(Intent t) {
Log("service on bind");
return new MyBinder();
}
@Override
public void onDestroy() {
Log("service on destroy");
unrunnable=true;
super.onDestroy();
}
/*
@Override
public boolean onUnbind(Intent intent) {
Log("service on unbind");
return super.onUnbind(intent);
}
public void onRebind(Intent intent) {
Log("service on rebind");
super.onRebind(intent);
}
*/
}
布局文件AndroidManifest.xml
[html]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ds.server"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AidlServerActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".AidlService"
android:enabled="true"
android:process=":remote" >
<intent-filter>
<!-- AIDL完整路徑名。必須指明,客戶端能夠通過AIDL類名查找到它的實現類 -->
<action android:name="com.ds.server.IAidlService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</application>
</manifest>
這裡,服務器端的工作做好了,接下來是客戶端的工作。
2.接著,是客戶端的:
1)首先,創建一個工程
2)接著,把服務器端的一些文件拷貝過來(創建com.ds.server這個包,然後往裡面復制進入如下圖的服務器端的文件(IAidlService.java)
下面是個文件的內容
AidlClientActivity.java
[java]
package com.ds.client;
import com.ds.server.IAidlService;
import android.app.Activity;
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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class AidlClientActivity extends Activity {
IAidlService iservice;
int count;
private ServiceConnection connection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
// 浠庤繙绋媠ervice涓?幏寰桝IDL瀹炰緥鍖栧?璞�
iservice = IAidlService.Stub.asInterface(service);
Log.i("Client","Bind Success:" + iservice);
}
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
iservice = null;
Log.i("Client","onServiceDisconnected");
}
};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView tv = (TextView) findViewById(R.id.tv);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Intent service = new Intent(IAidlService.class.getName());
bindService(service, connection, BIND_AUTO_CREATE);
if (iservice != null) {
try {
Log.v("AidlClientActivity","oncreate"+iservice.getType()+" "+count);
} catch (RemoteException e) {
e.printStackTrace();
}
}
else{
count++;
}
}
});
}
}
AndroidManifest.xml
[html]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ds.client"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AidlClientActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
這樣客戶端的工作也算完了,但這裡我還想說下一個問題。
你可能會看到在客戶端的Activity文件裡,有個count的變量,覺得是多余的,但這是為了說明下面這個問題的需要。
最開始的count是0,然後我運行客戶端後,鼠標左擊bind按鈕,會發現LogCat的verbose窗口會顯示
為什麼沒有執行 Log.v("AidlClientActivity","oncreate"+iservice.getType()+" "+count);這一句,然後我再點擊下bind
終於出現想要的結果,這裡你就會發現count變成1了,也就是之前執行過一次count+1了,這就說明了,第一次只是綁定,返回的 iservice是null,第二次以上才會返回對象。
到這裡就是我之前一直錯誤的地方,是理解錯了,我之前寫的程序沒有按鈕,是直接啟動客戶端後就綁定調用service,由於沒有按鈕不能多次按,也就會造成得不到想要的結果了。這裡總算明白它的一些運行機制了,先寫到這裡,後面有什麼新發現會及時更新。