Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - How to check if your contacts has registered on your app?

I am trying to create a ChatApp. So, I want to find out if in my contact list anyone has registered in my app or not.

enter image description here

As in the above image, there are 3 keys. El7SIqgHmWTsZCl6gVaXidKGsok1 This is me and others 2 are my friends and I have their phoneNumber also. So, I wanna display these 2 as my friends in my app. But It doesn't show any users.

Here is the Code that I Have tried.

public class UsersFragment extends Fragment {

    RecyclerView recyclerView;
    ContactsAdapter adapter;
    List<Users> contactsList, userList;
    DatabaseReference reference;
    String userId;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_users, container, false);

        recyclerView = view.findViewById(R.id.userRecyclerView);
        recyclerView.setHasFixedSize(false);
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        reference = FirebaseDatabase.getInstance().getReference().child("Users");
        contactsList = new ArrayList<>();
        userList = new ArrayList<>();

        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        userId = user.getUid();

        return view;
    }

    private void getContactList() {
        Cursor cursor = getActivity().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                null, null, null,
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
        ;
        while (cursor.moveToNext()) {
            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            String phone = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));

            Users contacts = new Users(name, phone, "", "");
            contactsList.add(contacts);
            if (contactsList.contains(contacts)) {
                cursor.moveToNext();
            }
            getActualUsers(contacts);
        }

    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        getContactList();
    }

    private void getActualUsers(final Users contacts) {
        Query query = reference.orderByChild("number").equalTo(contacts.getPhoneNumber());
        query.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                    Users users = dataSnapshot.getValue(Users.class);
                    userList.add(users);
                }
                Log.d("contact", String.valueOf(userList.size()));
                adapter = new ContactsAdapter(getContext(), userList);
                recyclerView.setAdapter(adapter);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });
    }

}

My Model Class

public class Users {

String username, phoneNumber, userId, profilephotoURL;

public  Users(){}
public Users(String username, String phoneNumber, String userId, String profilephotoURL) {
    this.username = username;
    this.phoneNumber = phoneNumber;
    this.userId = userId;
    this.profilephotoURL = profilephotoURL;
}

public String getUsername() {
    return username;
}

public String getPhoneNumber() {
    return phoneNumber;
}

public String getUserId() {
    return userId;
}

public String getProfilephotoURL() {
    return profilephotoURL;
}

}

My Adapter Class

public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.ViewHolder> {
    Context mContext;
    List<Users> mList;

    public UsersAdapter(Context mContext, List<Users> mList) {
        this.mContext = mContext;
        this.mList = mList;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.display_contacts, null);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        final Users users = mList.get(position);
        holder.name.setText(users.getUsername());
        holder.number.setText(users.getPhoneNumber());
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(mContext, ChatActivity.class);
                intent.putExtra("name", users.getUsername());
                intent.putExtra("userid", users.getPhoneNumber());
                intent.putExtra("id", users.getUserId());
                mContext.startActivity(intent);
            }
        });
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView name, number;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.contactName);
            number = itemView.findViewById(R.id.contactNumber);
        }
    }
}

Any Help or Suggestions?

like image 601
HARSH ASHRA Avatar asked Jul 20 '20 09:07

HARSH ASHRA


2 Answers

Not sure if this is the solution to your problem, but it might be and it is too long for a comment to explain:

Let me write your code in a commpressed way with some comments:

// start a loop over every local contacts on the phone
while (cursor.moveToNext()) {

  // create a local variable for this contact (the class name should be Contact. Singular.)
  Contacts contacts = new Contacts(name, phone, "");
  
  // get a contact with the same phone number from firebase.
  // the sorting is executed for every iteration of the loop -> bad performance. 
  // -> I recommend to order the reference outside of the loop.
  Query query = reference.orderByChild("number").equalTo(contacts.getNumber());

  // now you add the ValueEventListener

  // if onDataChanged is called, you iterate over all children of the new snapshot

  // you create again a local Contacts object

  // then there is this strange comparison of name and phone...don't know what that accomplishes, but ok

  // now comes the part that might cause the wrong behaviour:
  userList.add(contacts1);
  adapter = new ContactsAdapter(getContext(), userList);
  recyclerView.setAdapter(adapter);

}

So the last 3 lines seem error-prone:

  userList.add(contacts1);
  adapter = new ContactsAdapter(getContext(), userList);
  recyclerView.setAdapter(adapter);

In general there is not much wrong with them, but keep in mind that you are basically still in the very first loop that you started in getContactList() That means that you create a completely new adapter for every contact in the loop and assign this new adapter to the recyclerView.

Let's say you have 100 contacts on your phone. This leads to 100 adapters being created and set to the recyclerView.

I would suggest 2 major changes in your code:

  1. override onViewCreated and put the getContactList(); in there. The method onCreateView should only be concerned with basic view inflation and maye initializing simple View variables. Filling the View with data should be done afterwards in onViewCreated.

  2. Make a clear separation between "preparing the data for the View" and "putting the prepared data into the View". In other words: First create your final userList and only if this list is done, create the adapter and set it to the recyclerView.

If you want to improve even further, have a look at the idea of ViewModels. In short: The ViewModel is preparing all the data that its View wants to display (including filtering, transforming, etc.). The View (in this case your Fragment) is as "stupid" as possible -> It waits until the ViewModel passes data into it and does nothing more than to display that data.

LiveData is very useful for this approach and it will make your code much much cleaner and easier to understand and to maintain :)

Good luck with your project!

like image 122
muetzenflo Avatar answered Oct 22 '22 00:10

muetzenflo


I'll not give you any code but an architectural hint on how to achieve your goal. From details provided in your question, I assume your clients are registering through OTP. When they sign in you can store their UID against their phone numbers. Take a look on how to save user details.

Here is how your firebase stored registered users should look like

registeredUsers : {
    "23492hsdfs08fv9x9" : "0X20-342234...",
    "34928304283438d8f" : "0X02-123123..."
}

Now when you access current user contact list, loop through the usrs list in firebase to see which phone numbers from contact list are also in firebase.

You could use just list of phone numbers without adding Firebase UIDs but I recommend you do it like above in case you need to map a contact number to it's UID and then you can fetch that user's details from UID as well.

Hope I've given you a hint on how to get along.

like image 29
Mirwise Khan Avatar answered Oct 22 '22 00:10

Mirwise Khan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!