Android——service

来源:互联网 发布:建筑论文怎么写 知乎 编辑:程序博客网 时间:2024/06/15 12:26

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的使用
另外如果有不明白的地方可以留言。有写错或者不好的地方欢迎指正

0 0