0

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)
seberix
  • 1
  • 1
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Capricorn Jun 08 '18 at 21:37
  • @Capricorn, Thank you very much for your answer. According to the article on your link, the NullPointerException (NPE) is thrown if ones forget to initialize a method. In this case, I am initializing Message each time I want to send a message in terms to pass the handler reference, the id, and a bundle just the way the handler documentation proposes { message = Message.obtain(null, READ); and message.setData(bundle);}. This way I should be able to use the Message component msn without getting a NPE – seberix Jun 09 '18 at 04:41

0 Answers0