1

I am trying to pull contacts from the phone of the user and then match these against the phone numbers I have in my parse backend and then display the matches in a custom list view. I have managed to do almost everything, however I am having trouble setting the global variable mBinderPhoneNumber correctly. For whatever reason according to logcat the variable is first showing as null and only later gets the correct value even though I am setting the variable correctly before I need to use it.

Here is the logcat which shows the variable is showing up as null at first and then only later getting set correctly:

12-31 15:17:12.242 27804-27935/com.rileymacdonaldapps.binder D/TAG: mBinderPhoneNumbers from AddContactsInList:null
12-31 15:17:12.902 27804-27804/com.rileymacdonaldapps.binder D/TAG: mBinderPhoneNumbers from onCreate: [CORRECT PARSE USER1, CORRECT PARSE USER2]

Can someone kindly help me out?

Here is the activity:

public class AddContactsActivity extends Activity {
    public List mBinderPhoneNumbers;
    Context context = null;
    ContactsAdapter objAdapter;
    ListView lv = null;
    EditText edtSearch = null;
    LinearLayout llContainer = null;
    Button btnOK = null;
    RelativeLayout rlPBContainer = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = this;
        setContentView(R.layout.activity_add_contacts);
        rlPBContainer = (RelativeLayout) findViewById(R.id.pbcontainer);
        edtSearch = (EditText) findViewById(R.id.input_search);
        llContainer = (LinearLayout) findViewById(R.id.data_container);
        btnOK = (Button) findViewById(R.id.ok_button);


        btnOK.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                getSelectedContacts();
            }
        });

        edtSearch.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence cs, int arg1, int arg2,
                                      int arg3) {
                // When user changed the Text
                String text = edtSearch.getText().toString()
                        .toLowerCase(Locale.getDefault());
                objAdapter.filter(text);
            }

            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1,
                                          int arg2, int arg3) {
                // TODO Auto-generated method stub

            }

            @Override
            public void afterTextChanged(Editable arg0) {
                // TODO Auto-generated method stub
            }
        });
        // Get parse users
        String [] phoneNumberList = {"DUMMY NUMBER1", "DUMMY NUMBER2", "DUMMY NUMBER3", "DUMMY NUMBER4"};
        ParseQuery<ParseUser> query = ParseUser.getQuery(); {
            query.whereContainedIn("username", Arrays.asList(phoneNumberList));
            query.findInBackground(new FindCallback<ParseUser>() {
                public void done (List<ParseUser> list, ParseException e){
                    if (e == null) {
                        mBinderPhoneNumbers = list;
                        Log.d("TAG", "mBinderPhoneNumbers from onCreate: " + mBinderPhoneNumbers);
                    } else {
                        // Something went wrong.
                        Log.e("TAG", "User query error: " + e);
                    }
                }
            });
        }
        addContactsInList();
    }

    private void getSelectedContacts() {
        // TODO Auto-generated method stub

        StringBuffer sb = new StringBuffer();

        for (ContactObject bean : ContactsListClass.phoneList) {

            if (bean.isSelected()) {
                sb.append(bean.getName());
                sb.append(",");
            }
        }

        String s = sb.toString().trim();

        if (TextUtils.isEmpty(s)) {
            Toast.makeText(context, "Select at least one Contact",
                    Toast.LENGTH_SHORT).show();
        } else {

            s = s.substring(0, s.length() - 1);
            Toast.makeText(context, "Selected Contacts: " + s,
                    Toast.LENGTH_SHORT).show();
        }

    }

    private void addContactsInList() {
        // TODO Auto-generated method stub


        Thread thread = new Thread() {
            @Override
            public void run() {

                showPB();

                try {

                    Cursor phones = getContentResolver().query(
                            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                            null, null, null, null);

                    try {
                        ContactsListClass.phoneList.clear();
                    } catch (Exception e) {

                    }


                    while (phones.moveToNext()) {


                        Log.d("TAG", "mBinderPhoneNumbers from AddContactsInList:" + mBinderPhoneNumbers);
                        if (Arrays.asList(mBinderPhoneNumbers).contains(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER)))) {
                            String phoneName = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                            String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER));
                            String phoneImage = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
                            ContactObject cp = new ContactObject();
                            cp.setName(phoneName);
                            cp.setNumber(phoneNumber);
                            cp.setImage(phoneImage);
                            ContactsListClass.phoneList.add(cp);
                        }
                    }
                    phones.close();
                    lv = new ListView(context);
                    lv.setLayoutParams(new LayoutParams(
                            LayoutParams.MATCH_PARENT,
                            LayoutParams.MATCH_PARENT));

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // TODO Auto-generated method stub
                            llContainer.addView(lv);
                        }
                    });

                    Collections.sort(ContactsListClass.phoneList,
                            new Comparator<ContactObject>() {
                                @Override
                                public int compare(ContactObject lhs,
                                                   ContactObject rhs) {
                                    return lhs.getName().compareTo(
                                            rhs.getName());
                                }
                            });

                    objAdapter = new ContactsAdapter(AddContactsActivity.this,
                            ContactsListClass.phoneList);
                    lv.setAdapter(objAdapter);
                    lv.setOnItemClickListener(new OnItemClickListener() {

                        @Override
                        public void onItemClick(AdapterView<?> parent,
                                                View view, int position, long id) {

                            CheckBox chk = (CheckBox) view
                                    .findViewById(R.id.contactcheck);
                            ContactObject bean = ContactsListClass.phoneList
                                    .get(position);
                            if (bean.isSelected()) {
                                bean.setSelected(false);
                                chk.setChecked(false);
                            } else {
                                bean.setSelected(true);
                                chk.setChecked(true);
                            }

                        }
                    });

                } catch (Exception e) {

                    e.printStackTrace();

                }

                hidePB();

            }
        };

        thread.start();

    }

    void showPB() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                rlPBContainer.setVisibility(View.VISIBLE);
                edtSearch.setVisibility(View.GONE);
                btnOK.setVisibility(View.GONE);
            }
        });
    }

    void hidePB() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                rlPBContainer.setVisibility(View.GONE);
                edtSearch.setVisibility(View.VISIBLE);
                btnOK.setVisibility(View.VISIBLE);
            }
        });
    }

}
Riley MacDonald
  • 453
  • 1
  • 4
  • 15

3 Answers3

0
     query.findInBackground(new FindCallback<ParseUser>() {
                    public void done (List<ParseUser> list, ParseException e){
                        if (e == null) {
                            mBinderPhoneNumbers = list;
                            addContactsInList();// call here
                            Log.d("TAG", "mBinderPhoneNumbers from onCreate: " + mBinderPhoneNumbers);
                        } else {
                            // Something went wrong.
                            Log.e("TAG", "User query error: " + e);
                        }
                    }
                });

Better to use like this. Since you are using findInBackground, there will be a delay. The list will be available only after done is called.

Roshan
  • 3,442
  • 2
  • 14
  • 23
0

Both query.findInBackground() and addContactsInList() perform work asynchronously. Once you call them, they fire up a background thread to do the work. Because you call these two methods in sequence, both threads are started at approximately the same time. You can make no guarantees about when either method will complete relative to the other.

It sounds like what you want is to only call addContactsInList() after query.findInBackground() has completed. Moving that call to findInBackground()'s done() callback should achieve the desired result.

Bryan Herbst
  • 66,602
  • 10
  • 133
  • 120
0

The problem is, query.findInBackground() is executing in it's own thread. Since it's not a blocking call, main thread will not wait for query.findInBackground()'s completion. So, addContactsInList() will start it's execution even before mBinderPhoneNumbers gets initialized.

Better solution is to call addContactsInList() inside done(). Like this,

query.findInBackground(new FindCallback<ParseUser>() {
    public void done (List<ParseUser> list, ParseException e){
        if (e == null) {
            mBinderPhoneNumbers = list;
            addContactsInList();
            .....
        }
    }
});
Msp
  • 2,493
  • 2
  • 20
  • 34