Service的各种知识点

@(读书笔记)
   Service主要用于在后台处理一些耗时逻辑,或者去执行某些需要长期运行的任务。有时候在程序退出的情况下,Service也会在后台继续保持运行状态。

1.Service的基本用法:

1.新建一个MyService继承Service,并重写onCreate()、onStartCommand()和onDestroy()方法:
例:

 public class MyService extends Service {

    public  static  final String TAG="MyService";

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

    @Override
    public void onDestroy() {
        Log.i(TAG,"onDestroy");
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"onBind");
        return null;
    }
}

2.启动Service和停止Service的方法

//启动Service
  Intent startIntent = new Intent(this, MyService.class);  
  startService(startIntent);  
 //停止Service
    Intent stopIntent = new Intent(this, MyService.class);  
   stopService(stopIntent) 

3.项目中所有使用的Service都需要在AndroidManifest文件中配置:

 <service android:name="com.example.servicetest.MyService" >   service>  

第一次点击执行启动Service的方法时,会打印:

08-10 21:52:33.257 14033-14033/com.simon.activity I/MyService: onCreate
08-10 21:52:33.257 14033-14033/com.simon.activity I/MyService: onStartCommand

也就是说,当启动一个Service的时候,会调用该Service中的onCreate和onStartCommand方法。
再次点击执行启动Service的方法,会打印:

08-10 21:54:22.576 14033-14033/com.simon.activity I/MyService: onStartCommand

可以看到只执行了onStartCommand方法,因为onCreate方法只会在Service第一次创建的时候调用。如果Service已经创建过来,不管怎么调用startService方法,onCreate方法都不会执行。只会执行onStartCommand方法。

然后我们就可以在应用管理界面看到我们启动的Service了,这里需要注意一下Service一旦启动,就不会自动停止,即时里面的方法执行完成或者没有方法。

2.Service和Activity通信

在service的基本用法中,Activity只是启动了Service,然后Service就自己执行onCreate和onStartCommand了。这种方式下Service和Activity的关系不太。如果想在Activity中去通知Service去做什么事情,那就需要将Activity和Service建立关联。我们通过Binder对象来实现这个操作。

1.Service是通过onBinder对象和Activity建立关联的,例:

public class MyService extends Service {
    public  static  final String TAG="MyService";

    private  MyBinder binder=new MyBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG,"onCreate");
    }

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

    @Override
    public void onDestroy() {
        Log.i(TAG,"onDestroy");
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"onBind");
        return binder;
    }

    public class MyBinder extends Binder{
        public void startDownload(){
            Log.i(TAG,"startDownload");
            Log.i(TAG,"Thread-name"+Thread.currentThread().getName());
        }
    }

}

可以看到我们在Service中添加了一个自定义的MyBinder对象,然后给他添加了StartDownload方法。 这个方法中我们输出了日志,并打印了当前线程的名字。然后构建了一个myBinder对象,并把它作为onBinder方法的返回值。之后我们在Activity中会拿到这个binder对象,这样Activty和Service就建立关联了。

2.修改Activity的代码,添加绑定Service的方法

public class MainActivity extends AppCompatActivity {
    public static final String TAG = "tag";
    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) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "MainActivity-onCreate");

        findViewById(R.id.bind_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyService.class);
                bindService(intent, connection, BIND_AUTO_CREATE);
            }
        });
        findViewById(R.id.unbind_service).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(connection);
            }
        });
    }
}

可以看到我们这里先建立了一个匿名的ServiceConnection的匿名类,在里面重写了onServiceConnection()和onServiceDisconnected()方法,这两个方法分别会在Activity和Service建立关联和解除关联的时候调用。在onServiceConnected()方法中,我们又通过向下转型得到了MyBinder的实例,有了这个实例,我们就可以在Activity中调用Service中的相关方法了。

然后,我们执行下面这段代码,Service就会绑定到Activity中,bindService传递的第三个参数BIND_AUTO_CREATE表示在Service和Activity建立关联后自动创建Service. 就会使得Service的onCreate方法执行,onStartCommand方法不执行。

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

我们点击一下,绑定Service的按钮,打印日志如下

08-11 15:45:30.040 15608-15608/com.simon.activity I/MyService: onCreate
08-11 15:45:30.041 15608-15608/com.simon.activity I/MyService: onBind
08-11 15:45:30.048 15608-15608/com.simon.activity I/MyService: startDownload
08-11 15:45:30.048 15608-15608/com.simon.activity I/MyService: startDownload -Threadmain

可以看到,点击绑定Service后,先执行了onCreate和onBind方法。然后在ServiceConnection的onServiceConnection中执行了binder对象的startDownload方法。 我们看到打印的日志中的线程名可以确定startDownload是执行在主线程中的。

现在我们就可以在Activity中任意调用绑定的Service对象了。

需要注意的是,Service在整个应用范围内是通用的,即MyService不仅可以和MainActivity建立关联,也可以可以其他Acitivity建立关联。 建立关联的时候拿到的binder对象是同一个实例。并且再次建立关联的时候Service的onCreate方法不会执行。

3.如何销毁Serivce:

1.在Service的基本用法中,我们介绍了销毁Service最简单的一种情况,点击Start Service按钮启动Service,再点击Stop Service按钮停止service.这样MyService就销毁了。 打印日志如下:

08-11 16:10:52.529 22596-22596/com.simon.activity I/MyService: onCreate
08-11 16:10:52.565 22596-22596/com.simon.activity I/MyService: onStartCommand
08-11 16:10:54.619 22596-22596/com.simon.activity I/MyService: onDestroy

2.如果是点击binderService按钮呢? 由于在绑定Service的时候指定的标志位是BIND_AUTO_CREATE. 说明点击bind service按钮的时候Service也会创建,这时应该怎么销毁Service呢? 其实很简单,点击一下 Unbind Service按钮将Service解除关联就可以了。
日志如下:

08-11 16:14:15.137 22596-22596/com.simon.activity I/MyService: onCreate
08-11 16:14:15.139 22596-22596/com.simon.activity I/MyService: onBind
08-11 16:14:16.655 22596-22596/com.simon.activity I/MyService: onDestroy

3.如果是即点击start Service又点击了bind service. 要怎么销毁呢?
这样情况下,单独stop service和unbindService都不能销毁Service。 需要stop service和unbindService都点击一下,才能正常销毁。

08-11 16:19:57.506 22596-22596/com.simon.activity I/MyService: onCreate
08-11 16:19:57.506 22596-22596/com.simon.activity I/MyService: onStartCommand
08-11 16:19:59.960 22596-22596/com.simon.activity I/MyService: onBind
08-11 16:20:06.824 22596-22596/com.simon.activity I/MyService: onDestroy

4.Service和Thread的关系

这里我们要正确的理解Service和Thread的关系,Service有后台处理的概念,所以很容易和Thread的混淆在一起。其实Service是运行在主线程中的,Service所谓的后台,指定的是不需要UI的。即使Activity被销毁或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用需要始终和服务器保持心跳连接,就可以使用Service来实现。我们在Service中执行耗时任务,还是需要启动线程去执行。

Service中启动线程去执行耗时任务和Activity中启动线程又什么区别呢? 原因是在Activity中启动线程,如果Activity被销毁,就没有办法可以再重新获取到之前创建的实例。 而且一个Activity创建的子线程,另一个Activity也无法对其操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便的操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就可以重新获得Service中的Binder的实例。

5.创建前台Service

Service几乎都是在后台运行的,一直以来都是在后台默默工作。但是Service的系统优先级还是比较低,当系统出现内存不足情况下,就有可能会回收正在后台运行的Service.如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service. 前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统状态栏显示。下面示例如何创建前台Service:

public class FrontService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        Notification notification = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("这是通知的标题")
                .setContentText("这是通知的内容")
                .setContentIntent(PendingIntent.getService(this, 0, new Intent(this, FrontService.class), 0))
                .build();
        startForeground(1, notification);
    }

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

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

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

可以看到我们在Service的onCreate方法中先创建了一个Notification对象,然后调用了startForeground方法。将这个Service变成前台Service。
Service的各种知识点_第1张图片

你可能感兴趣的:(android,基础组件)