Issue
I am trying to implement a callback listener inside my GcmListenerService. I need to refresh a chat conversation as a new message arrives.
I proceed as usual, set up the listener inside the host activity, and the service, but I get the following error when the my callback listener starts showing results:
FATAL EXCEPTION: AsyncTask #1 java.lang.NullPointerException
at com.cerculdivelor.gcm.MyGcmListenerService.onMessageReceived(MyGcmListenerService.java:69)
at com.google.android.gms.gcm.GcmListenerService.zzq(Unknown Source)
at com.google.android.gms.gcm.GcmListenerService.zzp(Unknown Source)
at com.google.android.gms.gcm.GcmListenerService.zzo(Unknown Source)
at com.google.android.gms.gcm.GcmListenerService.zza(Unknown Source)
at com.google.android.gms.gcm.GcmListenerService$1.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
What could be wrong, is maybe a bad approach to use callbacks inside a Service??
GcmListenerService:
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
private SQLiteDataSource datasource;
newMessageListener mListener;
/**
* Called when message is received.
*
* @param from SenderID of the sender.
* @param data Data bundle containing message data as key/value pairs.
* For Set of keys use data.keySet().
*/
// [START receive_message]
@Override
public void onMessageReceived(String from, Bundle data) {
if (data.getString("notiftype") != null && data.getString("notiftype").equals("message")) {
datasource = new SQLiteDataSource(this);
datasource.open();
MessagesSetter message = new MessagesSetter();
message.setConversationId(data.getString("conversationId"));
message.setSenderfbid(data.getString("senderfbid"));
message.setSendername(data.getString("sendername"));
message.setProdname(data.getString("prodname"));
message.setMessage(data.getString("message"));
message.setTime(data.getString("timestamp"));
message.setAction(data.getString("action"));
Log.i("TAG", data.getString("message"));
datasource.addMessage(message);
showMessageNotification(data);
//refresh the conversation in ConversationActivity
mListener.newMessageArieved();
}
...
// Interface to send selected image's position for deletion
public void setNewMessageListener(newMessageListener mListener) {
this.mListener = mListener;
}
public static interface newMessageListener {
public void newMessageArieved ();
}
}
Host Activity:
public class ConversationActivity extends AppCompatActivity implements MyGcmListenerService.newMessageListener {
private ListView listview;
private SQLiteDataSource datasource;
private Bundle extras;
private String myFbId;
private String senderFbId;
private String conversationId;
private EditText replyText;
private ImageView sendReplyBtn;
private HttpConActivity http;
private ArrayList<MessagesSetter> conversation;
private String myName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.conversation_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.messageToolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
SharedPreferences preferences = getSharedPreferences("user",
MODE_PRIVATE);
myFbId = preferences.getString("fbId", "");
myName = preferences.getString("name", "");
extras = getIntent().getExtras();
if (extras != null) {
conversationId = extras.getString("conversationId");
}
//set up the listener for new message arievals
MyGcmListenerService serv = new MyGcmListenerService();
serv.setNewMessageListener(this);
...
@Override
public void newMessageArieved() {
conversation = datasource.getConversation(conversationId);
ConversationListViewAdapter messAdapt = new ConversationListViewAdapter(this,
R.layout.conversation_row_layout, conversation);
listview.setAdapter(messAdapt);
Log.i("TAG", "NEW MESSAGE!");
}
Solution
I'm not entirely sure if using callbacks inside a service is against best practice and all, but what I would do in your situation would be to have a constructor for MyGcmListenerService
that takes your listener as a parameter. Something like this:
public MyGcmListenerService(newMessageListener listener){
this.mListener = listener;
}
So that you can just set immediately upon initializing the service.
I'd still keep the setter for the listener though, just in case.
Then in the onMessageReceived
, I'd just include a null checker, just in case that there is no listener set, like so:
if (mListener != null){
mListener.newMessageArieved();
} else {
Log.d(TAG, "No new message listener set.");
}
Your logs show an NPE but I'm not so sure if the listener is causing it though. Have you made some tests (adding logs and stuff like that) to verify what exactly is causing the NPE?
Answered By - AL.