A recepção de um GCM de notificação dentro do Android serviço
-
21-12-2019 - |
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.
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.