zoukankan      html  css  js  c++  java
  • Android-远程Service

    http://blog.csdn.net/guolin_blog/article/details/9797169

    http://www.jianshu.com/p/eeb2bd59853f

    将一个普通的Service转换成远程Service其实非常简单,只需要在注册Service的时候将它的android:process属性指定成:remote就可以了,代码如下所示:

    <service android:name=".AIDLService"
            android:process=":remote"></service>

    远程service可以让service在另一个进程运行,所以可以执行阻塞进程的操作

    远程Service这么好用,干脆以后我们把所有的Service都转换成远程Service吧,还省得再开启线程了。其实不然,远程Service非但不好用,甚至可以称得上是较为难用。一般情况下如果可以不使用远程Service,就尽量不要使用它。

    下面就来看一下它的弊端吧,首先将MyService的onCreate()方法中让线程睡眠的代码去除掉,然后重新运行程序,并点击一下Bind Service按钮,你会发现程序崩溃了!为什么点击Start Service按钮程序就不会崩溃,而点击Bind Service按钮就会崩溃呢?这是由于在Bind Service按钮的点击事件里面我们会让MainActivity和MyService建立关联,但是目前MyService已经是一个远程Service了,Activity和Service运行在两个不同的进程当中,这时就不能再使用传统的建立关联的方式,程序也就崩溃了。

    那么如何才能让Activity与一个远程Service建立关联呢?这就要使用AIDL来进行跨进程通信了(IPC)。

    调用者和Service如果不在一个进程内, 就需要使用android中的远程Service调用机制.
    android使用AIDL定义进程间的通信接口. AIDL的语法与java接口类似, 需要注意以下几点:

      1. AIDL文件必须以.aidl作为后缀名.
      2. AIDL接口中用到的数据类型, 除了基本类型, String, List, Map, CharSequence之外, 其他类型都需要导包, 即使两种在同一个包内. List和Map中的元素类型必须是AIDL支持的类型.
      3. 接口名需要和文件名相同.
      4. 方法的参数或返回值是自定义类型时, 该自定义的类型必须实现了Parcelable接口.
      5. 所有非java基本类型参数都需要加上in, out, inout标记, 以表明参数是输入参数, 输出参数, 还是输入输出参数.
      6. 接口和方法前不能使用访问修饰符和static, final等修饰.

    AIDL实现
    1.首先我建立2个app工程,通过aidl实现一个app调用另一个app的service
    目录结构如下:
    service提供端app

    利用aidl调用service的app

    2.在两个app中都建立一个文件 IPerson.aidl注意 包名 要相同
    IPerson.aidl只是一个接口文件,用来aidl交互的,建立好之后在Studio中点Build-->Rebuild会自动创建需要的java文件。

    IPerson.aidl代码

    package mangues.com.aidl;
    interface IPerson {
      String greet(String someone);
    }

    3.在aidl_service 中建立AIDLService
    这个IPerson.Stub 就是通过IPerson.aidl 自动生成的binder 文件,你实现下,然后在onBind()中 return出去就好了,就和Android Service实现和activity交互一样。
    代码:

    public class AIDLService extends Service {
      private static final String TAG = "AIDLService";
    
      IPerson.Stub stub = new IPerson.Stub() {
          @Override
          public String greet(String someone) throws RemoteException {
              Log.i(TAG, "greet() called");
              return "hello, " + someone;
          }
      };
    
      @Override
      public void onCreate() {
          super.onCreate();
          Log.i(TAG, "onCreate() called");
      }
    
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
          Log.i(TAG, "onBind() onStartCommand");
          return super.onStartCommand(intent, flags, startId);
    
      }
    
      @Override
      public IBinder onBind(Intent intent) {
          Log.i(TAG, "onBind() called");
          return stub;
      }
    
      @Override
      public boolean onUnbind(Intent intent) {
          Log.i(TAG, "onUnbind() called");
          return true;
      }
    
      @Override
      public void onDestroy() {
          super.onDestroy();
          Log.i(TAG, "onDestroy() called");
      }
    }

    这里为什么可以这样写呢?因为Stub其实就是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现。

    4.aidl_service MainActivity 中启动这个service
    简单点就不写关闭什么的了;

    @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          Intent startIntent = new Intent(this, AIDLService.class);
          startService(startIntent);
      }

    在AndroidManifest.xml注册

    <service android:name=".AIDLService"
                   android:process=":remote">
              <intent-filter>
                  <action android:name="android.intent.action.AIDLService" />
                  <category android:name="android.intent.category.DEFAULT" />
              </intent-filter>
          </service>

    作用就是把这个service暴露出去,让别的APP可以利用
    android.intent.action.AIDLService 字段隐形绑定这个service,获取数据。

    5.aidl_client 中绑定aidl_service service 获取数据
    代码:

    public class MainActivity extends AppCompatActivity {
        private IPerson person;
        private ServiceConnection conn = new ServiceConnection() {
           @Override
          public void onServiceConnected(ComponentName name, IBinder service) {
              Log.i("ServiceConnection", "onServiceConnected() called");
              person = IPerson.Stub.asInterface(service);
              String retVal = null;
              try {
                  retVal = person.greet("scott");
              } catch (RemoteException e) {
                  e.printStackTrace();
              }
              Toast.makeText(MainActivity.this, retVal, Toast.LENGTH_SHORT).show();
          }
    
          @Override
          public void onServiceDisconnected(ComponentName name) {
              //This is called when the connection with the service has been unexpectedly disconnected,
              //that is, its process crashed. Because it is running in our same process, we should never see this happen.
              Log.i("ServiceConnection", "onServiceDisconnected() called");
          }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          Intent mIntent = new Intent();
          mIntent.setAction("android.intent.action.AIDLService");
          Intent eintent = new Intent(getExplicitIntent(this,mIntent));
          bindService(eintent, conn, Context.BIND_AUTO_CREATE);
      }
      public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
          // Retrieve all services that can match the given intent
          PackageManager pm = context.getPackageManager();
          List<ResolveInfo> resolveInfo = 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;
      }
    }

    在上一篇文章中我们已经知道,如果想要让Activity与Service之间建立关联,需要调用bindService()方法,并将Intent作为参数传递进去,在Intent里指定好要绑定的Service,示例代码如下:

    Intent bindIntent = new Intent(this, MyService.class);  
    bindService(bindIntent, connection, BIND_AUTO_CREATE);

    这里在构建Intent的时候是使用MyService.class来指定要绑定哪一个Service的,但是在另一个应用程序中去绑定Service的时候并没有MyService这个类,这时就必须使用到隐式Intent了

     <intent-filter>  
                <action android:name="com.example.servicetest.MyAIDLService"/>  
            </intent-filter>

    这就说明,MyService可以响应带有com.example.servicetest.MyAIDLService这个action的Intent。

  • 相关阅读:
    mybatis入门截图三
    centos 6.X 关闭selinux
    安装完最小化 RHEL/CentOS 7 后需要做的 30 件事情(二)
    安装完最小化 RHEL/CentOS 7 后需要做的 30 件事情(一)
    Linux定时任务Crontab命令详解
    CentOS 更换yum源为aliyun yum源
    CentOS7 FTP服务搭建(虚拟用户访问FTP服务)
    CentOS 7 安装Oracle 11gR2
    印度项目质量管理经验
    项目管理系列之质量管理
  • 原文地址:https://www.cnblogs.com/qlky/p/6682352.html
Copyright © 2011-2022 走看看