• 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。

  • 相关阅读:
    SCI写作经典替换词,瞬间高大上!(转)
    最佳化常用测试函数 Optimization Test functions
    算法复杂度速查表
    VS 代码行统计
    CPLEX IDE 菜单栏语言设置( 中文 英文 韩文 等多国语言 设置)
    如何从PDF文件中提取矢量图
    Matlab无法打开M文件的错误( Undefined function or method 'uiopen' for input arguments of type 'char)
    visual studio 资源视图 空白 解决方案
    MFC DialogBar 按钮灰色不响应
    嗨翻C语言笔记(二)
  • 原文地址:https://www.cnblogs.com/qlky/p/6682352.html
Copyright © 2020-2023  润新知