Service显示启动和隐式启动

1,显示启动 
  • 直接上代码一目了然,不解释了。
 
//显示启动
Intent intent = new Intent(this,ForegroundService.class);
startService(intent);
 
2, 隐式启动 
  • 需要设置一个Action,我们可以把Action的名字设置成Service的全路径名字,在这种情况下android:exported默认为true。
final Intent serviceIntent=new Intent(); 
serviceIntent.setAction("com.android.ForegroundService");
startService(serviceIntent);
 
3,  存在的意义 
  • 如果在同一个应用中,两者都可以用。在不同应用时,只能用隐式启动。
 
 
4, Android 5.0以上的隐式启动问题 
  • Android 5.0之后google出于安全的角度禁止了隐式声明Intent来启动Service。如果使用隐式启动Service,会出没有指明Intent的错误,如下: 
Service显示启动和隐式启动_第1张图片
 
【1】主要原因
我们可以从源码中找到,这里看看Android 4.4的ContextImpl源码中的validateServiceIntent(Intent service),可知如果启动service的intent的component和package都为空并且版本大于KITKAT的时候只是报出一个警报,告诉开发者隐式声明intent去启动Service是不安全的.
Service显示启动和隐式启动_第2张图片
 
而在android5.0之后呢?我们这里看的是android6.0的源码如下
Service显示启动和隐式启动_第3张图片
源码可以看出如果启动service的intent的component和package都为空并且版本大于LOLLIPOP(5.0)的时候,直接抛出异常,该异常与之前隐式启动所报的异常时一致的。
 
【2】解决方式:
  • 设置Action和packageName
final Intent serviceIntent=new Intent(); serviceIntent.setAction("com.android.ForegroundService");
serviceIntent.setPackage(getPackageName());//设置应用的包名
startService(serviceIntent);

 

  • 将隐式启动转换为显示启动
public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
    // Retrieve all services that can match the given intent
     PackageManager pm = context.getPackageManager();
     List 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;
    }

 

 
  • 调用方式如下:
Intent mIntent=new Intent();//辅助Intent
mIntent.setAction("com.android.ForegroundService");
final Intent serviceIntent=new Intent(getExplicitIntent(this,mIntent));
startService(serviceIntent);

 

 
 
 
 
关于更多Service内容: https://blog.csdn.net/cricket_7/category_9580061.html
 
 
 
 
 

你可能感兴趣的:(Android,Service)