0

I will try to explain this as best I can. (I'm still new with both Java and Android)

Issue:

I am trying to compare an incoming number string to a Contact object's number string by searching the arrayList.

Background:

I am able to load Contacts from an arrayList into different views (ListView, textView, etc) so I know the methods and objects are working. It's this new class (RingerService) that I'm having the issue with.

Design

I have an arrayList of contacts in a class named contactStorage. It works as intended for displaying different views:

//constructor with context to access project resources and instantiate from JSONfile to arrayList 
private ContactStorage(Context appContext){
    mAppContext = appContext;
    mSerializer = new ContactJSONer(mAppContext, FILENAME);
    
    try{
        mContacts = mSerializer.loadContacts();
    }catch (Exception e){
        mContacts = new ArrayList<Contact>();
        Log.e(TAG, "No contacts available, creating new list: ", e);
    }
}

//get method to only return one instance from the constructor
public static ContactStorage get(Context c){
    if (sContactStorage == null){
        sContactStorage = new ContactStorage(c.getApplicationContext());
    }
    return sContactStorage;
}

//for ringer service to find matching number
public Contact getContactNumber(String number){
    for (Contact c: mContacts){
        if(c.getNumber().replaceAll("[^0-9]", "").equals(number))
            return c;
    }
    return null;
}

when I call the get method above in the RingerService class below, that's when things break. To be specific, I am getting a NullPointerException on onCallStateChanged:

 private Contact mContact;
private String number;
private Context mContext;

    @Override
   public void onCreate(){
       mTelephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
       mPhoneStateListener = new PhoneStateListener(){
           // state change 
           @Override
           public void onCallStateChanged(int state, String incomingNumber){
               if (state == 1 ){ 
                   try{
                        mContact = ContactStorage.get(mContext).getContactNumber(incomingNumber);
                        number = mContact.getNumber();
                        Log.d(TAG, state+" received an incoming number: " + number);
                    }catch(Exception e){
                        Log.d(TAG, " exception: " + e);
                    }
               } else {
                   Log.d(TAG, state+" number not found" + incomingNumber);
               }
           }   
       };
       super.onCreate();
   }

Troubeshooting:

1. I've removed the reference to number (number = mContact.getNumber();) - the program runs fine in that case. I can send a test call to the emulator and the log message displays correctly with the test number arg. I considered it could be the way in which the array searching works in getContactNumber class. Is it never finding a matching value, resulting in null?

2. I also thought that since this is a service, I'm somehow not getting the right context when calling the ContactStorage.get(Context c) method.

3. if I set my mContact reference and no number match was found, would mContact = null; still let the program run?

Community
  • 1
  • 1
Futureproof
  • 375
  • 4
  • 21
  • Since `getContactNumber` can potentially return `null` and then you turn right around and call `mContact.getNumber()` where `mContact` is the return of `getContactNumber` ... thats a NullPointerException waiting to happen. – Origineil Jun 20 '14 at 03:55
  • 1
    Did you initialize your context (`mContext`) anywhere?. I feel like your context is null. Debug and check. – Aniruddha Jun 20 '14 at 04:42
  • 1
    possible duplicate of [What is a Null Pointer Exception, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-null-pointer-exception-and-how-do-i-fix-it) – Oleg Estekhin Jun 20 '14 at 07:05
  • The reason I used getApplicationContext() in **ContactStorage** was that I expected to use the model data in multiple areas, application wide (Activities, fragments, services). Since service is a context, could I simply set `Context mContext = RingerService(this)` to directly access it? – Futureproof Jun 20 '14 at 16:51

2 Answers2

4

You are trying to match strings with == in c.getNumber() == number which will check if two objects reference are equals

Use c.getNumber().equals(number)

Pallavi
  • 96
  • 3
  • Is the `number` you are trying to match is in the list `mContacts`? If not then you will have to handle `mContact` being `null` case in the code – Pallavi Jun 20 '14 at 04:03
  • @Aniruddha `for (Contact c: mContacts){ if (c.getNumber() == number) return c; } return null;` returns `null` everytime as its doing reference equally – Pallavi Jun 20 '14 at 05:59
  • @Pallavi didn't see that `return null` before. Sorry – Aniruddha Jun 20 '14 at 06:00
  • I tried using a number that I knew was already on one of the contact objects, but in a real world scenario something like a try, catch exception block would be better. – Futureproof Jun 20 '14 at 19:06
0

Thanks for the suggestions. It turns out that when testing an incoming phone call in Eclipse to an emulator device, the GUI field only takes numerics without spaces or hyphens: (1112221122)

Since my contact objects' number field is getting assigned through android's CONTACT_URI, the format is saved as a string (###) ###-####. This will never match, causing the nullPointerException error. I updated the getContactNumber method to replace this formatting for the long string of numbers for any potential match.

I then added a catch for any RuntimeException on the RingerService method. All is working now.

Out of curiosity, does anyone know the format for real incoming phone numbers?

Futureproof
  • 375
  • 4
  • 21