0

I am trying to modify an app to add additional features. I have a function that looks like this

public class MainActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
    private static final int REQUEST_SELECT_DEVICE = 1;
    private static final int REQUEST_ENABLE_BT = 2;
    public static final String TAG = "nRFUART";
    private static final String TAG1 = "smsTAG";
    private static final int UART_PROFILE_CONNECTED = 20;
    private static final int UART_PROFILE_DISCONNECTED = 21;
    public static String content = null;
    private int mState = UART_PROFILE_DISCONNECTED;
    private UartService mService = null;
    private BluetoothDevice mDevice = null;
    private BluetoothAdapter mBtAdapter = null;
    private ListView messageListView;
    private ArrayAdapter<String> listAdapter;
    public Button btnConnectDisconnect,btnSend;
    private EditText edtMessage;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBtAdapter == null) {
            Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
        }else{

            btnConnectDisconnect=(Button) findViewById(R.id.btn_select);
            btnSend=(Button) findViewById(R.id.sendButton);
            edtMessage = (EditText) findViewById(R.id.sendText);
            mBtAdapter = BluetoothAdapter.getDefaultAdapter();
            messageListView = (ListView) findViewById(R.id.listMessage);
            listAdapter = new ArrayAdapter<String>(this, R.layout.message_detail);
            messageListView.setAdapter(listAdapter);
            messageListView.setDivider(null);
            //Call receiveBroadCast like this
            receiveBroadCast(getIntent().getStringExtra("message"));
            service_init();
        }

    ...

        // Handle Send button
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EditText editText = (EditText) findViewById(R.id.sendText);
//              String message = editText.getText().toString();
                String message = content;
                byte[] value;
                try {
                    //send data to service
                    value = message.getBytes("UTF-8");
                    mService.writeRXCharacteristic(value);
                    //Update the log with time stamp
                    String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
                    listAdapter.add("["+currentDateTimeString+"] TX: "+ message);
                    messageListView.smoothScrollToPosition(listAdapter.getCount() - 1);
                    edtMessage.setText("");
                    Log.i(TAG1, "success, value: " + value + " message: " + message);
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.i(TAG1, "fail" + e.toString());
                }
            }
        });

        ...

    }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public void receiveBroadCast(String text) {
        btnSend=(Button) findViewById(R.id.sendButton);
        Log.i(TAG1, "test " + text);
        try {
            Log.i(TAG1, "success " + text);
            content = text;
            btnSend.performClick();
        } catch (Exception e) {
            Log.i(TAG1, "fail " + e.toString());
        }
    }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

But when I run the code I am getting the error

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference

Here is the main.xml file that contains my button

        <Button
            android:id="@+id/sendButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentBottom="true"
            android:layout_marginRight="0dp"
            android:layout_marginBottom="0dp"
            android:enabled="false"
            android:text="Send" />

Any idea what is causing this error?

I am trying to make my receiveBroadcast automatically click on the sendButton everytime I supply a string to my receiveBroadcast.

This is my SMSReceiver class that I am using to call receiveBroadcast:

public class SmsReceiver extends BroadcastReceiver {
    private static final String TAG = "MyBroadcastReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
            Bundle bundle = intent.getExtras();
            SmsMessage[] msgs = null;
            if (bundle != null){
                try{
                    Object[] pdus = (Object[]) bundle.get("pdus");
                    msgs = new SmsMessage[pdus.length];
                    for(int i=0; i<msgs.length; i++){
                        msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
                        String msgBody = msgs[i].getMessageBody();
                        Log.i(TAG, " success " + msgBody);
                        MainActivity Text = new MainActivity();
                        Text.receiveBroadCast(msgBody);
                        Intent intentsms = new Intent(context, MainActivity.class);
                        intentsms.putExtra("message", msgBody);
                        context.startActivity(intentsms);
                    }
                } catch(Exception e) {
                    Log.i(TAG, e.toString());
                }
            }
        }
    }
}
Vic Tim
  • 13
  • 3
  • 1
    What you are trying to do? – Suraj Nov 17 '18 at 10:03
  • Just from that Exception message, I would guess that you're directly instantiating an `Activity` class yourself; e.g., something like `MainActivity activity = new MainActivity();`. If so, you cannot do that, but we can't really provide any specific suggestions without more information. – Mike M. Nov 17 '18 at 10:03
  • Where are you calling `receiveBroadCast()`? – Mike M. Nov 17 '18 at 10:13
  • in a receiver class that I have created – Vic Tim Nov 17 '18 at 10:17
  • And are you directly instantiating `MainActivity` in that Receiver, like I showed above? – Mike M. Nov 17 '18 at 10:18
  • yes i have initialised it as "MainActivity Text" – Vic Tim Nov 17 '18 at 10:21
  • Yeah, you can't do that. An `Activity` must be instantiated by the system. You need some other mechanism to send data from the Receiver to the `Activity`. There are several options. You could send it on an `Intent` with `startActivity()`, like is shown in [this post](https://stackoverflow.com/a/6857648). Or you could use `LocalBroadcastManager`, like is shown in [this post](https://stackoverflow.com/a/26612814). Similar to that is using an event bus, which is mentioned in that answer, and demonstrated in [this other one](https://stackoverflow.com/a/38954540). – Mike M. Nov 17 '18 at 10:38
  • Of course, there are other ways, too, but the main point is that you need to somehow pass that data to a valid `Activity` instance, not one you create yourself. – Mike M. Nov 17 '18 at 10:38
  • So I past the data from my SmsReceiver to my onCreate using activities? Then receive the data in the activity in onCreate? – Vic Tim Nov 17 '18 at 10:42
  • That's one possibility. To be honest, I prefer `LocalBroadcastManager` for this. It's in the support library, so it's an "official" component. It uses the native `Intent` and `BroadcastReceiver` classes that are already in the framework, so it's a very lightweight addition to your app. Additionally, its `sendBroadcast()` method returns a `boolean` to indicate if any Receiver's handle the broadcast, so you can do something else – e.g., showing a `Notification` instead – if your `MainActivity` doesn't happen to be running when a message comes in. I'll see if I can find a better example of that. – Mike M. Nov 17 '18 at 10:55
  • @VicTim kindly check the updated answer to get an idea – Muhammad waris Nov 17 '18 at 10:58
  • Here, this one is a little better: https://stackoverflow.com/a/8875292. In that example, `ReceiverActivity` is your `MainActivity`, and `SenderActivity` is your SMS Receiver. The code in the `sendMessage()` method there is what you would use from the SMS Receiver's `onReceive()` to send `msgBody`. In `ReceiverActivity`, the `mMessageReceiver` will get that broadcast with `msgBody` (if it's active), and from its `onReceive()`, you can call your `receiveBroadCast()` method with the message retrieved from the `Intent`. Follow all of that? – Mike M. Nov 17 '18 at 11:19
  • Correct me if im wrong, but base on my current code here, I believe the error lies in the public void receiveBroadCast(String text) { btnSend=(Button) findViewById(R.id.sendButton); I am not sure why is it the findViewById is a null – Vic Tim Nov 17 '18 at 12:39
  • Try debugging your app and you will know in which line exactly is your app crashing. – Ankush Rawat Nov 17 '18 at 13:37

1 Answers1

0

For that thing to work for you. You will have to send the LocalBroadCastManager to MainActivity and there you will have to get that data to perform your Action.

Check the implementation below:

public class MainActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
    private static final int REQUEST_SELECT_DEVICE = 1;
    private static final int REQUEST_ENABLE_BT = 2;
    public static final String TAG = "nRFUART";
    private static final String TAG1 = "smsTAG";
    private static final int UART_PROFILE_CONNECTED = 20;
    private static final int UART_PROFILE_DISCONNECTED = 21;
    public static String content = null;
    private int mState = UART_PROFILE_DISCONNECTED;
    private UartService mService = null;
    private BluetoothDevice mDevice = null;
    private BluetoothAdapter mBtAdapter = null;
    private ListView messageListView;
    private ArrayAdapter<String> listAdapter;
    public Button btnConnectDisconnect,btnSend;
    private EditText edtMessage;


    private BroadcastReceiver myMessageRec = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // Get extra data included in the Intent
            String message = intent.getStringExtra("message");
            Log.d("receiver", "Got message: " + message);
            receiveBroadCast(message);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        LocalBroadcastManager.getInstance(MainActivity.this).registerReceiver(myMessageRec,
                new IntentFilter("myMessage"));
        btnConnectDisconnect = (Button) findViewById(R.id.btn_select);
        btnSend = (Button) findViewById(R.id.sendButton);
        edtMessage = (EditText) findViewById(R.id.sendText);
        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
        messageListView = (ListView) findViewById(R.id.listMessage);
        listAdapter = new ArrayAdapter<String>(this, R.layout.message_detail);
        messageListView.setAdapter(listAdapter);
        messageListView.setDivider(null);
        service_init();

        // Handle Send button
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EditText editText = (EditText) findViewById(R.id.sendText);
//              String message = editText.getText().toString();
                String message = content;
                byte[] value;
                try {
                    //send data to service
                    value = message.getBytes("UTF-8");
                    mService.writeRXCharacteristic(value);
                    //Update the log with time stamp
                    String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
                    listAdapter.add("[" + currentDateTimeString + "] TX: " + message);
                    messageListView.smoothScrollToPosition(listAdapter.getCount() - 1);
                    edtMessage.setText("");
                    Log.i(TAG1, "success, value: " + value + " message: " + message);
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Log.i(TAG1, "fail" + e.toString());
                }
            }
        });

    }

    public void receiveBroadCast(String text) {
        Log.i(TAG1, "test " + text);
        try {
            Log.i(TAG1, "success " + text);
            content = text;
            btnSend.performClick();
        } catch (Exception e) {
            Log.i(TAG1, "fail " + e.toString());
        }
    }

    @Override
    protected void onDestroy() {
        // Unregister since the activity is about to be closed.
        LocalBroadcastManager.getInstance(MainActivity.this).unregisterReceiver(myMessageRec);
        super.onDestroy();
    }


}

SmsReceiver will look like this:

public class SmsReceiver extends BroadcastReceiver {
        private static final String TAG = "MyBroadcastReceiver";
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
                Bundle bundle = intent.getExtras();
                SmsMessage[] msgs = null;
                String str = "";
                if (bundle != null) {
                    Object[] pdus = (Object[]) bundle.get("pdus");
                    msgs = new SmsMessage[pdus.length];
                    for (int i=0; i<msgs.length; i++){
                        msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
                        str += "SMS from " + msgs[i].getOriginatingAddress();
                        str += " :";
                        str += msgs[i].getMessageBody().toString();
                        str += "\n";
                    }
                }
                Intent intentsms = new Intent("myMessage");
                intentsms.putExtra("message", str);
                LocalBroadcastManager.getInstance(context).sendBroadcast(intentsms);
            }
        }
    }
Muhammad waris
  • 314
  • 1
  • 10
  • Whenever I receive an SMS, the app restarts – Vic Tim Nov 17 '18 at 11:14
  • That is because of this check `if (mBtAdapter == null)` so to fix that remove `finish;` and `return;` form the code as in updated answer. And check why `mBtAdapter ` is null – Muhammad waris Nov 17 '18 at 11:26
  • I have updated my code to match what you have, but nothing is working, please advice if I made any mistakes along the way, thank you – Vic Tim Nov 17 '18 at 11:38
  • Are you getting the `Toast` message "Bluetooth is not available" ? – Muhammad waris Nov 17 '18 at 11:48
  • nope, infact i am receiving the success logs from receive broadcast, but nothing is happening – Vic Tim Nov 17 '18 at 11:52
  • that means `receiveBroadCast` is successully being called without NullPointerException so now what you want next ? – Muhammad waris Nov 17 '18 at 12:00
  • Just tested, I'm still getting the same error java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference – Vic Tim Nov 17 '18 at 12:28
  • change your `SmsReceiver` class as updated in answer and then let me know – Muhammad waris Nov 17 '18 at 12:45
  • Correct me if im wrong, but base on my current code here, I believe the error lies in the public void receiveBroadCast(String text) { btnSend=(Button) findViewById(R.id.sendButton); I am not sure why is it the findViewById is a null – Vic Tim Nov 17 '18 at 12:56
  • above in my code i have put this `btnSend=(Button) findViewById(R.id.sendButton);` line in `onCreate` so you need to remove this line from `receiveBroadCast` – Muhammad waris Nov 17 '18 at 12:58
  • @VicTim for now update onCreate() as updated in answer – Muhammad waris Nov 17 '18 at 13:02
  • I have deleted the btnSend=(Button) findViewById(R.id.sendButton) from my receiveBroadcast and followed your onCreate(), the app is reopening again on top of the current app – Vic Tim Nov 17 '18 at 13:06
  • why do you have a curly bracket after serviec_init(), it seems to be causing me some syntax error – Vic Tim Nov 17 '18 at 13:39
  • your code is closing my onCreate, putting btnSend.setOnClickListener(new View.OnClickListener() outside of the onCreate – Vic Tim Nov 17 '18 at 13:53
  • I can't put receiveBroadCast inside onCreate, cannot resolve symbol 'text' – Vic Tim Nov 17 '18 at 14:03
  • `receiveBroadCast` will be outside of `onCreate()` in MainActivity – Muhammad waris Nov 17 '18 at 14:10