Pergunta

Eu tenho um Service que corre ao lado da minha aplicação principal.A finalidade deste serviço é para sincronizar com um servidor principal no plano de fundo.A fim de evitar constantemente pesquisa principal do servidor de atualizações, eu tenho implementado o google cloud messaging para notificar o aplicativo quando há alterações a ser baixado.

Quando eu coloco o GcmBroadcastReceiver classe no meu principal do pacote, ele recebe a notificação de multa.No entanto, eu gostaria de esta ser recebida pelo meu serviço, para que possa desencadear uma downloadChanges() a função também dentro do serviço.Eu realmente não deseja que o aplicativo para pegar a notificação e, em seguida, tem que usar IPC para se comunicar com o serviço - que parece um pouco complicada.

Existe uma maneira para o meu serviço para receber a GCM de notificação, em vez de o aplicativo principal?

Atualmente o meu código está assim:

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();
        }
    }
}

No entanto, recebo um ClassNotFoundException ao receber a GCM de notificação.Qual é a maneira correta para o meu serviço de plano de fundo para lidar com uma GCM de notificação?

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 -->

Logcat:

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

Editar:Devo acrescentar que o meu serviço é em um separado pacote para o meu pacote principal.Eu tenho um sentimento que é o que está causando o problema, mas eu poderia estar errado.

Foi útil?

Solução

Seu principal problema é a nomeação do receptor em seu manifesto.Porque é uma classe interna ela precisa incluir o exterior nome da classe e ter seu nome anexado separados por $.Exemplo...

com.appnl.myapp.SyncService$GcmBroadcastReceiver

Ao dizer isso, no entanto, não tenho certeza se este é um bom caminho para fazer as coisas.

Em primeiro lugar, o ciclo de vida de um BroadcastReceiver é tão longa como a onReceive(...) método executa e que o método só deve fazer o mínimo de trabalho.A menos que o seu downloadChanges() método simplesmente inicia uma operação assíncrona de algum tipo (e então retorna imediatamente) irá bloquear o onReceive(...) o método.

Em segundo lugar, a sua abordagem assume que o Service é executado de forma permanente.Se isso é realmente o caso, e você pode garantir que ele continuará a executar então o que é bom, mas você pode estar correndo o risco de um monte de descarga da bateria.

Se você não precisa de um permanentemente em execução Service então eu, pessoalmente, manter o BroadcastReceiver separar e utilizar um IntentService em vez disso.Você teria, então, simplesmente de receber a transmissão e, em seguida, em onReceive(...) utilização startService(...).Isso seria garantir a BroadcastReceiver tem uma vida curta e um IntentService utiliza a sua própria thread de trabalho (evitando assim uma NetworkOnMainThreadException) e que também irá se auto-terminar depois que concluiu o seu trabalho.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top