Service设置前台服务&提高优先级

来源:互联网 发布:c语言的主函数类型 编辑:程序博客网 时间:2024/06/05 18:53

就一点,希望大神指正本文中的错误,谢谢!有哪里我没写的或者写漏了的地方也欢迎提出来,谢谢大佬们。

1.啥是前台服务?

555,我的图片被吃了…其实所谓的前台服务就是在Service中发送了一个通知。

2.怎么设为前台服务呢?

在你的服务的onStartCommand方法里写如下代码就好了
构建Notification有两种方式,一种用于API11之后,一种用于API16之后:

 @Override    public int onStartCommand(Intent intent, int flags, int startId) {    //api11的写法        Notification.Builder builder = new Notification.Builder(this.getApplicationContext());        //intent指定点击Notification后跳转的Activity        Intent intent = new Intent(this,MainActivity.class);        builder.setContentIntent()                .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher))                // 设置下拉列表里的标题 title icon text为必需选项,这三项不设置通知不会显示。                .setContentTitle("Title")                // 设置状态栏内的小图标                .setSmallIcon(R.mipmap.ic_launcher)                // 设置上下文内容                 .setContentText("content")                // 设置该通知发生的时间                .setWhen(System.currentTimeMillis());                //设置前台服务点击后的动作(这里就是点击跳到MainActivity)            .setContentIntent(PendingIntent.getActivity(this, 0, intent , 0))        // 获取构建好的Notification        Notification notification = builder.getNotification();        //第一个参数是通知的唯一标识id,后面就是我们的通知        startForeground(12346, notification);        //API16之后的写法        Intent notificationIntent = new Intent(this, MainActivity.class);        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);        Notification notification = new Notification.Builder(this)                .setContentTitle("Title")                .setContentText("Message")                .setSmallIcon(R.mipmap.ic_launcher)                .setContentIntent(pendingIntent)                .build();        startForeground(12346, notification );        return START_STICKY;    }

提示用户去开启通知

但是有很多机型(比如说oppo)安装app的时候默认是没有发送通知的权限的,只能由用户手动去开启,而用户一般来说是不知道你需要发送通知的,在userPermission中也没有对应的权限名称,因此我们只能自己去申请权限,让用户开启,不然你的通知是没法显示的。

package com.example.servicedemo;import android.annotation.SuppressLint;import android.app.AppOpsManager;import android.content.Context;import android.content.pm.ApplicationInfo;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * Created by LZC on 2017/9/20. */public class NotificationUtil {    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";    @SuppressLint("NewApi")    public static boolean isNotificationEnabled(Context context) {        AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);        ApplicationInfo appInfo = context.getApplicationInfo();        String pkg = context.getApplicationContext().getPackageName();        int uid = appInfo.uid;        Class appOpsClass = null;      /* Context.APP_OPS_MANAGER */        try {            appOpsClass = Class.forName(AppOpsManager.class.getName());            Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE,                    String.class);            Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);            int value = (Integer) opPostNotificationValue.get(Integer.class);            return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (NoSuchFieldException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        return false;    }}

isNotificationEnabled()方法返回true则通知权限已经打开,我们就不需要做处理了,如果没有打开的话,那我们就去申请一下:

private void getAppDetailSettingIntent(Context context) {        Intent localIntent = new Intent();        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        if (Build.VERSION.SDK_INT >= 9) {            localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");            localIntent.setData(Uri.fromParts("package", getPackageName(), null));        } else if (Build.VERSION.SDK_INT <= 8) {            localIntent.setAction(Intent.ACTION_VIEW);            localIntent.setClassName("com.android.settings","com.android.settings.InstalledAppDetails");            localIntent.putExtra("com.android.settings.ApplicationPkgName", getPackageName());        }        startActivity(localIntent);    }

提高Service优先级的其他方法

  • Application加上Persistent属性。
    android:persistent=”true”放在application标签下,但是很遗憾,如果你不是做系统级应用开发的,只是普通的第三方app,那么这个属性是无效的。一般来说设为前台服务就能够满足需求。
  • 在intent fillter中设置Service的优先级
    android:priority=”1000”,其中数字越小优先级越低,1000代表优先级最高,不过这个的效果并没有设为前台服务好,这个1000的优先级顶多与前台服务的优先级相同。其实Priority属性不仅仅可以用于Service,只要是有intent fillter的组件都可以,比如说Activity和BroadcastReceiver。这个属性多是用来按指定一个执行顺序的。
<service android:name=".BindService">            <intent-filter android:priority="1000">                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE"/>            </intent-filter></service>
  • 将Service设为黏性服务
    只需要将Service的onStartCommand()方法的返回值设为START_STICKY即可。想知道为啥的可以百度onStartCommand()方法的四个返回值。
    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        return START_STICKY;    }
  • 在Service的onDestroy()里发送广播重启服务
    实现原理是Service注册广播,当服务被杀死的时候发送一条广播,监听到对应广播后在broadcastReceiver的onReceive()方法里重新开启服务。
    缺点就是很可能你的服务是被因为app直接被kill掉了,并不会走onDestroy()。
    //在Service的onCreate()中注册广播    @Override    public void onCreate() {        playerReceiver = new PlayerReceiver();        IntentFilter mFilter = new IntentFilter();        mFilter.addAction("destroy");        registerReceiver(playerReceiver, mFilter);    }
    //Service的onDestroy()发送广播    @Override    public void onDestroy() {        Intent intent = new Intent("destroy");        sendBroadcast(intent);        stopForeground(true);        super.onDestroy();    }
//onReceive()方法中根据action重新开启服务public class PlayerReceiver extends BroadcastReceiver {    public PlayerReceiver() {}    @Override    public void onReceive(Context context, Intent intent) {        String action = intent.getAction();        if("destroy".equals(action)){            MyIntentService myIntentService = new MyIntentService();            context.startService(new Intent(context,MyIntentService.class));        }    }}
  • 通过监听系统广播来重启服务
    和上面的方法类似,都是监听广播,不过一个是我们发的,一个是系统发的。
//这是静态注册receiver,你也可以动态进行注册<receiver android:name="com.example.servicedemo.MyReceiver" >            <intent-filter>                <action android:name="android.intent.action.BOOT_COMPLETED" />                <action android:name="android.intent.action.USER_PRESENT" />                <action android:name="android.intent.action.PACKAGE_RESTARTED" />            </intent-filter>        </receiver>
//onReceice()方法 @Override    public void onReceive(Context context, Intent intent) {        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {             //做你对应的操作        }        if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {             //做你对应的操作        }    }

讲到这,差不多提高服务优先级的方法就说完了。