【Android学习笔记】再探Android Service

引言:初学Android的时候,对Service是草草了之,现在反过来复习,才发现自己有很多知识没有掌握,在这里总结一下。Service是Android的四大组件之一,是Android中实现程序后台运行最合适的解决方案之一,非常适合被用于去执行那些不需要和用户界面交互而且要求长期运行的任务。

1、创建一个Service

  • 服务中常用的几个方法分别是onCreate()、onStartCommand()、onDestroy()
public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    //每次服务启动时都会调用
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    //在服务第一次创建的时候调用,放只需要执行一次的代码
    @Override
    public void onCreate() {
        super.onCreate();
    }

    //服务销毁的时候调用
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}
  • 在AndroidManifest.xml注册Service
<service  android:name=".MyService" android:enabled="true" android:exported="true"></service>

2、启动和停止Service

//启动服务
@Override
public void onClick(View v) {
    startService(new Intent(MainActivity.this, MyService.class));
}

//停止服务 
@Override
public void onClick(View v) {
    stopService(new Intent(MainActivity.this,MyService.class));
}

3、绑定Service

  • 注意:startService()、stopService()和bindService()、unbindService()是成对出现的方法,startService()后,执行stopService()即可停止服务,bindService()后,执行unbindService()也可接除与服务的绑定;但是如果startService()后,接着调用bindService(),想要停止服务,必须先执行stopService(),再调用unbindService()。
@Override
public void onClick(View v) {
    bindService(new Intent(MainActivity.this,MyService.class), MainActivity.this, Context.BIND_AUTO_CREATE);
}

@Override
public void onClick(View v) {
    unbindService(MainActivity.this);
}
  • 还需要在启动Service的Activity里重写两个方法
@Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.i("miomin", "服务连接成功");
}

@Override
    public void onServiceDisconnected(ComponentName name) {
        Log.i("miomin", "服务连接关闭");
}

4、Service的生命周期

  • 下图可以看到,使用startService()启动Service和bindService()启动Service,所经历的生命周期是不同的。
    【Android学习笔记】再探Android Service_第1张图片

想要更详细的了解Service生命周期,可以参考这篇博文,Activity和Service的生命周期(图)

5、跨应用启动和板吊顶Service

Android5.0以后,禁止使用隐式Intent启动Service,必须使用显式意图,对于跨引用启动,我们必须指明被作为启动对象的Service的完整包名。

//使用包名构造显示意图
private Intent intent = new Intent();
intent.setComponent(new ComponentName("scu.miomin.com.learnaidl", "scu.miomin.com.learnaidl.AppService"));

switch (id) {
    case R.id.btnStartService:
        startService(intent);
        break;
    case R.id.btnStopService:
        stopService(intent);
        break;
    case R.id.btnBindService:
        bindService(intent, MainActivity.this,Context.BIND_AUTO_CREATE);
        break;
    case R.id.btnUnbindService:
        unbindService(MainActivity.this);
        break;
}

6、与Service通信

(1)进程内部使用Binder通信

创建一个专门的Binder对象来构造Service与Activity的通信通道,在onServiceConnected()回调中接受由目标Service的unbind()方法返回的Binder对象,可以直接对Binder对象的方法进行操作,可以传入参数,返回数据等等;如果需要实现Service实时返回下载进度的功能,可以在Service中构建回调,具体的可以参考如下例子,相信大家都看得懂。

  • MyService.java
public class MyService extends Service {

    // 控制任务是否执行
    private boolean serviceRunning = false;

    private String data = "this is default message";

    public void setCallback(Callback callback) {
        mCallback = callback;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public class MyBinder extends Binder {
        public void setData(String newData) {
            MyService.this.data = newData;
        }

        public MyService getMyService() {
            return MyService.this;
        }
    }

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

    @Override
    public void onCreate() {
        super.onCreate();

        serviceRunning = true;

        new Thread() {
            @Override
            public void run() {
                int i = 0;
                while (serviceRunning) {
                    i++;
                    String str = i + ":" + data;
                    if (mCallback != null)
                        mCallback.onDataChange(str);
                    Log.i("miomin", str);
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        serviceRunning = false;
    }

    private Callback mCallback;

    public interface Callback {
        void onDataChange(String date);
    }
}
  • MainActivity.java
public class MainActivity extends AppCompatActivity implements ServiceConnection {

    EditText etData;
    private MyService.MyBinder myBinder;
    private TextView tvOut;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         findViewById(R.id.startService).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startService(new Intent(MainActivity.this, MyService.class));
            }
        });

        findViewById(R.id.stopService).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(new Intent(MainActivity.this, MyService.class));
            }
        });

        findViewById(R.id.bindService).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService(new Intent(MainActivity.this, MyService.class), MainActivity.this, Context.BIND_AUTO_CREATE);
            }
        });

        findViewById(R.id.unbindService).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(MainActivity.this);
            }
        });

        etData = (EditText) findViewById(R.id.etData);

        findViewById(R.id.btnSyncData).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (myBinder != null) {
                    myBinder.setData(etData.getText().toString());
                }
            }
        });

        tvOut = (TextView) findViewById(R.id.tvOut);
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.i("miomin", "服务连接成功");
        myBinder = (MyService.MyBinder) service;
        myBinder.getMyService().setCallback(new MyService.Callback() {
            @Override
            public void onDataChange(String date) {
                Message message = Message.obtain();
                Bundle bundle = new Bundle();
                bundle.putString("data", date);
                message.setData(bundle);
                handler.sendMessage(message);
            }
        });
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            tvOut.setText(msg.getData().getString("data"));
        }
    };

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.i("miomin", "服务连接关闭");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(MainActivity.this);
    }
}

(2)使用AIDL跨进程与Service通信

  • 引言:在Android平台,一个进程通常不能访问另一个进程的内存空间,所以要想跨进行通信的话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。而为了方便编码,Android系统提供了AIDL工具来处理这项工作。
  • AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。
  • AIDL接口文件,和普通的接口内容没有什么特别,只是它的扩展名为.aidl。如果想要使用AIDL进行跨进程通信,需要在两个工程的src文件夹下建立一模一样的AIDL文件,并且保证包名相同。

    1、创建AIDL文件

interface IAppServiceAidlInterface {
    /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    void setData(String data);

    List<Car> getAllCar(); 
}

2、在Service中实现AIDL中定义的接口

  • 注意:在实现接口前,需要先ReBuild。
@Override
public IBinder onBind(Intent intent) {
    return new IAppServiceAidlInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public void setData(String data) throws RemoteException {
            AppService.this.data = data;
        }

        @Override
        public List<Car> getAllCar() throws RemoteException {
            return null;
        }
    };
}

3、在需要跨进程操作Service的Activity中接受Binder对象

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
    IAppServiceAidlInterface AIDLBinder = IAppServiceAidlInterface.Stub.asInterface(service);
}

你可能感兴趣的:(android,service,服务,aidl)