• Service的理解


    转自 原文

     

    Service的理解

    Service是什么?
    Service是一种可以在后台运行相关任务的组件。没有界面。其存在的线程是主线程,一般会通过启动子线程来执行耗时操作。
    Service有什么用?
    可用于在后台执行下载任务。从而不影响用户界面操作。
    Service分启动型服务、绑定型服务两种。
    绑定服务中的创建Binder的扩展类的目的是什么?
    该类主要用于获取Service的实例,以及执行相关的方法。
    额外知识
    1.不绑定服务,直接点击取消绑定服务会报错。因此需要通过判断Binder对象是否为空来处理。
    2.服务可以不定义Action,通过Intent指定要跳转的Service即可。
    3.Service的有效范围是所有满足条件的Activity。
    4.在Service里执行耗时操作会导致ANR,启动新的线程执行耗时操作可有效避免。

    两种服务的区别

    Service类型说明使用步骤
    启动型服务1.生命周期为onCreate->onStartCommand->onDestroy 
    2.服务一旦启动后,需要调用stopService方法或stopSelf方法才能停止。 
    3.可常驻系统。
    1.通过调用startService启动服务 
    2.通过stopService停止服务
    绑定型服务1.生命周期为onCreate->onBind->onUnbind->onDestory 
    2.需要返回Binder对象,即定义Binder的子类。
    3.通过Binder子类的方法来获取Service对象,用于与Activity交互。 
    4.在Activity中需要通过创建ServiceConnection对象来获取service实例。从而调用service里的方法。
    1.通过bindService绑定服务 
    2.通过unbindService取消绑定服务

    Service生命周期

    Service的类型及其示例

    启动型服务 - StartService

    使用
    1.创建java类继承Service
    2.重写onStart、onCreate等方法。
    3.在onCreate中新开子线程,用于执行任务。

    示例 - 启动型服务

    Service作用
    打印0-2000的数字,完毕后停止服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    public class CalcService extends Service {
    private int total;
    private boolean openService; //结束服务时的标识

    public CalcService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
    super.onCreate();
    LogTool.e("CalcService", "onCreate");
    }

    @Override
    public int onStartCommand(final Intent intent, int flags, final int startId) {

    LogTool.e("CalcService", "onStartCommand");
    Functions.toast("Service已启动,请查看LOG");
    //启动线程执行耗时操作。通常是下载之类的任务
    new Thread(new Runnable() {
    @Override
    public void run() {
    while (!openService) {
    try {
    Thread.sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    LogTool.e("CalcService", total);
    total++;
    builder.setSubText("total:" + total);
    if (total == 2000) {
    stopSelf();
    }
    }
    }
    }).start();
    return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
    super.onDestroy();
    LogTool.e("CalcService", "onDestroy");
    Functions.toast("CalcService已停止,请查看LOG");
    openService = true;
    }
    }
    1
    2
    3
    4
    5
    // Activity中的代码
    public void startService(View v){
    Intent intent = new Intent(this,CalcService.class);
    startService(intent);
    }

    绑定型服务 - BindService

    BindService(Intent,ServiceConnection,Context.BIND_AUTO_CREATE)
    参数分别为Intent,ServiceConnection,标识号。通常为BIND_AUTO_CREATE。
    使用
    1.创建java类继承Service
    2.创建Java类继承Binder类。用于返回Service实例。
    3.重写onBind、onUnBind等方法。
    4.在Activity中创建ServiceConnection对象,并获取Binder实例。
    ps:为防止未绑定服务,用户点击取消绑定而导致的崩溃。需要对unbindService进行边缘性处理。

    示例 - 普通绑定型服务

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    public class BindService extends Service {
    private BindService service;
    private TestBinder binder = new TestBinder();
    private int count = 0;

    public class TestBinder extends Binder {
    //通过Binder对象来获取服务对象,从而调用服务里的方法
    public BindService getService() {
    if (service == null) {
    service = new BindService();
    }
    return service;
    }
    }

    private boolean closeThread;

    public BindService() {
    }

    @Override
    public void onCreate() {
    super.onCreate();
    new Thread(new Runnable() {
    @Override
    public void run() {
    while (!closeThread) {
    LogTool.e("BindService", "count:" + count);
    count++;
    }
    }
    }).start();
    }

    @Override
    public TestBinder onBind(Intent intent) {
    LogTool.e("BindService", "onBind");
    return binder;
    }

    @Override
    public void onDestroy() {
    super.onDestroy();
    this.closeThread = true;
    LogTool.e("BindService", "onDestroy");
    Functions.toast("BindService已停止");
    }

    @Override
    public boolean onUnbind(Intent intent) {
    LogTool.e("BindService", "onUnbind");
    return true;
    }


    public void startDownload() {
    Functions.toast("开始执行耗时任务,点击UnbindService按钮或返回按钮可取消任务");
    }

    }

    Activity中的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    binder = (BindService.TestBinder) service;
    binder.getService().startDownload();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    Functions.toast("断开连接");
    LogTool.e("BindService", "serviceDisconnected");
    }
    };

    //启动服务
    public void BindService(View v) {
    Intent intent = new Intent(this, BindService.class);
    bindService(intent, connection, Service.BIND_AUTO_CREATE);
    }

    // 取消绑定服务,边缘性处理
    public void UnbindService(View v) {
    if (binder != null) {
    unbindService(connection);
    }
    }

    示例 - 绑定型远程服务

    理解
    如何定义远程服务?
    在配置文件中添加代码android:progress=”:remote”即可
    为什么设置了Service为远程Service就不会导致ANR了?
    远程服务是指将服务放到另一个进程中执行,所以就不会导致程序的ANR现象。
    如何跨进程与Activity进行通信? 见示例
    如何实现跨程序通信?

    示例 - 实现跨进程与Activity交互

    步骤
    1.创建aidl文件,定义接口(TestInterface)及相关方法。点击make project,自动生成Stub相关的接口。
    2.创建Service类,并在ManiFest文件设置远程属性。android:process=”:remote”
    3.在Service中创建接口TestInterface.Stub 对象,重写接口方法。
    4.在Activity中通过AIDL接口的asInterface方法来获取AIDL对象。
    5.利用接口对象调用相关方法。

    1
    2
    3
    4
    5
    // 创建aidl文件,定义接口。
    package io.tanjundang.study.test.service;
    interface RemoteAidlInterface {
    void calcMsg();
    }
    1
    2
    3
    4
    // 配置服务远程属性
    <service
    android:name=".test.service.RemoteService"
    android:process=":remote" />

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // Service中创建远程接口的Stub对象
    public class RemoteService extends Service {

    RemoteAidlInterface.Stub mBinder = new RemoteAidlInterface.Stub() {
    @Override
    public void calcMsg() throws RemoteException {
    LogTool.e("RemoteService", "66666");
    }
    };

    @Override
    public Binder onBind(Intent intent) {
    return mBinder;
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    // Activity中调用远程接口的方法
    public class RemoteActivity extends AppCompatActivity {

    private RemoteAidlInterface mBinder;
    private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    mBinder = RemoteAidlInterface.Stub.asInterface(iBinder);
    try {
    mBinder.calcMsg();
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {

    }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_remote);
    }

    public void StartRemoteService(View v) {
    Intent intent = new Intent(this, RemoteService.class);
    bindService(intent, connection, BIND_AUTO_CREATE);
    }

    public void UnbindRemoteService(View v) {
    if (mBinder != null) {
    unbindService(connection);
    }
    }
    }

    示例 - 实现跨程序与Activity交互

    步骤
    实现步骤跟上面类似。只是需要为Service定义Action,以及将AIDL接口及其包名复制到另一程序中。即可实现跨程序交互。

    IntentService

    理解
    为什么有这个类?
    该类是Service的子类,主要是简化了异步操作繁琐复杂的代码。
    有什么特点?
    1.不需要自己创建子线程。
    2.不需要考虑何时关闭服务。
    使用情景是什么?
    多次调用startService。
    使用
    1.Service继承IntentService。
    2.以类名为参数调用父类构造方法。
    3.重写onHandleIntent核心方法以及其他方法。

    前台服务

    什么是前台服务?
    普通服务在内存不足的情况下会被系统杀掉,而前台服务不会因为内存不足而被杀掉。
    前台服务有什么特点?
    前台服务有通知栏提示,可设定相关的标题、提示灯。例如天气、播放器等。
    前台服务的使用
    1.构建Notification对象。
    2.通过startForeground方法启动通知栏。
    3.通过stopForeground方法关闭通知栏。
    注意
    Notification的构建中,若不调用setSmallIcon方法设置Icon,其他相关设置(标题、提示)均无效。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @Override
    public int onStartCommand(final Intent intent, int flags, final int startId) {
    final NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
    builder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(getApplicationContext(), MainActivity.class), 0));
    builder.setContentTitle("前台服务");
    //不知道什么鬼,不设置Icon,其他信息都不显示
    builder.setSmallIcon(R.drawable.ic_menu_camera);
    builder.setContentText("二级子标题");
    builder.setSubText("三级子标题");
    Notification notification = builder.build();
    //开启通知栏提示
    startForeground(startId, notification);
    LogTool.e("CalcService", "onStartCommand");
    Functions.toast("Service已启动,请查看LOG");
    total = intent.getIntExtra("msg", 100);
    return super.onStartCommand(intent, flags, startId);
    }

    Service官方文档
    郭林大神ADIL服务
    绑定服务

  • 相关阅读:
    jNotify:操作结果信息提示条
    jqurey datatable tableTools 自定义button元素 以及按钮定义事件
    jqurey datatable mRender FnRender 不起作用问题
    VS2013 ViewData ViewBag Ajax等关键词报错(当前上下文不存在名称)而且不提示也点不出来,但是可以正常运行,
    关于 update别名 与update select
    EF 保证线程内唯一 上下文的创建
    文件接收上传
    lucence.net+盘古分词
    log4net 入门教程
    MVC+EF OA观看视频记录
  • 原文地址:https://www.cnblogs.com/wxmdevelop/p/7248779.html
Copyright © 2020-2023  润新知