就一点,希望大神指正本文中的错误,谢谢!有哪里我没写的或者写漏了的地方也欢迎提出来,谢谢大佬们。
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())) {
//做你对应的操作
}
}
讲到这,差不多提高服务优先级的方法就说完了。