I'm writing a program using bound service with Inter Process Communication(IPC). The goal is to send the generated data in a thread (DataExchange) from the service to the mainActivity, using Messenger and Hanler. When the data is placed in the message queue from run method, I'm unable to receive it in the activityHandler (mainActivity). fortunatly I can receive the data in the serviceHandler (Local communication), however when I try to send the same message from the serviceHandler (service) to activityHandler (mainActivity), I'm getting a FATAL EXCETION
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Messenger.send(android.os.Message)' on a null object reference
Someone please help
MainActivity
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int WRITE = 2;
private static final int READ = 3;
private static final int SEND = 4;
private static final int UPDATE = 5;
TextView textView;
Messenger activityMessenger;
boolean bound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R. id. textView);
Intent bindBtService = new Intent(this, BluetoothService.class);
bindService(bindBtService, serviceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
activityMessenger = new Messenger(service);
bound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
unbindService(serviceConnection);
activityMessenger = null;
bound = false;
}
};
//Send a command to the service requesting data update
public void getMessage(View view) {
String button_text = (String) ((Button)view).getText();
if (button_text.equals("Message from the service")){
//create a message object
Message msg = Message.obtain(null, WRITE);
//specify the reply handler
msg.replyTo = new Messenger(new activityHandler());
try {
activityMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
/*To process Incoming massages from the service*/
class activityHandler extends Handler{
@Override
public void handleMessage(Message msg) {
String received;
switch (msg.what){
case READ:
received = msg.getData().getString("response_message");
Log.i(TAG, "From ButtonClick " + received);
textView.setText(received);
break;
case UPDATE:
received = msg.getData().getString("update");
//for debugging
Log.i(TAG, "From Run Method " + received);
textView.setText(received);
break;
default:
super.handleMessage(msg);
}
}
}
@Override
protected void onDestroy() {
unbindService(serviceConnection);
activityMessenger = null;
bound = false;
super.onDestroy();
}
}
Service
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import java.util.Random;
public class BluetoothService extends Service {
private static final String TAG = BluetoothService.class.getSimpleName();
private static final int MAC_ADDRESS = 1;
private static final int WRITE = 2;
private static final int READ = 3;
private static final int SEND = 4;
private static final int UPDATE = 5;
private String Data = " ";
private String incomingData;
private DataExchange dataExchange;
private Rand randomize;
//Messenger serviceMessenger;
Messenger serviceMessenger = new Messenger(new ServiceHandler());
public BluetoothService() {
//Log.i(TAG, "Inside CONSTRUCTOR");
incomingData = Data;
}
@Override
public void onCreate() {
super.onCreate();
//Log.i(TAG, "Inside ONCREATE");
//serviceMessenger = new Messenger(new ServiceHandler());
//create a new thread with a serviceHandler object
dataExchange = new DataExchange(new ServiceHandler());
dataExchange.start();
}
/*Setter and Getter to set the data from the Rand Thread class
* to be retrieved in the serviceHandler class
*/
private synchronized void setIncomingData(String rando){
incomingData = rando;
}
public synchronized String getIncomingData(){
return incomingData;
}
/*Pass the binding object Messenger with a reference of the serviceHandler
*to perform IPC communication
*/
@Override
public IBinder onBind(Intent intent) {
return serviceMessenger.getBinder();
}
class ServiceHandler extends Handler{
Messenger mess;
Message message;
String response = " ";
Bundle bundle = new Bundle();
@Override
public void handleMessage(Message msg) {
switch (msg.what){
/*Process the request from the activity and send data to update
*the textView on mainActivity
*/
case WRITE:
randomize = new Rand();
randomize.start();
while (getIncomingData().equals(" "));
//Log for debug proposes
//Log.i(TAG, "Random Number: " + getIncomingData());
response = getIncomingData();
message = Message.obtain(null, READ);
bundle.putString("response_message", response);
message.setData(bundle);
try {
msg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
/*GET THE DATA FROM RUN METHOD AND SEND IT TO mainActivity*/
case SEND:
response = msg.getData().getString("message");
//Log for debug proposes
//Log.i(TAG, "Random Number: " );
/*Initiate message object with a identifier*/
message = Message.obtain(null, UPDATE);
//Put the and a keyword and the string message into a bundle
bundle.putString("update", response);
//Pass the bundle to the message object
message.setData(bundle);
try {
/* place the message into the message queue
* replyTo returns a reference from the receive Handler
* in this case the receive handler is the activityHandle
*/
msg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
default:
super.handleMessage(msg);
}
}
}
/*USING GETTER AND SETTER TO PASS DATA TO THE SERVICE HANDLER*/
private class Rand extends Thread{
public Rand() {
//Log for debug proposes
//Log.i(TAG, "Inside the thread");
}
@Override
public void run() {
//generate random numbers
Random random = new Random();
int number = random.nextInt(10) + 1;
//converts integer to string
String rando = String.valueOf(number);
//Log for debug proposes
Log.i(TAG, "Random Number has been set to :" + rando);
//Set data to be collected into the serviceHandler class
setIncomingData(rando);
SystemClock.sleep(50);
setIncomingData(" ");
}
}
/*USING HANDLER FOR COMMUNICATION*/
private class DataExchange extends Thread implements Runnable{
Handler serviceHandler;
public DataExchange(ServiceHandler serviceHandler) {
super();
//new object of the handler class to process communication
this.serviceHandler = serviceHandler;
}
@Override
public void run() {
for (int i = 0; i < 100; i++){
String val = String.valueOf(i);
try {
Thread.sleep(1000);
Message msg = prepareMessage(val);
//place message on the messageQueue
//serviceHandler.sendMessage(msg);
try {
serviceMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*prepare the message with a identifier, a key word and a string message
* id : UPDATE and key word :update defines a message to be sent
* to the mainActivity (Inter Process Communication "IPC")
* id : SEND and key word :message defines a message to be sent
* to the serviceHandler (Local communication)
* */
private Message prepareMessage(String string){
Bundle dataBundle = new Bundle();
/*For IPC communication*/
//Message result = serviceHandler.obtainMessage(UPDATE);
//dataBundle.putString("update", string);
/*For LOCAL communication*/
Message result = serviceHandler.obtainMessage(SEND);
dataBundle.putString("message", string);
result.setData(dataBundle);
return result;
}
}
/*
@Override
public void onDestroy() {
super.onDestroy();
serviceMessenger = null;
dataExchange = null;
}
*/
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="32dp"
android:textSize="36sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text=" "
tools:textSize="30sp" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginEnd="148dp"
android:layout_marginLeft="148dp"
android:layout_marginRight="148dp"
android:layout_marginStart="148dp"
android:layout_marginTop="128dp"
android:onClick="getMessage"
android:text="Message from the service"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Message" />
</android.support.constraint.ConstraintLayout>
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.seber.lisah">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".BluetoothService"
android:enabled="true"
android:exported="true"></service>
</application>
</manifest>
FATAL EXCEPTION
06-08 16:53:14.466 2072-2072/com.seber.lisah E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.seber.lisah, PID: 2072
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Messenger.send(android.os.Message)' on a null object reference
at com.seber.lisah.BluetoothService$ServiceHandler.handleMessage(BluetoothService.java:111)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)