Android:Service之远程服务和AIDL的创建

     什么是远程服务?

远程服务(Remote Service)也被称之为独立进程,它不受其它进程影响,可以为其它应用程序提供调用的接口——实际上就是进程间通信IPC(Inter-Process Communication),Android提供了AIDL(Android Interface Definition Language,接口描述语言)工具来帮助进程间接口的建立。

在Android中,不同的应用属于不同的进程(Process),一个进程不能访问其他进程的存储(可以通过ContentProvider实现)。

   优点:1.远程服务有自己的独立进程,不会受到其它进程的影响;

              2.可以被其它进程复用,提供公共服务;

              3.具有很高的灵活性。

   缺点:相对普通服务,占用系统资源较多,使用AIDL进行IPC也相对麻烦。

1、首先我们来简单深入了解远程服务,在此我们新建一个demo,在它的布局文件中增加两个ExitText文本域,再增加一个Button按钮。代码如下:

 <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入用户名"
        android:id="@+id/et_main_name"
        />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_main_password"
        android:hint="请输入密码"
        />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:onClick="login"
        android:text="登录"/>
2、新建一个类(LoginService.java)继承Service,重写它的onBind()方法;写一个类继承Binder,实现一个自定义接口,实现业务方法,在onBind()方法中返回该类对象。在代码如下:

public class LoginService extends Service{
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("test", "onBind: ");
        //如果你需要绑定服务,就需要返回值,否则默认为null
        return new MyIbinder();
    }
 
   class MyIbinder extends Binder implements LoginInterface{
       @Override
        public boolean login(String name, String pwd) {
          if ("sunny".equals(name) && "123".equals(pwd)) {//判断用户名和密码:如果密码正确就登录成功,否则失败
               return true;
           }
            return false;
       }
//        public boolean login(String name,String pwd){
//            if ("sunny".equals(name)&&"123".equals(pwd)) {//判断用户名和密码:如果密码正确就登录成功,否则失败
//                return true;
//              }
//            return false;
//        }
//    }

}
在清单文件AndroidManifest.xml 中对LoginService.java中配置如下所示:

 <service android:name=".LoginService"
            android:exported="true"></service>

3、新建一个自定义接口(LoginInterface),定义方法和属性。在LoginService.java中写一个类实现这个接口(LoginInterface)。代码如下:

package com.example.administrator.android_servicemain;

/**
 * Created by Administrator on 2017/2/12.
 */

public interface LoginInterface {
    public boolean login(String name,String pwd);
}

4、 在客户端MainActivity.java中与LoginService.java这个类绑定,传递ServiceConnection用来接收onBind()方法返回的Ibinder,强转为接口类型,就可以调用这个方法。绑定服务中有三个参数:<1>、需要Intent对象。<2>、Connection是远程服务的对象,可以使用匿名内部类(ServiceConnection)的方式实现。<3>、对于绑定操作,一般用BIDN_AUTO_CREATE;这个服务会在你绑定时自动创建。代码如下:

public class MainActivity extends AppCompatActivity {

    private EditText et_main_name;
    private EditText et_main_password;
    private Intent intent;
    private LoginService.MyIbinder myibinder;
    private LoginInterface loginInterface;
    private LoginInterfaceOut loginInterfaceOut;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//获取文本域的值
        et_main_name = (EditText) findViewById(R.id.et_main_name);
        et_main_password = (EditText) findViewById(R.id.et_main_password);

        intent = new Intent(this,LoginService.class);//开始绑定服务
    }
    //实列化一个对象
    ServiceConnection serviceConnection=new ServiceConnection() {
        @Override//绑定成功
        public void onServiceConnected(ComponentName name, IBinder ibinder) {
           loginInterface = (LoginInterface) ibinder;//这个接口就是等于你服务中的ibinder,服务中的ininder的实现了LoginInterface
 这个接口,所以可以直接替换。          // myibinder = (LoginService.MyIbinder) ibinder;
            Log.i("test", "onServiceConnected: 绑定成功!");
        }
        @Override//绑定失败
        public void onServiceDisconnected(ComponentName name) {
            Log.i("test", "onServiceConnected: 绑定失败!");
        }
    };
//绑定服务
    @Override
    protected void onResume() {
        //Service.BIND_AUTO_CREATE:这个服务在你绑定的时自动创建
        bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);
        super.onResume();
    }
    //按钮的点击事件
    public void login(View view){
        //获取文本框的用户名和密码
        String name=et_main_name.getText().toString();
        String pwd=et_main_password.getText().toString();
           boolean flag= loginInterface.login(name,pwd);
     //   boolean flag= myibinder.login(name,pwd);
        Toast.makeText(MainActivity.this, ""+ flag  , Toast.LENGTH_SHORT).show();

//        if ("sunny".equals(name)&&"123".equals(pwd)) {//判断用户名和密码:如果密码正确就登录成功,否则失败
//            Toast.makeText(MainActivity.this, "" + name + " " + pwd, Toast.LENGTH_SHORT).show();
//        }else {
//            Toast.makeText(MainActivity.this, "登录失败!用户名或密码输入错误~~", Toast.LENGTH_SHORT).show();
      //  }
    }
}

5、使用AIDL(Android interface define language):Android接口定义语言。可以在Android设备上两个进程之间进行进程间通信(interpricess communication,IPC)。新建一个aidl文件,然后将demo编译,它会自动生成aidl相对应的接口的java类。代码如下:

// LoginInterfaceOut.aidl
package com.example.administrator.android_servicemain;
interface LoginInterfaceOut {
 boolean login(String name, String pwd);
}

然后MainActivity.java和LoginService.java代码同上,只需要修改代码即可。(1)在LoginService.java写一个类,继承LoginInterfaceOut.Stub,并重写它的方法。代码如下:

//AIDL:Android interface define language-->安卓接口定义语言
public class LoginService extends Service{
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("test", "onBind: ");
        //如果你需要绑定服务,就需要返回值,否则默认为null
        return new MyIbinder();
    }
    class MyIbinder extends LoginInterfaceOut.Stub{//写一个类继承LoginInterfaceOut这个接口
        @Override
        public boolean login(String name, String pwd) throws RemoteException {
            if ("sunny".equals(name) && "123".equals(pwd)) {//判断用户名和密码:如果密码正确就登录成功,否则失败
                return true;
            }
            return false;
        }
    }
}
(2)MainActivity.java:( 1、在连接之后可以获取服务对象;(2、必须用asinterface方法得到LoginService对象。 代码如下:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//获取文本域的值
        et_main_name = (EditText) findViewById(R.id.et_main_name);
        et_main_password = (EditText) findViewById(R.id.et_main_password);

        intent = new Intent(this,LoginService.class);//开始绑定服务
    }
    //实列化一个对象
    ServiceConnection serviceConnection=new ServiceConnection() {
        @Override//绑定成功
        public void onServiceConnected(ComponentName name, IBinder ibinder) {
            loginInterfaceOut = LoginInterfaceOut.Stub.asInterface(ibinder);
             Log.i("test", "onServiceConnected: 绑定成功!");
        }
        @Override//绑定失败
        public void onServiceDisconnected(ComponentName name) {
            Log.i("test", "onServiceConnected: 绑定失败!");
        }
    };
//绑定服务
    @Override
    protected void onResume() {
        //Service.BIND_AUTO_CREATE:这个服务在你绑定的时自动创建
        bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);
        super.onResume();
    }
    //按钮的点击事件
    public void login(View view){
        //获取文本域的用户名和密码
        String name=et_main_name.getText().toString();
        String pwd=et_main_password.getText().toString();
        boolean flag= false;
        try {
            flag = loginInterfaceOut.login(name,pwd);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        Toast.makeText(MainActivity.this, ""+ flag  , Toast.LENGTH_SHORT).show();
    }
}

6、 再新建一个demo,将你要通信的AIDL产生的(LoginInterfaceOut)java类复制到demo中。其中demo的布局文件与上述一样,这时我们需要在MianActivity主activity中写入ComponentName componentName=new ComponentName("与进程进行通讯的包名","与进程进行通讯的包名下的服务名");intent.setComponent(componentName);多进程间启动Services;Android 5.0 之后,启动其他应用程序的服务,不允许使用隐式。代码如下:

public class MainActivity extends AppCompatActivity {
     private EditText et_main_name;
     private EditText et_main_password;
     private LoginInterfaceOut loginInterfaceOut;
     private Intent intent;

     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         //获取文本域的值
         et_main_name = (EditText) findViewById(R.id.et_main_name);
         et_main_password = (EditText) findViewById(R.id.et_main_password);
         intent = new Intent();
         ComponentName componentName=new ComponentName("com.example.administrator.android_servicemain","com.example.administrator.android_servicemain.LoginService");
         intent.setComponent(componentName);
    }
     ServiceConnection serviceConnection=new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder ibinder) {
             loginInterfaceOut = LoginInterfaceOut.Stub.asInterface(ibinder);
             Log.i("test", "onServiceConnected: 绑定成功!");
         }
         @Override
         public void onServiceDisconnected(ComponentName name) {
             Log.i("test", "onServiceConnected: 绑定失败!");
         }
     };
     //绑定服务
     @Override
     protected void onResume() {
         //Service.BIND_AUTO_CREATE:这个服务在你绑定的时自动创建
         bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);
         super.onResume();
     }
     //按钮的点击事件
     public void login(View view){
         //获取文本框的用户名和密码
         String name=et_main_name.getText().toString();
         String pwd=et_main_password.getText().toString();
         boolean flag= false;
         try {
             flag = loginInterfaceOut.login(name,pwd);
         } catch (RemoteException e) {
             e.printStackTrace();
         }
         Toast.makeText(MainActivity.this, ""+ flag  , Toast.LENGTH_SHORT).show();
     }
}
7、总结:
<1、远程服务(绑定服务):所谓远程指的是跨进程,而不是距离的远近。

<2、生命周期:多个组件可以绑定同一个远程服务,当所有的组件与远程服务解除绑定的时,远程服务也就会被销毁。

<3、AIDL(Android interface define language):Android接口定义语言。可以进行进程间的通信。

<4、LoginInterfaceOut.Stub是根据LoginInterfaceOut.aidl文件自动生成的,一般不需要去了解这个类的内容,只需写一个类继承LoginInterfaceOut.Stub即可。

<5、onBinder()方法必须返回LoginInterfaceOut.Stub类的子类,否则客户端无法获取服务对象。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值