无法停止服务-空对象引用错误-Android

时间:2018-08-16 00:37:41

标签: java android serial-port

当我在水平或垂直视图中启动我的应用程序时,一旦我旋转屏幕,该应用程序就会运行正常,并崩溃并出现以下错误。从未使用过串行端口或Android服务。

  

错误:java.lang.RuntimeException:无法停止服务com.xxx.testing.UsbService@1aba8fa1:java.lang.NullPointerException:尝试调用虚拟方法'void com.felhr.usbserial.UsbSerialDevice.close()'在空对象引用上
   在com.xxx.testing.UsbService.onDestroy(UsbService.java:92)

我们将不胜感激。 谢谢

错误

--------- beginning of crash
08-15 17:23:30.475 5966-5966/com.xxx /AndroidRuntime: FATAL EXCEPTION: main
    Process: com.xxx t, PID: 5966
    java.lang.RuntimeException: Unable to stop service com.xxx.testing.UsbService@1aba8fa1: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.felhr.usbserial.UsbSerialDevice.close()' on a null object reference
        at android.app.ActivityThread.handleStopService(ActivityThread.java:2911)
        at android.app.ActivityThread.access$2200(ActivityThread.java:144)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1381)
        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)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.felhr.usbserial.UsbSerialDevice.close()' on a null object reference
        at com.xxx.testing.UsbService.onDestroy(UsbService.java:92)
        at android.app.ActivityThread.handleStopService(ActivityThread.java:2894)

USB服务

@Override
public void onCreate() {
    this.context = this;
    serialPortConnected = false;
    UsbService.SERVICE_CONNECTED = true;
    setFilter();
    usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    findSerialPortDevice();
}

@Override
public IBinder onBind(Intent intent) {
    return binder;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    unregisterReceiver(usbReceiver);
    serialPort.close();
    UsbService.SERVICE_CONNECTED = false;
    super.onDestroy();
}

private class ConnectionThread extends Thread {
    @Override
    public void run() {
        serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
        if (serialPort != null) {
            if (serialPort.open()) {
                serialPort.setBaudRate(BAUD_RATE);
                serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
                serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
                serialPort.setParity(UsbSerialInterface.PARITY_NONE);
                serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
                serialPort.read(mCallback);
                isReadyToSend = true;
                // Everything went as expected. Send an intent to MainActivity
                Intent intent = new Intent(ACTION_USB_READY);
                context.sendBroadcast(intent);
            } else {
                // Serial port could not be opened, maybe an I/O error or if CDC driver was chosen, it does not really fit
                // Send an Intent to Main Activity
                if (serialPort instanceof CDCSerialDevice) {
                    Intent intent = new Intent(ACTION_CDC_DRIVER_NOT_WORKING);
                    context.sendBroadcast(intent);
                } else {
                    Intent intent = new Intent(ACTION_USB_DEVICE_NOT_WORKING);
                    context.sendBroadcast(intent);
                }
            }
        } else {
            // No driver for given device, even generic CDC driver could not be loaded
            Intent intent = new Intent(ACTION_USB_NOT_SUPPORTED);
            context.sendBroadcast(intent);
        }
    }
}

public void setHandler(Handler mHandler) {
    this.mHandler = mHandler;
}

private void setFilter() {
    IntentFilter filter = new IntentFilter();
    filter.addAction(ACTION_USB_PERMISSION);
    filter.addAction(ACTION_USB_DETACHED);
    filter.addAction(ACTION_USB_ATTACHED);
    registerReceiver(usbReceiver, filter);
}

private void requestUserPermission() {
    PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
    usbManager.requestPermission(device, mPendingIntent);
}

public class UsbBinder extends Binder {
    public UsbService getService() {
        return UsbService.this;
    }
}

private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context arg0, Intent arg1) {
        if (arg1.getAction().equals(ACTION_USB_PERMISSION)) {
            boolean granted = arg1.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
            if (granted) // User accepted our USB connection. Try to open the device as a serial port
            {
                Intent intent = new Intent(ACTION_USB_PERMISSION_GRANTED);
                arg0.sendBroadcast(intent);
                connection = usbManager.openDevice(device);
                serialPortConnected = true;
                new ConnectionThread().run();
            } else // User not accepted our USB connection. Send an Intent to the Main Activity
            {
                Intent intent = new Intent(ACTION_USB_PERMISSION_NOT_GRANTED);
                arg0.sendBroadcast(intent);
            }
        } else if (arg1.getAction().equals(ACTION_USB_ATTACHED)) {
            if (!serialPortConnected)
                findSerialPortDevice(); // A USB device has been attached. Try to open it as a Serial port
        } else if (arg1.getAction().equals(ACTION_USB_DETACHED)) {
            // Usb device was disconnected. send an intent to the Main Activity
            Intent intent = new Intent(ACTION_USB_DISCONNECTED);
            arg0.sendBroadcast(intent);
            serialPortConnected = false;
            serialPort.close();
        }
    }
};

private void findSerialPortDevice() {
    // This snippet will try to open the first encountered usb device connected, excluding usb root hubs
    HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
    if (!usbDevices.isEmpty()) {
        boolean keep = true;
        for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
            device = entry.getValue();
            int deviceVID = device.getVendorId();
            int devicePID = device.getProductId();
            String title = String.format("Vendor %s Product %s", device.getVendorId(), device.getProductId());
            Log.d("USB", "Found main Device: " + deviceVID + " " + devicePID);

            if (deviceVID != 0x1d6b && (devicePID != 0x0001 || devicePID != 0x0002 || devicePID != 0x0003)) {
                // There is a device connected to our Android device. Try to open it as a Serial Port.
                requestUserPermission();
                keep = false;
            } else {
                connection = null;
                device = null;
            }

            if (!keep)
                break;
        }
        if (!keep) {
            // There is no USB devices connected (but usb host were listed). Send an intent to MainActivity.
            Intent intent = new Intent(ACTION_NO_USB);
            sendBroadcast(intent);
        }
    } else {
        // There is no USB devices connected. Send an intent to MainActivity
        Intent intent = new Intent(ACTION_NO_USB);
        sendBroadcast(intent);
    }
}

活动

public class splash_screen extends AppCompatActivity {

TextView text100, text200, text300, display;
Layout timer1;
// int time= 3600000*8;
public String data;
private UsbService usbService;
private EditText editText;
private MyHandler mHandler;
public StringBuilder stringBuilder = new StringBuilder();
//long time = 3600000 * 10;
long  time = 20000;
private long result;
private long result2;
static final String STATE_USER = "user";
private String mUser;
@Override
protected void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash_screen);
    FullScreencall();

    mHandler = new MyHandler(splash_screen.this);


    int mUIFlag = View.SYSTEM_UI_FLAG_LOW_PROFILE
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    getWindow().getDecorView().setSystemUiVisibility(mUIFlag);

    text100 = (TextView) findViewById(R.id.tv_hour);
    text200 = (TextView) findViewById(R.id.tv_minute);
    text300 = (TextView) findViewById(R.id.tv_second);

    View someView1 = findViewById(R.id.timer1);
    View someView2 = findViewById(R.id.timer2);
    View someView3 = findViewById(R.id.timer3);

    someView1.setBackgroundColor(Color.parseColor("#000000"));
    someView2.setBackgroundColor(Color.parseColor("#000000"));
    someView3.setBackgroundColor(Color.parseColor("#000000"));

    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mUser = savedInstanceState.getString(STATE_USER);
    } else {
        // Probably initialize members with default values for a new instance
        mUser = "NewUser";
    }

}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putString(STATE_USER, mUser);
    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

public void FullScreencall() {
    if(Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api


        int mUIFlag = View.SYSTEM_UI_FLAG_LOW_PROFILE
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN;


        getWindow().getDecorView().setSystemUiVisibility(mUIFlag);

    } else if(Build.VERSION.SDK_INT >= 19) {
        //for new api versions.
        View decorView = getWindow().getDecorView();
        // Hide both the navigation bar and the status bar.
        // SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
        // a general rule, you should design your app to hide the status bar whenever you
        // hide the navigation bar.
        int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;

        decorView.setSystemUiVisibility(uiOptions);


    }
}

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        switch (intent.getAction()) {
            case UsbService.ACTION_USB_PERMISSION_GRANTED: // USB PERMISSION GRANTED
                //Toast.makeText(context, "USB Ready", Toast.LENGTH_SHORT).show();
                break;
            case UsbService.ACTION_USB_PERMISSION_NOT_GRANTED: // USB PERMISSION NOT GRANTED
                Toast.makeText(context, "USB Permission not granted", Toast.LENGTH_SHORT).show();
                break;
            case UsbService.ACTION_NO_USB: // NO USB CONNECTED
                // Toast.makeText(context, "No USB connected", Toast.LENGTH_SHORT).show();
                break;
            case UsbService.ACTION_USB_DISCONNECTED: // USB DISCONNECTED
                Toast.makeText(context, "USB disconnected", Toast.LENGTH_SHORT).show();
                break;
            case UsbService.ACTION_USB_NOT_SUPPORTED: // USB NOT SUPPORTED
                Toast.makeText(context, "USB device not supported", Toast.LENGTH_SHORT).show();
                break;
        }


    }
};

private void startService(Class<?> service, ServiceConnection serviceConnection, Bundle extras) {

    Intent serviceIntent = new Intent(this, UsbService.class);
    this.startService(serviceIntent);
    startService(serviceIntent);

    if (!UsbService.SERVICE_CONNECTED) {
        Intent startService = new Intent(this, UsbService.class);
        if (extras != null && !extras.isEmpty()) {
            Set<String> keys = extras.keySet();
            for (String key : keys) {
                String extra = extras.getString(key);
                startService.putExtra(key, extra);
            }
        }
        startService(startService);
    }
    Intent bindingIntent = new Intent(this, service);
    bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}

private final ServiceConnection usbConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName arg0, IBinder arg1) {
        usbService = ((UsbService.UsbBinder) arg1).getService();
        usbService.setHandler(mHandler);
        usbService.sendATGetACC();


    }

    @Override
    public void onServiceDisconnected(ComponentName arg0) {
        usbService = null;
    }
};

@Override
public void onResume() {
    super.onResume();
    setFilters();  // Start listening notifications from UsbService
    startService(UsbService.class, usbConnection, null); // Start UsbService(if it was not started before) and Bind it
}

@Override
public void onPause() {
    try {
        unregisterReceiver(mUsbReceiver);
        unbindService(usbConnection);
    } catch (IllegalArgumentException ex) {
    }
    super.onPause();

}

@Override
public void onDestroy() {
    try {
        if (mUsbReceiver != null)
            unregisterReceiver(mUsbReceiver);
    } catch (Exception e) {
    }
    stopService(new Intent(splash_screen.this, UsbService.class));
    super.onDestroy();
}


private void setFilters() {
    IntentFilter filter = new IntentFilter();
    filter.addAction(UsbService.ACTION_USB_PERMISSION_GRANTED);
    filter.addAction(UsbService.ACTION_NO_USB);
    filter.addAction(UsbService.ACTION_USB_DISCONNECTED);
    filter.addAction(UsbService.ACTION_USB_NOT_SUPPORTED);
    filter.addAction(UsbService.ACTION_USB_PERMISSION_NOT_GRANTED);
    registerReceiver(mUsbReceiver, filter);
}

public class MyHandler extends Handler {

    private final WeakReference<splash_screen> mActivity;

    public MyHandler(splash_screen activity) {
        mActivity = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case UsbService.MESSAGE_FROM_SERIAL_PORT:
                String data = (String) msg.obj;
                if (data != null && !data.isEmpty()) {
                    Log.d("REPLY", "data value" + data);
                    mActivity.get().time(data);
                    break;
                } else {
                    Log.d("REPLY", "novalue");
                }
        }
    }
}

public void time(String data) {
    long sec = Integer.parseInt(data);
    Log.d("REPLY", "Recieved data" + sec);

    result = TimeUnit.SECONDS.toMillis(sec);
    Log.d("REPLY", "Result value" + result);

    result2 = time - result;
    Log.d("REPLY", "Result2 value" + result2);
    Log.d("REPLY", "Time value" + time);


    if (result >= time) {

        //usbService.sendATGetSTOP();
        Intent mainIntent = new Intent(splash_screen.this,
                MainActivity.class);
        mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        splash_screen.this.startActivity(mainIntent);
        splash_screen.this.finish();
    } else {
        if (result >= time) {

            // usbService.sendATGetSTOP();
            Intent mainIntent = new Intent(splash_screen.this,
                    MainActivity.class);
            mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

            splash_screen.this.startActivity(mainIntent);
            splash_screen.this.finish();

        } else {
            // Log.d("REPLY", "result2 value " + result2);
            splashScreenUseAsyncTask();

        }
    }
}


private void splashScreenUseAsyncTask() {
    // Create a AsyncTask object.
    final RetrieveDateTask retrieveDateTask = new RetrieveDateTask();
    retrieveDateTask.execute("", "", "");
    // Get splash image view object.
    final ImageView splashImageView = (ImageView) findViewById(R.id.logo_id);

    //for 5 Hours
    CountDownTimer countDownTimer = new CountDownTimer(result2, 1000) {
        @SuppressLint("DefaultLocale")
        @Override
        public void onTick(long l) {

            long Hours = l / (60 * 60 * 1000) % 24;
            long Minutes = l / (60 * 1000) % 60;
            long Seconds = l / 1000 % 60;

            // tv_days.setText(String.format("%02d", Days));
            text100.setText(String.format("%02d", Hours));
            text200.setText(String.format("%02d", Minutes));
            text300.setText(String.format("%02d", Seconds));

            AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
            anim.setDuration(500);
            anim.setRepeatCount(anim.INFINITE);
            anim.setRepeatMode(Animation.REVERSE);
            splashImageView.startAnimation(anim);


        }

        @Override
        public void onFinish() {

            if (!retrieveDateTask.isAsyncTaskComplete()) {
                this.start();
            }
        }
    };
    // Start the count down timer.
    countDownTimer.start();

}

// This is the async task class that get data from network.
@SuppressLint("StaticFieldLeak")
private class RetrieveDateTask extends AsyncTask<String, String, String> {

    // Indicate whether AsyncTask complete or not.
    private boolean asyncTaskComplete = false;

    public boolean isAsyncTaskComplete() {
        return asyncTaskComplete;
    }

    public void setAsyncTaskComplete(boolean asyncTaskComplete) {
        this.asyncTaskComplete = asyncTaskComplete;
    }

    // This method will be called before AsyncTask run.
    @Override
    protected void onPreExecute() {
        this.asyncTaskComplete = false;
    }

    // This method will be called when AsyncTask run.
    @Override
    protected String doInBackground(String... strings) {
        try {
            // Simulate a network operation which will last for 10 seconds.
            Thread currTread = Thread.currentThread();
            currTread.sleep(result2);

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            return null;
        }
    }

    // This method will be called after AsyncTask run.
    @Override
    protected void onPostExecute(String s) {
        //usbService.sendATGetSTOP();
        this.asyncTaskComplete = true;
        //usbService.sendATGetACC();
        // Start SplashScreenMainActivity.
        Intent mainIntent = new Intent(splash_screen.this,
                MainActivity.class);
        mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

        splash_screen.this.startActivity(mainIntent);
        splash_screen.this.finish();

    }
}

}

2 个答案:

答案 0 :(得分:0)

旋转屏幕时,它将重新创建活动。我建议检查onDestroy()以查看USB是否为空。然后,在create()中更改方向后进行调试,以查看是否也重新创建了USB。我们可以利用onSaveInstance()在更改方向之前保存一些数据。

https://developer.android.com/guide/topics/resources/runtime-changes

答案 1 :(得分:0)

在onDestroy()中使用它:

if (serialPort != null){
        serialPort.close();
    }

代替:

serialPort.close();