开发者

Getting a strange NPE in one of my Bluetooth classes, it didn't happen before

Using Android's Bluetooth Chat sample app as my guide http://developer.android.com/resources/samples/BluetoothChat/index.html, I've tried to create my own bluetooth function for an app I am working on.

Last night I tested it with two Android phones and had some issues, but there were no force closes. It simply didn't connect my devices when I asked it to. I went in and added a few Log lines to make sure the program was following the proper course. When I reinstalled and launched the app on my phone today, I got a force close error when attempting to turn on Bluetooth, a problem I did not have at all last night. The only code I changed was the addition of 2-3 log commands. I checked logcat and got the following:

Getting a strange NPE in one of my Bluetooth classes, it didn't happen before

As you can see, the problem is caused by an NPE @ line 185. Here is my code for the BluetoothService class, I will repost the specific area of issue below it.

package com.tagapp.android;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class BluetoothService {

    private static final String TAG = "BluetoothService";
    private static final boolean D = true;
    private static final String NAME = "BluetoothTag";
    private static final UUID MY_UUID = 
        UUID.fromString("93845760-234e-11e0-ac64-0800200c9a66");

    private final BluetoothAdapter mAdapter;
    private final Handler mHandler;
    private AcceptThread mAcceptThread;
    private ConnectThread mConnectThread;
    private ConnectedThread mConnectedThread;
    private int mState;

    public static final int STATE_NONE = 0;
    public static final int STATE_LISTEN = 1;
    public static final int STATE_CONNECTING = 2;
    public static final int STATE_CONNECTED = 3;

    public BluetoothService(Context context, Handler handler) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        mHandler = handler;
    }

    private synchronized void setState(int state) {
        if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
        mState = state;
        mHandler.obtainMessage(BluetoothTransfer.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
    }

    public synchronized int getState() {
        return mState;
    }

    public synchronized void start() {
        if (D) Log.d(TAG, "start");

        if(mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }

        if(mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        if(mAcceptThread == null) {
            mAcceptThread = new AcceptThread();
            mAcceptThread.start();
        }
        setState(STATE_LISTEN);
    }

    public synchronized void connect(BluetoothDevice device) {
        if (D) Log.d(TAG, "connect to: " + device);
        if(mState == STATE_CONNECTING) {
            if(mConnectThread != null) {
                mConnectThread.cancel();
                mConnectThread = null;
            }
        }
        if(mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }
        mConnectThread = new ConnectThread(device);
        mConnectThread.start();
        setState(STATE_CONNECTING);
    }

    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
        if (D) Log.d(TAG, "connected");

        if(mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }

        if(mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        if(mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }
        mConnectedThread = new ConnectedThread(socket);
        mConnectedThread.start();
        Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_DEVICE_NAME);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothTransfer.DEVICE_NAME, device.getName());
        msg.setData(bundle);
        mHandler.sendMessage(msg);
        setState(STATE_CONNECTED);
    }

    public synchronized void stop() {
        if (D) Log.d(TAG, "stop");

        if(mConnectThread != null) {
            mConnectThread.cancel();
            mConnectThread = null;
        }

        if(mConnectedThread != null) {
            mConnectedThread.cancel();
            mConnectedThread = null;
        }

        if(mAcceptThread != null) {
            mAcceptThread.cancel();
            mAcceptThread = null;
        }
        setState(STATE_NONE);
    }

    public void write(byte[] out) {
        ConnectedThread ct;
        synchronized(this) {
            if(mState != STATE_CONNECTED) return;
            ct = mConnectedThread;
        }
        ct.write(out);
    }

    private void connectionFailed() {
        setState(STATE_LISTEN);
        Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothTransfer.TOAST, "Unable to connect device");
        msg.setData(bundle);
        mHandler.sendMessage(msg);
    }

    private void connectionLost() {
        setState(STATE_LISTEN);
        Message msg = mHandler.obtainMessage(BluetoothTransfer.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothTransfer.TOAST, "Device connection was lost");
        msg.setData(bundle);
        mHandler.sendMessage(msg);
    }

    private class AcceptThread extends Thread {
        private final BluetoothServerSocket mmServerSocket;

        public AcceptThread() {
            BluetoothServerSocket tmp = null;
            try {
                tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
            }
            catch (IOException e) {
                Log.e(TAG, "listen() failed", e);
            }
            mmServerSocket = tmp;
        }

        public void run() {
            if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
            setName("AcceptThread");
            BluetoothSocket socket = null;
            while (mState != STATE_CONNECTED) {
                try {
                    socket = mmServerSocket.accept();
                }
                catch (IOException e) {
                    Log.e(TAG, "accept() failed", e);
                    break;
                }
                if(socket != null) {
                    synchronized (BluetoothService.this) {
                        switch(mState) {
                        case STATE_LISTEN :
                        case STATE_CONNECTING :
                            connected(socket, socket.getRemoteDevice());
                            break;
                        case STATE_NONE :
                        case STATE_CONNECTED :
                            try {
                                socket.close();
                            }
                            catch (IOException e) {
                                Log.e(TAG, "Could not close unwanted socket", e);
                            }
                            break;
                        }
                    }
                }
            }
            if (D) Log.i(TAG, "END mAcceptThread");
        }

        public void cancel() {
            if (D) Log.d(TAG, "cancel " + this);
            try {
                mmServerSocket.close();
            }
            catch (IOException e) {
                Log.e(TAG, "close() of server failed", e);
            }
        }
    }

    private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;

        public ConnectThread(BluetoothDevice device) {
            mmDevice = device;
            BluetoothSocket tmp = null;
            try {
                tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
            }
            catch (IOException e) {
                Log.e(TAG, "create() failed", e);
            }
            mmSocket = tmp;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectThread");
            setName("ConnectThread");
            mAdapter.cancelDiscovery();
            try {
                mmSocket.connect();
            }
            catch (IOException e) {
                connectionFailed();
                try {
                    mmSocket.close();
                }
                catch (IOException e2) {
                    Log.e(TAG, "unable to close() socket during connection failure", e2);
                }
            BluetoothService.this.start()开发者_如何学运维;
            return;
            }
            synchronized (BluetoothService.this) {
                mConnectThread = null;
            }
            connected(mmSocket, mmDevice);
        }

        public void cancel() {
            try {
                mmSocket.close();
            }
            catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }

    private class ConnectedThread extends Thread {

        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "create ConnectedThread");
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            }
            catch (IOException e) {
                Log.e(TAG, "tempt sockets not created", e);
            }
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;
            while (true) {
                try {
                    bytes = mmInStream.read(buffer);
                    mHandler.obtainMessage(BluetoothTransfer.CONTACT_RECEIVE, bytes, -1, buffer).sendToTarget();
                }
                catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    break;
                }
            }
        }

        public void write(byte[] buffer) {
            try {
                mmOutStream.write(buffer);
                mHandler.obtainMessage(BluetoothTransfer.CONTACT_SEND, -1, -1, buffer).sendToTarget();
            }
            catch (IOException e) {
                Log.e(TAG, "exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            }
            catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }
}

The lines which are causing the NPE (the AcceptThread):

private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;

    public AcceptThread() {
        BluetoothServerSocket tmp = null;
        try {
            tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        }
        catch (IOException e) {
            Log.e(TAG, "listen() failed", e);
        }
        mmServerSocket = tmp;
    }

    public void run() {
        if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
        setName("AcceptThread");
        BluetoothSocket socket = null;
        while (mState != STATE_CONNECTED) {
            try {
                socket = mmServerSocket.accept();//THIS LINE CAUSES NPE
            }
            catch (IOException e) {
                Log.e(TAG, "accept() failed", e);
                break;
            }

The object socket should by initialized @ null, but it is supposed to try socket = mmServerSocket.accept();

This is directly from Google's sample app provided on the Android dev website. I have two concerns: 1, why isn't this working, and 2, why did it work just fine just hours ago?

Thanks for your help.


Regarding "strange NPE" - it's not strange at all. The reason you get NPE at this line

socket = mmServerSocket.accept(); //THIS LINE CAUSES NPE

is pretty obvious - variable mmServerSocket equals NULL, and this is the only possible reason to get NPE at this line of code. The reason why mmServerSocket equals NULL is simple too - look at a constructor of your class:

public AcceptThread() {
    BluetoothServerSocket tmp = null;
    try {
        tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
    }
    catch (IOException e) {
        Log.e(TAG, "listen() failed", e);
    }
    mmServerSocket = tmp;
}

You are calling method listenUsingRfcommWithServiceRecord which throws IOException, you catching this exception, as we can clearly see in logcat. Next, tmp variable stays initialized as NULL, same as mmServerSocket, which leads as to NPE mentioned above.

The reason why listenUsingRfcommWithServiceRecord is throwing IOException - because bluetooth is turned off, as you mention in your question. Android documentation says nothing about your assumption that this method should automatically turn on bluetooth if it's turned off. I think you should manually check if bluetooth is turned off and turn it on manually, before calling listenUsingRfcommWithServiceRecord.

You can find how to check is bluetooth turned on/off and turn it on here and here

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜