Android——service

原创 2016年08月29日 08:45:22

Android Service

  • android中service主要有本地service(localService)远程service(remoteService)

  • 启动service的方式主要有直接启动(startService)绑定启动(bindService)

  • 本文还将介绍一个较为普遍的service灰色保活手段。

demo下载地址:http://download.csdn.net/detail/sapce_fish/9616181

本地service(localService)
1.编写service类(在service创建后会启动一个线程,模拟在service中的任务)

package com.space.service.local;

import android.app.Service;
import android.content.Intent;
import android.os.*;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by space on 2016/8/26.
 */
public class LocalService extends Service{
    private final static String TAG = "LocalService";

    private boolean mIsRun;

    private LocalBind mLocalBind;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("space", TAG+"---onBind()");
        return mLocalBind;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("space", TAG + "---onCreate() Process.myPid=" + android.os.Process.myPid());
        startDownload();
        mLocalBind = new LocalBind();
    }

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

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("space", TAG + "---onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("space", TAG + "---onDestroy()");
        mIsRun = false;
    }


    public class LocalBind extends Binder{
        public void localDownload(){
            if(!mIsRun){
                startDownload();
            }else{
                Log.i("space", TAG + "---------下载任务正在进行");
            }
        }
    }

    private void startDownload(){
        mIsRun = true;
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for(int i=0;i<1000 && mIsRun;i++){
                        Log.i("space", TAG + "---------下载线程在执行 " + i);
                        Thread.sleep(5 * 1000);
                    }
                    Log.i("space", TAG + "---下载线程执行完了 ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

2.Manifest中注册service

<service android:name=".local.LocalService"
            android:label="测试localService"></service>

3.启动service

直接启动

startService(new Intent(this,LocalService.class));

关闭

stopService(new Intent(this, LocalService.class));

bind启动

bindService(new Intent(this, LocalService.class), mLocalSerConn, BIND_AUTO_CREATE);

解除绑定

if(mIsBindLocal){
      unbindService(mLocalSerConn);
      mIsBindLocal = false;
 }else{
      Log.i(TAG,"还没有绑定service");
 }

两种启动方式对比:

情况\启动方式 直接启动service bind启动
启动方式 startService bindService
关闭方式 stopService unbindService
finish acitivty 不会关闭 会关闭
开启后调用service中的方法 不可调用 可通过返回的bind调用


注:service是运行在主线程上的,如果需要在service中做耗时操作,避免ANR则需要在service中开线程执行


远程service(remoteService)
1.定义aidl接口文件

package com.space.service.remote;
interface IRemote{
    String remoteDownload(String parame);
}

2.编写service类(在service创建后会启动一个线程,模拟在service中的任务)

package com.space.service.remote;

import android.app.Service;
import android.content.Intent;
import android.os.*;
import android.os.Process;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by space on 2016/8/26.
 */
public class RemoteService extends Service {

    private final String TAG = "RemoteService";
    private boolean mIsRun;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("space",TAG+"---onBind()");
        return remoteBind;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        startDownload();
        Log.i("space", TAG + "---onCreate() Process.myPid="+ Process.myPid());
    }

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

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("space", TAG + "---onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("space", TAG + "---onDestroy()");
        mIsRun = false;
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        Log.i("space", TAG + "---onLowMemory()");
    }

    public IRemote.Stub remoteBind = new IRemote.Stub() {
        @Override
        public String remoteDownload(final String parame) throws RemoteException {
            Log.i("space", TAG + "---------接收到的参数为 " + parame);
            if(!mIsRun){
                startDownload();
            }else{
                Log.i("space", TAG + "---------下载任务正在进行");
            }
            return "success";
        }
    };

    private void startDownload(){
        mIsRun = true;
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for(int i=0;i<1000 && mIsRun;i++){
                        Log.i("space", TAG + "---------下载线程在执行 " + i);
                        Thread.sleep(5 * 1000);
                    }
                    Log.i("space", TAG + "---下载线程执行完了 ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

3.在Manifest中注册service

<service android:name=".remote.RemoteService"
            android:process=":remotefff"
            android:label="测试remoteService">
            <intent-filter>
                <action android:name="com.space.service.remoteService"/>
            </intent-filter>
        </service>

4.启动service

直接启动

Intent i = new Intent();
i.setAction("com.space.service.remoteService");
startService(new Intent(createExplicitFromImplicitIntent(this,i)));

关闭

Intent in = new Intent();
in.setAction("com.space.service.remoteService");
stopService(new Intent(createExplicitFromImplicitIntent(this,in)));

bind启动

Intent intent = new Intent();
intent.setAction("com.space.service.remoteService");
Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent));
mIsBindRemote = bindService(eintent, mRemoteSerConn, BIND_AUTO_CREATE);

解除绑定

if(mIsBindRemote){
      unbindService(mRemoteSerConn);
      mIsBindRemote = false;
}else{
       Log.i(TAG,"还没有绑定 remote service");
}

因为直接用隐式intent的方法启动service会报异常,另外一种启动方式如下:

public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
        //Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
        //Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }
        //Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);
        //Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);
        //Set the component to be explicit
        explicitIntent.setComponent(component);
        return explicitIntent;
    }

本地service与远程service对比:

情况\service 本地service 远程service
进程 与APP同一进程 不与APP同一进程
与Activity的通信方式 本进程内通信 跨进程通信
Activity被kill 服务停止 服务不受影响(但是当系统内存不足时会被kill)


service灰色保活

之所以称为灰色保活是因为这种保活手段是利用系统漏洞,来提升service的优先级,使service尽量保持运行,实际上许多app都利用此漏洞来保活service。
思路是:API < 18,启动前台Service时直接传入new Notification();
API >= 18,同时启动两个id相同的前台Service,然后再将后启动的Service做stop处理;
知道此种实现得益于看到的另外一篇文章,在此对作者表示感谢,附上文章地址:http://www.jianshu.com/p/63aafe3c12af

首先我们来看一下各大应用是否有使用此种方式来保活service

手机连上电脑打开cmd窗口,手机上打开应用QQ,清空通知栏,然后在cmd窗口中输入

adb shell dumpsys activity services com.tencent.mobileqq

qq测试截图
通知栏截图
通知栏没有看到QQ的 Notification 但是看到 isForeground=true 则说明QQ利用了这种灰色保活的手段,其他应用大家有兴趣也可以试一下,那我们来看一下灰色保活的具体实现。

灰色保活的实现方式

package com.space.service.gray;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
/**
 * Created by space on 2016/8/28.
 */
public class GrayService extends Service{
    private final static String TAG = "GrayService";
    private final static int GRAY_SERVICE_ID = 1111;
    private boolean mIsRun;
    @Override
    public void onCreate() {
        super.onCreate();
        startDownload();
        Log.i("space", TAG + "---onCreate() Process.myPid=" + android.os.Process.myPid());
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("space", TAG + "---onbind");
        return null;
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("space", TAG + "---onStartCommand()");
        if (Build.VERSION.SDK_INT < 18) {
            Log.i("space",TAG+"api<18");
            startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 ,此方法能有效隐藏Notification上的图标
        } else {
            Log.i("space",TAG+"api>18");
            Intent innerIntent = new Intent(this, GrayInnerService.class);
            startService(innerIntent);
            startForeground(GRAY_SERVICE_ID, new Notification());
        }
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void unbindService(ServiceConnection conn) {
        super.unbindService(conn);
        Log.i("space", TAG + "---onUnbind");
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("space", TAG + "---onDestroy()");
        mIsRun = false;
    }
    @Override
    public void onLowMemory() {
        super.onLowMemory();
        Log.i("space", TAG + "---onLowMemory()");
    }
    private void startDownload(){
        mIsRun = true;
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for(int i=0;i<1000 && mIsRun;i++){
                        Log.i("space", TAG + "---------下载线程在执行 " + i);
                        Thread.sleep(5 * 1000);
                    }
                    Log.i("space", TAG + "---下载线程执行完了 ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    /**
     * 给 API >= 18 的平台上用的灰色保活手段
     */
    public static class GrayInnerService extends Service {
        private final static String TAG = "GrayInnerService";
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i("space", TAG + "---onCreate");
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i("space", TAG + "---onStartCommand");
            startForeground(GRAY_SERVICE_ID, new Notification());
            stopForeground(true);
            stopSelf();
            return super.onStartCommand(intent, flags, startId);
        }
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i("space", TAG + "---onDestroy");
        }
        @Override
        public void onLowMemory() {
            super.onLowMemory();
            Log.i("space", TAG + "---onLowMemory");
        }
    }
}

在Manifest中注册service

<service android:name=".gray.GrayService"
            android:label="测试grayService"></service>
        <service android:name=".gray.GrayService$GrayInnerService"
            android:label="测试GrayInnerService"></service>

开启service

startService(new Intent(this, GrayService.class));

关闭service

stopService(new Intent(this, GrayService.class));

至此已经介绍了localService与remoteService的使用
另外如果有不明白的地方可以留言。有写错或者不好的地方欢迎指正

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android中的Service与进程间通信(IPC)详解

Service 什么是Service 在后台长期运行的没有界面的组件。其他组件可以启动Service让他在后台运行,或者绑定Service与它进行交互,甚至实现进程间通信(IPC)。例如,可以让服...
  • linchaolong
  • linchaolong
  • 2016年04月27日 20:38
  • 6307

Android Service最全面的解析

刘明渊 的博客地址:http://blog.csdn.net/vanpersie_9987 Service Service是Android中一个类,它是Android四大组件之一,使用S...
  • scott2017
  • scott2017
  • 2016年05月26日 11:41
  • 29107

Android Service的启动过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作。其实不然,Service是运行在主线程的。直接执行耗时操作是会...
  • qq_35114086
  • qq_35114086
  • 2016年10月15日 19:51
  • 547

Android Service(二) Service使用

上篇文章,我们只是翻译了Android官方文档,今天就通过实例来演示Service的启动以及生命周期等特征。 一、实战演示。 1.新建工程,创建项目。 2.新建一个类,继承自Service,实现它的o...
  • zxw136511485
  • zxw136511485
  • 2016年12月14日 11:21
  • 1201

关于Android Service真正的完全详解,你需要知道的一切

Service 1.Service基础知识概述   Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一...
  • javazejian
  • javazejian
  • 2016年10月07日 08:11
  • 49549

一个Android Service小例子

写过一些android程序,但是android中的Service的组件却不曾用过,因此,对它也不甚了解,所以,今天写个小例子来学习如何使用Service。这其实也是我学习新东西的一个方法,对于陌生的东...
  • u012398902
  • u012398902
  • 2015年11月30日 18:18
  • 1943

Android研发安全3-Service安全

在Android系统开发中,Service是一个重要的组成部分。如果现在某些程序中的某部分操作是很耗时的,那么可以将这些程序定义在Service中,这样就可以在后台运行,也可以在不显示界面的形式下运行...
  • mynameishuangshuai
  • mynameishuangshuai
  • 2016年10月30日 18:05
  • 6112

android中Service使用详解

service用于长期在后台处理任务,而不需要对用户可见。 service有2种基本的启动方式: startService():使用这种方式,来进行单一的任务,不需要返回结果给调用者 bindServ...
  • baidu_26994091
  • baidu_26994091
  • 2016年06月29日 01:51
  • 12335

Android中Service的一个Demo例子

Android中Service的一个Demo例子  Service组件是Android系统重要的一部分,网上看了代码,很简单,但要想熟练使用还是需要Coding。  本文,主要贴代码,不对Servic...
  • FansUnion
  • FansUnion
  • 2015年11月14日 17:58
  • 3377

Android四大组件之Service工作原理

Servie的工作过程 As we all know, Service分为两种工作状态,一种是启动状态,主要用于执行后台计算,另外一种是绑定状态,主要用于其他组件和Service交互。需要注意的是Se...
  • tianmi1988
  • tianmi1988
  • 2016年03月19日 20:42
  • 1162
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android——service
举报原因:
原因补充:

(最多只允许输入30个字)