Ich habe seit einiger Zeit eine App, in der ich einen Dienst über einen Rundfunkempfänger (MyStartupIntentReceiver) anrufe. Der Code im Rundfunkempfänger zum Aufrufen des Dienstes lautet:
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.duk3r.eortologio2.MyService");
context.startService(serviceIntent);
}
Das Problem ist, dass ich in Android 5.0 Lollipop den folgenden Fehler erhalte (in früheren Versionen von Android funktioniert alles in Ordnung):
Unable to start receiver com.duk3r.eortologio2.MyStartupIntentReceiver: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.duk3r.eortologio2.MyService }
Was muss ich ändern, damit der Dienst als explizit deklariert und normal gestartet wird? Versuchte einige Antworten in anderen ähnlichen Threads, aber obwohl ich die Nachricht loswurde, würde der Dienst nicht starten.
<intent-filter>
Sie nur eine Komponente, wenn Sie möchten, dass Apps von Drittanbietern mit dieser Komponente kommunizieren. Sie scheinen in die Falle geraten zu sein, anzunehmen, dass Sie<intent-filter>
für alles eine brauchen - in Wirklichkeit brauchen Sie selten eine<intent-filter>
. Eine expliziteIntent
ist, wenn Sie die Komponente festlegen, mit der in sichIntent
selbst gesprochen werden soll, normalerweise unter Verwendung des Konstruktors, der ein Java-Class
Objekt als zweiten Parameter verwendet. Dies sollten Sie anstelle von implizitenIntent
s und<intent-filter>
s für Komponenten verwenden, die für Ihre App lokal sind.Antworten:
Alle Absichten, die Sie in Bezug auf einen Dienst, eine Aktivität usw. in Ihrer App machen, sollten immer diesem Format folgen
Intent serviceIntent = new Intent(context,MyService.class); context.startService(serviceIntent);
oder
Intent bi = new Intent("com.android.vending.billing.InAppBillingService.BIND"); bi.setPackage("com.android.vending");
implizite Absichten (was Sie derzeit in Ihrem Code haben) gelten als Sicherheitsrisiko
quelle
bindService
?Stellen Sie Ihre
packageName
Werke ein.intent.setPackage(this.getPackageName());
quelle
Konvertieren Sie implizite Absichten in explizite Absichten und starten Sie dann den Dienst.
Intent implicitIntent = new Intent(); implicitIntent.setAction("com.duk3r.eortologio2.MyService"); Context context = getApplicationContext(); Intent explicitIntent = convertImplicitIntentToExplicitIntent(implicitIntent, context); if(explicitIntent != null){ context.startService(explicitIntent); } public static Intent convertImplicitIntentToExplicitIntent(Intent implicitIntent, Context context) { PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfoList = pm.queryIntentServices(implicitIntent, 0); if (resolveInfoList == null || resolveInfoList.size() != 1) { return null; } ResolveInfo serviceInfo = resolveInfoList.get(0); ComponentName component = new ComponentName(serviceInfo.serviceInfo.packageName, serviceInfo.serviceInfo.name); Intent explicitIntent = new Intent(implicitIntent); explicitIntent.setComponent(component); return explicitIntent; }
quelle
Versuche dies. Für mich geht das. Hier ist MonitoringService meine Serviceklasse. Ich habe zwei Aktionen, die anzeigen, dass der Dienst gestoppt oder gestartet werden soll. Ich sende diesen Wert von meinem Rundfunkempfänger abhängig von AIRPLANE_MODE_CHANGED .
@Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(Intent.ACTION_AIRPLANE_MODE_CHANGED.equalsIgnoreCase(action)){ boolean isOn = intent.getBooleanExtra("state", false); String serviceAction = isOn? MonitoringService.StopAction : MonitoringService.StartAction; Intent serviceIntent = new Intent(context, MonitoringService.class); serviceIntent.setAction(serviceAction); context.startService(serviceIntent); } }
HINWEIS: Ich füge folgenden Code hinzu, um meinen Broadcast-Empfänger mit dem Namen " ManageLocationListenerReceiver" auszulösen .
<receiver android:name=".ManageLocationListenerReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.AIRPLANE_MODE" /> </intent-filter> </receiver>
quelle
Ich habe die Antwort von Shahidul verbessert, um die Kontextabhängigkeit zu beseitigen:
public class ServiceUtils { public static void startService(String intentUri) { Intent implicitIntent = new Intent(); implicitIntent.setAction(intentUri); Context context = SuperApplication.getContext(); Intent explicitIntent = convertImplicitIntentToExplicitIntent(implicitIntent, context); if(explicitIntent != null){ context.startService(explicitIntent); } } private static Intent convertImplicitIntentToExplicitIntent(Intent implicitIntent, Context context) { PackageManager pm = context.getPackageManager(); List<ResolveInfo> resolveInfoList = pm.queryIntentServices(implicitIntent, 0); if (resolveInfoList == null || resolveInfoList.size() != 1) { return null; } ResolveInfo serviceInfo = resolveInfoList.get(0); ComponentName component = new ComponentName(serviceInfo.serviceInfo.packageName, serviceInfo.serviceInfo.name); Intent explicitIntent = new Intent(implicitIntent); explicitIntent.setComponent(component); return explicitIntent; } }
Innerhalb der SuperApplication-Klasse:
public class SuperApplication extends Application { private static MyApp instance; public static SuperApplication getInstance() { return instance; } public static Context getContext(){ return instance; // or return instance.getApplicationContext(); } @Override public void onCreate() { instance = this; super.onCreate(); } }
In Ihrem Manifest:
<application android:name="com.example.app.SuperApplication " android:icon="@drawable/icon" android:label="@string/app_name" ....... <activity ......
Und dann rufen Sie einfach an:
ServiceUtils.startService("com.myservice");
quelle