Search code examples
javaandroidconstructornullpointerexception

Arraylist being assigned correctly inside a constructor but is null when it is outside in a Android Studio Service


I cannot seem to figure out as to why whenever I try to assign an arraylist I recieved from the MainActivity to a public arraylist of a background service SensorService in the service's constructor. This is my constructor

    public SensorService(ArrayList<String> contactListNumber) {

    contactNumbers=contactListNumber;
    Log.d(TAG, "Inside Constructor");
    Log.d(TAG, "SensorService: Phone Numbers = "+contactListNumber);
    Log.d(TAG, "SensorService: Input Arraylist Size = "+contactListNumber.size());
    Log.d(TAG, "SensorService: Assigned Arraylist Size = "+contactNumbers.size());
    setPhoneNumberArray(contactListNumber);
}

I even tried invoking a method but it still gives me the same results where it assigns the contactNumbers correctly but when I try to invoke it inside onCreate I get an NullPointerException.

This is the MainActivity Intent where I create the service

    SensorService sensorService = new SensorService(Contact_Number);
    Intent intent = new Intent(this, sensorService.getClass());
    if(!isMyServiceRunning(sensorService.getClass())){
    startService(intent);
   //intent.putExtra("ContactNumberList", Contact_Number);
    Toast.makeText(this, "Starting Service", Toast.LENGTH_SHORT).show();
    }

And this is my complete SensorService.

public class SensorService extends Service {
    
        private SensorManager mSensorManager;
        private Sensor mAccelerometer;
        private ShakeDetector mShakeDetector;
        public ArrayList<String> contactNumbers;
    
        public SensorService() {
        }
        public SensorService(ArrayList<String> contactListNumber) {
    
            contactNumbers=contactListNumber;
            Log.d(TAG, "Inside Constructor");
            Log.d(TAG, "SensorService: Phone Numbers = "+contactListNumber);
            Log.d(TAG, "SensorService: Input Arraylist Size = "+contactListNumber.size());
            Log.d(TAG, "SensorService: Assigned Arraylist Size = "+contactNumbers.size());
            setPhoneNumberArray(contactListNumber);
        }
    
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            super.onStartCommand(intent, flags, startId);
            return START_STICKY;
        }
    
        @Override
        public void onCreate() {
    
    
            //contactNumbers=MainActivity.Contact_Numbers;
    
            super.onCreate();
    
            // start the foreground service
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                startMyOwnForeground();
            else
                startForeground(1, new Notification());
    
            // ShakeDetector initialization
            mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
            mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            mShakeDetector = new ShakeDetector();
            Log.d(TAG, "SensorService: Assigned Arraylist Size Outside Constructor = "+contactNumbers.size());
            mShakeDetector.setOnShakeListener(new ShakeDetector.OnShakeListener() {
    
                @SuppressLint("MissingPermission")
                @Override
                public void onShake(int count) {
                    // check if the user has shacked
                    // the phone for 3 time in a row
                    //if (count == 3)
                    if (count == 1) {
    
                        // vibrate the phone
                        vibrate();
                        Log.d(TAG, "onShake: Vibrate Activated");
    
                        // create FusedLocationProviderClient to get the user location
                        FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
                        Log.d("Check: ", "Sending Message");
                        // use the PRIORITY_BALANCED_POWER_ACCURACY
                        // so that the service doesn't use unnecessary power via GPS
                        // it will only use GPS at this very moment
                        fusedLocationClient.getCurrentLocation(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY, new CancellationToken() {
                            @Override
                            public boolean isCancellationRequested() {
                                return false;
                            }
    
                            @NonNull
                            @Override
                            public CancellationToken onCanceledRequested(@NonNull OnTokenCanceledListener onTokenCanceledListener) {
                                return null;
                            }
                        }).addOnSuccessListener(new OnSuccessListener<Location>() {
                            @Override
                            public void onSuccess(Location location) {
                                // check if location is null
                                // for both the cases we will
                                // create different messages
                                Log.d("Check: ", "MESSAGE SENT");
                                if (location != null) {
    
                                    // get the SMSManager
                                    SmsManager smsManager = SmsManager.getDefault();
    
                                    // get the list of all the contacts in Database
                                    DatabaseHelper db = new DatabaseHelper(SensorService.this);
                                    ArrayList<String> Contact_id, Contact_Name, Contact_Number;
                                    ArrayList<String> phonenumber = new ArrayList<String>();
                                    Log.d(TAG, "onSuccess: contactlistnumber size = "+contactNumbers.size());
                                    String[] phoneNumberList = new String[contactNumbers.size()];
                                    phoneNumberList = contactNumbers.toArray(phoneNumberList);
                                    Log.d(TAG, "onSuccess: Item 1 = "+phoneNumberList[0]);
                                    for(int i = 0; i < phoneNumberList.length ; i++){
                                        Log.d("Number is",(String)phoneNumberList[i]);
                                    }
    
                                    //phonenumber = (ArrayList<String>)getIntent().getSerializableExtra("ContactNumberList");
    
                                    // send SMS to each contact
                                    for (String c : phoneNumberList) {
                                        String message = "Hey, I am in DANGER, i need help. Please urgently reach me out. Here are my coordinates.\n " + "http://maps.google.com/?q=" + location.getLatitude() + "," + location.getLongitude();
                                        smsManager.sendTextMessage(c, null, message, null, null);
                                    }
                                } else {
                                    String message = "I am in DANGER, i need help. Please urgently reach me out.\n" + "GPS was turned off.Couldn't find location. Call your nearest Police Station.";
                                    SmsManager smsManager = SmsManager.getDefault();
                                    DatabaseHelper db = new DatabaseHelper(SensorService.this);
                                    List<ContactInfo> list = (List<ContactInfo>) db.getEveryone();
                                    String[] phoneNumberList = new String[contactNumbers.size()];
                                    phoneNumberList = contactNumbers.toArray(phoneNumberList);
                                    for (String c : phoneNumberList) {
                                        smsManager.sendTextMessage(c, null, message, null, null);
                                    }
                                }
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.d("Check: ", "OnFailure");
                                String message = "I am in DANGER, i need help. Please urgently reach me out.\n" + "GPS was turned off.Couldn't find location. Call your nearest Police Station.";
                                SmsManager smsManager = SmsManager.getDefault();
                                DatabaseHelper db = new DatabaseHelper(SensorService.this);
                                List<ContactInfo> list = (List<ContactInfo>) db.getEveryone();
                                String[] phoneNumberList = new String[contactNumbers.size()];
                                phoneNumberList = contactNumbers.toArray(phoneNumberList);
                                for (String c : phoneNumberList){
                                    smsManager.sendTextMessage(c, null, message, null, null);
                                }
                            }
                        });
    
                    }
                }
            });
    
            // register the listener
            mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
        }
    
        // method to vibrate the phone
        public void vibrate() {
    
            final Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
            VibrationEffect vibEff;
    
            // Android Q and above have some predefined vibrating patterns
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                vibEff = VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK);
                vibrator.cancel();
                vibrator.vibrate(vibEff);
            } else {
                vibrator.vibrate(500);
            }
    
    
        }
    
        // For Build versions higher than Android Oreo, we launch
        // a foreground service in a different way. This is due to the newly
        // implemented strict notification rules, which require us to identify
        // our own notification channel in order to view them correctly.
        @RequiresApi(Build.VERSION_CODES.O)
        private void startMyOwnForeground() {
            String NOTIFICATION_CHANNEL_ID = "example.permanence";
            String channelName = "Background Service";
            NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_MIN);
    
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            assert manager != null;
            manager.createNotificationChannel(chan);
    
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
            Notification notification = notificationBuilder.setOngoing(true)
                    .setContentTitle("You are protected.")
                    .setContentText("We are there for you")
    
    
                    // this is important, otherwise the notification will show the way
                    // you want i.e. it will show some default notification
                    .setSmallIcon(R.drawable.ic_launcher_foreground)
    
                    .setPriority(NotificationManager.IMPORTANCE_MIN)
                    .setCategory(Notification.CATEGORY_SERVICE)
                    .build();
            startForeground(2, notification);
        }
    
        @Override
        public void onDestroy() {
            // create an Intent to call the Broadcast receiver
            Intent broadcastIntent = new Intent();
            broadcastIntent.setAction("restartservice");
            broadcastIntent.setClass(this, ReactivateService.class);
            this.sendBroadcast(broadcastIntent);
            super.onDestroy();
        }
        public void setPhoneNumberArray(ArrayList numbers) {
            contactNumbers=numbers;
            //Log.d(TAG, "setPhoneNumberArray: contactnumbers size = "+contactNumbers.size());
        }
    }

would really appreciate if anyone could tell me why this is happening.


Solution

  • I found my mistake. For anyone else trying to do this. I made the very shortsighted mistake of not declaring the Arraylist contactNumbers as static. This is what it looked like before.

    public ArrayList<String> contactNumbers;

    In the end when I added the static keyword. such that it looks like

    static public ArrayList<String> contactNumbers;.

    Everything else seems to work corrrectly. Since I could now get the value of contactNumbers inside of the service.