Как данные могут быть отправлены клиенту из метода run потока в службе? - PullRequest
0 голосов
/ 09 июня 2018

Я пишу программу, используя связанный сервис с межпроцессным взаимодействием (IPC).Цель состоит в том, чтобы отправить сгенерированные данные в потоке (DataExchange) из службы в mainActivity, используя Messenger и Hanler.Когда данные помещаются в очередь сообщений из метода run, я не могу получить их в activityHandler (mainActivity).к счастью, я могу получить данные в serviceHandler (локальная связь), однако, когда я пытаюсь отправить то же сообщение от serviceHandler (service) в activityHandler (mainActivity), я получаю фатальное исключение

java.lang.NullPointerException: попытка вызвать виртуальный метод 'void android.os.Messenger.send (android.os.Message)' для пустой ссылки на объект

Кто-то, пожалуйста, помогите

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

Сервис

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;
    }
    */
}

Макет

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

Манифест

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

ФАКТИЧЕСКОЕ ИСКЛЮЧЕНИЕ

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