Domanda

Ho un Service che funziona insieme alla mia applicazione principale.Lo scopo di questo servizio è sincronizzarsi con un server principale in background.Per evitare di interrogare costantemente il server principale per gli aggiornamenti, ho implementato la messaggistica cloud di Google per avvisare l'app quando ci sono modifiche da scaricare.

Quando inserisco il GcmBroadcastReceiver class nel mio pacchetto principale, riceve la multa di notifica.Tuttavia, vorrei che questo venisse ricevuto dal mio servizio, in modo che possa quindi attivare un downloadChanges() funzione anche all'interno del servizio.Non voglio davvero che l'app riceva la notifica, quindi debba usarla IPC comunicare con il servizio, sembra un po' complicato.

Esiste un modo per far sì che il mio servizio riceva la notifica GCM anziché l'app principale?

Attualmente il mio codice è così:

public class SyncService extends Service {

// lots of other stuff in this class

    public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "GCM received!");
            downloadChanges();
        }
    }
}

Tuttavia, ottengo un ClassNotFoundException quando si riceve la notifica del GCM.Qual è il modo corretto in cui il mio servizio in background gestisce una notifica GCM?

Manifesto:

<application
    android:name="com.appnl.myapp.CustomApp"
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:screenOrientation="portrait"
    android:theme="@style/AppTheme" >

    <meta-data android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />

    <!-- android.name=".GcmBroadcastReceiver" -->

    <receiver
        android:name=".GcmBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="com.appnl.gcm" />
        </intent-filter>
    </receiver>

    <service
        android:name="service.SyncService"
        android:enabled="true"
        android:exported="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/service_name" >
        <intent-filter>
            <action android:name="service.SyncService" />
        </intent-filter>
    </service>

<!-- activity list -->

Registro di sistema:

04-11 12:40:19.474: E/AndroidRuntime(28044): FATAL EXCEPTION: main
04-11 12:40:19.474: E/AndroidRuntime(28044): java.lang.RuntimeException: Unable to instantiate receiver com.appnl.myapp.GcmBroadcastReceiver: java.lang.ClassNotFoundException: Didn't find class "com.appnl.myapp.GcmBroadcastReceiver" on path: /data/app/com.appnl.myapp-1.apk
04-11 12:40:19.474: E/AndroidRuntime(28044):    at android.app.ActivityThread.handleReceiver(ActivityThread.java:2493)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at android.app.ActivityThread.access$1600(ActivityThread.java:159)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1392)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at android.os.Handler.dispatchMessage(Handler.java:99)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at android.os.Looper.loop(Looper.java:137)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at android.app.ActivityThread.main(ActivityThread.java:5419)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at java.lang.reflect.Method.invokeNative(Native Method)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at java.lang.reflect.Method.invoke(Method.java:525)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at dalvik.system.NativeStart.main(Native Method)
04-11 12:40:19.474: E/AndroidRuntime(28044): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.appnl.myapp.GcmBroadcastReceiver" on path: /data/app/com.appnl.myapp-1.apk
04-11 12:40:19.474: E/AndroidRuntime(28044):    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:64)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
04-11 12:40:19.474: E/AndroidRuntime(28044):    at android.app.ActivityThread.handleReceiver(ActivityThread.java:2488)
04-11 12:40:19.474: E/AndroidRuntime(28044):    ... 10 more

Modificare:Dovrei aggiungere che il mio servizio è in a separato pacchetto al mio pacchetto principale.Ho la sensazione che sia questo a causare il problema, ma potrei sbagliarmi.

È stato utile?

Soluzione

Il tuo problema principale è la denominazione del ricevitore nel tuo manifest.Poiché è una classe interna, è necessario includere il nome della classe esterna e aggiungere il suo nome separato da $.Esempio...

com.appnl.myapp.SyncService$GcmBroadcastReceiver

Detto questo, tuttavia, non sono sicuro che questo sia un buon modo di fare le cose.

Innanzitutto il ciclo di vita di a BroadcastReceiver è lungo quanto il onReceive(...) il metodo viene eseguito e quel metodo dovrebbe eseguire solo un lavoro minimo.A meno che il tuo downloadChanges() avvia semplicemente un'operazione asincrona di qualche tipo (e quindi ritorna immediatamente) bloccherai il file onReceive(...) metodo.

In secondo luogo il tuo approccio presuppone il Service è in esecuzione in modo permanente.Se è effettivamente così e puoi garantire che continuerà a funzionare, allora va bene, ma potresti rischiare di scaricare molto la batteria.

Se non hai bisogno di un funzionamento permanente Service allora personalmente terrei il BroadcastReceiver separare e utilizzare un IntentService Invece.Quindi riceveresti semplicemente la trasmissione e poi entreresti onReceive(...) utilizzo startService(...).Ciò garantirebbe la BroadcastReceiver ha una vita breve e un IntentService utilizza il proprio thread di lavoro (evitando così a NetworkOnMainThreadException) e si terminerà automaticamente una volta completato il suo lavoro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top