【笔记】Service的使用

时间:2021-01-25 15:17:23

一、创建Service

  1.创建一个myService类,来继承Service。重写其中的方法,包括:onCreate(),onStartCommend(),onDestroy(),onBind()方法是自动重载的。

    1.1 onCreate():创建Service的时候调用,只调用一次。

    1.2 onStartCommend():执行Service的时候调用,执行几次,调用几次。

    1.3 onDestroy():在销毁Service的时候调用,只调用一次。

    1.4 onBind():在bindService的时候调用。只调用一次。

  1.2 myService代码如下:

package com.wangpei.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log; /**
* 作者:WangPei on 2015/7/9 09:48
* 邮箱:460977141@qq.com
*/
public class myService extends Service { private static final String TAG = "myInfo";
  //需要返回Binder实例
private MyBinder myBinder = new MyBinder(); @Override
public IBinder onBind(Intent intent) {
return myBinder;
} @Override
public void onCreate() {
Log.i(TAG,"onCreate is excute");
super.onCreate();
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand is excute");
return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
Log.i(TAG,"onDestroy is excute");
super.onDestroy();
} class MyBinder extends Binder{ public void startDownload(){
        //模拟下载任务
Log.i(TAG,"startDownload is excute");
}
}
}

二、startService AND stopService

  2.1 startService

    2.1.1 代码如下:

Intent startIntent = new Intent(MainActivity.this,myService.class);
startService(startIntent);

    2.1.2 调用myService类中的方法顺序如下:

        onCreate() ---> onStartCommend() ---先创建Service,然后在执行。

  2.2 stopService 代码如下:

    2.2.1 代码如下:

Intent stopIntent = new Intent(MainActivity.this,myService.class);
stopService(stopIntent);

    2.2.2 调用myService类中的方法顺序如下:

        onDestroy() --直接被销毁。

三、bindService AND unBindService

  3.1 创建ServiceConnection:

//初始化myService中的binder
private myService.MyBinder myBinder; private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (myService.MyBinder) service;
       //启动下载任务
myBinder.startDownload();
} @Override
public void onServiceDisconnected(ComponentName name) { }
};

    3.1.1 onServiceConnected()方法,是在Activity和Service建立连接的时候,进行调用。

    3.1.1 onServiceDisconnected()方法,onServiceDisconnected()方法不是解除关联的时候调用,而是发生异常时调用的。

  3.2 bindService 代码如下:

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

    3.2.1 BIND_AUTO_CREATE:意思是在绑定Service的时候,进行自动创建。

  3.3 unBindService 代码如下:

unbindService(connection);

  3.4 注意 如果同时startService和bindService,必须要stopService和unBindService,才能onDestroy()该Service。

   3.5 额外的东西

    楼主文中是有说明Service和Activity是如何通信的;首先在自定义的Service类中覆盖onBind(Intent intent)方法,返回一个Binder子类的对象,在自定义的Binder子类中可以定义一些方法;然后再Activity创建个ServiceConnection对象,并实现其onServiceConnected(ComponentName name, IBinder service) 方法,在这个方法中将传入的IBinder对象强转为在Service中定义的Binder子类,这样就拿到了Service中的某个对象的引用了,想怎通信都行;但要使onServiceConnected方法被回调,还需要调用bindService方法,把ServiceConnection的对象当作参数传过去......

四、Service AND Thread 的关系

  4.1 Service

    4.1.1 Service旨在后台运行,并且Service也是在主线程中运行的。

    4.1.2 Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。

    4.1.3 使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

    4.1.4 我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。

    4.1.5 较为标准的Service写法:

private MyBinder myBinder;

@Override  
public Binder onBind(Intent intent){
  return myBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 开始执行后台任务
}
}).start();
return super.onStartCommand(intent, flags, startId);
} class MyBinder extends Binder { public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// 执行具体的下载任务
}
}).start();
} }

  4.2 Thread

    4.2.1 Thread是在子线程中运行的,旨在不影响主线程的运行。

4.2.2 Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例;

五、前台Service

  5.1 需要在通知栏显示,点击之后,可以跳转到Activity。优点,可以保持持续的运行。比如说墨迹天气,它的Service在后台更新天气数据的同时,还会在系统状态栏一直显示当前天气的信息。具体实现如下:

public class MyService extends Service {  

    public static final String TAG = "MyService";  

    private MyBinder mBinder = new MyBinder();  

    @Override
public void onCreate() {
super.onCreate();
    //先定义通知
Notification notification = new Notification(R.drawable.ic_launcher,
"有通知到来", System.currentTimeMillis());
    //跳转意图
Intent notificationIntent = new Intent(this, MainActivity.class);
    //将意图转换为等待意图
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
    //初始化通知
notification.setLatestEventInfo(this, "这是通知的标题", "这是通知的内容",
pendingIntent);
    //然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。
startForeground(1, notification);
Log.d(TAG, "onCreate() executed");
} ......... }

 六、远程Service

  6.1 远程Service介绍:

        在注册service的时候,添加属性:remote即可激活远程service。远程service,是不同有主进程的service。直接可以在内部执行耗时操作,并且不影响主进程的使用。但是,有一个弊端。远程service没有办法和Activity进行绑定。因为,远程service是不同于应用程序主进程的进程,他们之间无法建立连接的。

     那么如何,才能使Activity和远程service建立连接呢?这里我们需要使用AIDL。接口定义语言来实现跨进程通信技术。

  6.2 AIDL(android interface definition language)的使用:

    6.2.1 使用方法,先建立一个后缀为AIDL的文件,这是一个接口文件。然后进行编译。系统会自动生成一个java文件。然后我们就可以进行使用了。

// IMyAidlInterface.aidl
package com.wangpei.service; // Declare any non-default types here with import statements interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
int plus(int a, int b);
String toUpperCase(String str);
}

   6.2.2 然后进行编译,系统会自动生成一个相应的java文件。此时,我们就可以使用它了。

在MyService中进行使用(对aidl中的方法,进行重写。):

package com.wangpei.service;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log; /**
* 作者:WangPei on 2015/7/9 09:48
* 邮箱:460977141@qq.com
*/
public class myService extends Service { private static final String TAG = "myInfo";
private MyBinder myBinder = new MyBinder(); @Override
public IBinder onBind(Intent intent) {
return mBinder;
} IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
@Override
public int plus(int a, int b) throws RemoteException {
return a+b;
} @Override
public String toUpperCase(String str) throws RemoteException {
if(str != null){ return str.toUpperCase();
}else {
return null;
}
}
}; @Override
public void onCreate() {
Log.i(TAG,"onCreate is excute");
// Log.i(TAG,"myService thread is :"+Thread.currentThread().getName()); /**
* 前台Service的使用
*/
// Notification notification = new Notification(R.drawable.ic_launcher,"这是通知的内容",System.currentTimeMillis());
// Intent notificationIntent = new Intent(this,MainActivity.class);
// PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
// notification.setLatestEventInfo(this,"这是通知的标题","这是主要内容",pendingIntent);
// startForeground(1,notification); super.onCreate();
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand is excute");
return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
Log.i(TAG,"onDestroy is excute");
super.onDestroy();
} class MyBinder extends Binder{ public void startDownload(){
Log.i(TAG,"startDownload is excute");
}
}
}

  6.2.3 最后在Activity中进行调用,即可,使用Aidl中,所定义的方法。

 private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// myBinder = (myService.MyBinder) service;
// myBinder.startDownload();
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
try {
int result = iMyAidlInterface.plus(9,15);
String str = iMyAidlInterface.toUpperCase("wang pei"); Log.i(TAG,result+"");
Log.i(TAG,str);
} catch (RemoteException e) {
e.printStackTrace();
}
}