四大应用组件之Service

1. 概念理解    

 Service运行在后台back键,应用退出,不会停止
 Service生命周期方法在主线程执行

2. 启动Service和绑定Service声明周期调用

2.1. 启动

     Intent intent=new Intent(MainActivity.this,MyService.class);
            startService(intent);

startService:
    第一次调用:构造方法->onCreate -> onStart -> onStartCommand
    后面每次调用:onStartCommand
 stopService:
    onDestroy销毁

2.2. 绑定Service

ServiceConnection connection=null;
public void bindService(View view){
           // 绑定服务器的理解  Activity作为宿组和Service进行绑定
         //     可以都有多个Activity绑定同一个Service,
             // 所有的Activity 断开以后才会调用Service 的onUnbind 回调方法
 Intent intent=new Intent(MainActivity.this,MyService.class);
 if(connection==null){
                 connection=new ServiceConnection() {
                     @Override
                     public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

                     }
                     @Override
                     public void onServiceDisconnected(ComponentName componentName) {
                     }
                 };
                 // Context.BIND_AUTO_CREATE 模式 绑定并且启动
                 bindService(intent,connection, Context.BIND_AUTO_CREATE);
             }else {
                 Log.e(TAG,"服务已经绑定");
             }
}
    @Override
    protected void onDestroy() {
        // 如果应用退出不解绑,会内存泄露
        if(connection!=null){
            unbindService(connection);
            connection=null;
        }
        super.onDestroy();
    }

    bindService: 
    第一次调用:构造方法->onCreate -> onBind -> ServiceConnection(A)
    解绑: 
    unbindService:  onUnbind -> onDestroy

    必须调用解绑,绑定是以为Activity作为宿主,否则Activity销毁的时候会泄露,抛异常

 3. AIDL  远程调用

在A  App 中 调用 B App 的服务器暴露出来的方法
 aldi 的目的就是 调用 B 服务中暴露的方法

server端:
 1. 通过aidl暴露接口,传递自定义需要打包,实现Parcelable 接口

IStudentInterface.aidl

// IStudentInterface.aidl
package com.example.myremote;

// 导入包
import com.example.myremote.Student;

// Declare any non-default types here with import statements

interface IStudentInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     *1. 接口名称和返回值相同
     *2. 不能你有访问修饰符修饰
     *3. 实体类必须要实现Parcelable接口
     *
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

            Student getStudentById(int id);
}

 Student.aidl

package com.example.myremote;

parcelable Student;

 生产的aidl源码在:  build/generated/source/aidl/包名下
 2.  通过Binder 暴露服务中方法

package com.example.myremote;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class RemoteService extends Service {
    public RemoteService() {
    }

    String TAG="denganzhi1";
// 3. Binder 返回客户端,返回给A 应用
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.e(TAG,"onBind");
    //    return  null;
      return new  StudentSevice();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG,"onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG,"onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    // 1. 在服务中定义方法
    public Student getStudentNewById(int i){
        return new Student(100,"xiaohei");
    }

    // 2. 暴露服务中方法,通过Binder包装
    /**
     * public static abstract class Stub extends android.os.Binder implements com.example.myremote.IStudentInterface
     * 继承关系
     */
    class StudentSevice extends  IStudentInterface.Stub{
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
        }
        @Override
        public Student getStudentById(int id) throws RemoteException {
            Log.e(TAG,"getStudentById:"+id);
            return getStudentNewById(1);
        }
    }


}

AndroidManifest.xml

  <service
            android:name=".RemoteService"
            android:enabled="true"
            android:exported="true">
            <!-- 指定意图,用于Client调用找到 Service端口, 唯一 -->
            <intent-filter>
                <action android:name="com.example.myremote.RemoteService.Action"></action>
            </intent-filter>
        </service>

client端:

1. 客户端,拷贝服务端的aidl,实体类,包名要和服务器端一致到客户端项目
2.  客户端绑定服务端,服务端返回Bindder,把Binder转化为接口IStudentInterface

 ServiceConnection serviceConnection2=null;
    IStudentInterface iStudentInterface=null;
    public void bindRemoteServicce(View view){
// 指定隐式意图
        Intent intent=new Intent("com.example.myremote.RemoteService.Action");
        /**
         * bindService方法在5.0以后做出改变,隐式意图需要设置Package 或者 Commponent,直接定义一个action是报异常的。
         */
        intent.setPackage("com.example.myremote");
        if(serviceConnection2==null){
            serviceConnection2=new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                  iStudentInterface=  IStudentInterface.Stub.asInterface(service);
                }
                @Override
                public void onServiceDisconnected(ComponentName name) {
                }
            };
            bindService(intent,serviceConnection2,Context.BIND_AUTO_CREATE);
        }else {
            Log.e(TAG,"已经绑定");
        }
    }

3. 调用AIDL的方法,获取B App传递过来的, 调用方法获取返回值

 // 调用AIDL的方法
        btn_diaoyong.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(iStudentInterface!=null){
                    try {
                        com.example.myremote.Student student = iStudentInterface.getStudentById(1);
                        Log.e("denganzhi","student..."+student);
                    } catch (RemoteException e) {
                        Log.e("denganzhi",e.getMessage());
                        e.printStackTrace();
                    }
                }
            }
        });

4. 资源释放

    public void unbindRemoteServicce(View view){
        if(serviceConnection2!=null){
            unbindService(serviceConnection2);
            serviceConnection2=null;
            iStudentInterface=null;
        }else{
            Log.e(TAG,"尚未绑定");
        }
    }
    @Override
    protected void onDestroy() {
        // 如果应用退出不解绑,会内存泄露,抛异常,但是本会奔溃,没有关系
        unbindRemoteServicce(null);
        super.onDestroy();
    }
发布了75 篇原创文章 · 获赞 68 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/dreams_deng/article/details/104712787
今日推荐