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

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

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())) {
             //做你对应的操作
        }
    }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值