How can i hide similar data in a firebase database? - java

Firebase database contains data for different keys. I need to query and show this data with recyclerview. but since the same data are saved many times in the database, the same results appear many times in recyclerview. I want to prevent this. Even though the queried value is dozens of times in the database, I want it to be displayed only once in recyclerview. How can I do that. I will be happy if you help.
InfiniteFirebaseArray infiniteFirebaseArray = new InfiniteFirebaseArray();
infiniteFirebaseArray.getSearch(areaCode + phoneNumber);
mAdapter = new InfiniteFirebaseRecyclerAdapter<ContactList, NameViewHolder>(ContactList.class, R.layout.layout_search_contact_list_item,
NameViewHolder.class, mUserDatabase, mPageLimit) {
#Override
protected void populateViewHolder(NameViewHolder viewHolder, ContactList model, int position) {
Logger.enter();
if (model != null) {
String string = model.getDisplay_name();
String firstletter = string.substring(0, 1);
resultcount++;
viewHolder.name.setText(model.getDisplay_name());
viewHolder.phone.setText(model.getPhone_number());
viewHolder.userImageText.setText(firstletter);
ContactResult contactResult = new ContactResult();
contactResult.setName(model.getDisplay_name());
contactResult.setPhone(model.getPhone_number());
contactLists.add(contactResult);
Log.d("testcontacts",String.valueOf(contactLists.get(position).getName()));
viewHolder.callPhone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String phoneNumber = contactLists.get(position).getPhone();
callPhone(phoneNumber);
}
});
viewHolder.addContact.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String contactName = contactLists.get(position).getName();
String contactPhoneNumber = contactLists.get(position).getPhone();
addContact(contactName, contactPhoneNumber);
}
});
}
Logger.exit();
}
};
Search_Contact_List.setAdapter(mAdapter);
Search_Contact_List.addOnScrollListener(new EndlessRecyclerViewScrollListener(gridLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
Logger.enter();
mAdapter.more();
Logger.exit();
}
});
Database result:

Related

How to prevent RecyclerView from refreshing all the datas when a newly data has been added?

I'm creating a simple chat app wherein every chatbubbles will be shown in a RecyclerView, now I noticed that every time ill enter a new data coming from Firebase RealTime Database, the old data's / or let's say the old chat bubbles will disappear and reappear once the newly added data has been displayed. I would like the old chat bubbles to not behave just like that, I would like it to remain appeared the whole time.
Here's my method to load every chatbubbles:
private void LoadChat() {
Query orderPosts = ChatRef.orderByChild("servertimestamp");
options = new FirebaseRecyclerOptions.Builder<Chat>().setQuery(orderPosts, Chat.class).build();
adapter = new FirebaseRecyclerAdapter<Chat, MyViewHolder12>(options) {
#Override
protected void onBindViewHolder(#NonNull MyViewHolder12 holder, int position, #NonNull Chat model) {
final String userpower = model.getPower();
final String pow = "Admin";
if (userpower.equals(pow)){
holder.chat_userpower.setVisibility(View.VISIBLE);
holder.chat_userpower.setText(model.getPower());
}
else{
holder.chat_userpower.setVisibility(View.GONE);
}
final String quotedc = model.getQuotedchat();
final String quotedn = model.getQuotedname();
if (quotedc == null){
holder.quotedchatbox.setVisibility(View.GONE);
holder.quotedchatboxlayout.setVisibility(View.GONE);
holder.quotedchatdescription.setVisibility(View.GONE);
}
else{
holder.quotedchatboxlayout.setVisibility(View.VISIBLE);
holder.quotedchatbox.setVisibility(View.VISIBLE);
holder.quotedchatdescription.setVisibility(View.VISIBLE);
holder.quotedchatdescription.setText("Quoted "+ model.getQuotedname() +" " + model.getQuotedchat());
}
holder.chat_usercomment.setText(model.getChat());
Picasso.get().load(model.getProfileimage()).placeholder(R.drawable.profile).into(holder.chat_userimage);
holder.chat_userdep.setText(model.getDep());
holder.chat_date.setText(model.getDate());
holder.chat_username.setText(model.getUsername());
holder.nestedchat_reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
quote = true;
quotedname = model.getUsername();
//CommentKey = getRef(holder.getAdapterPosition()).getKey();
quoting.setVisibility(View.VISIBLE);
quotedchat = model.getChat();
quoting.setText("Quoting "+ quotedname + ": " + model.getChat());
quoting.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
quote = false;
quoting.setVisibility(View.GONE);
}
});
}
});
}
#NonNull
#Override
public MyViewHolder12 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.allchatlayout, parent, false);
return new MyViewHolder12(view);
}
};
adapter.startListening();
allchatlist.setAdapter(adapter);
}
here's my layoutmanager:
LinearLayoutManager lm = new LinearLayoutManager(this);
lm.setReverseLayout(false);
lm.setStackFromEnd(false);
allchatlist.setNestedScrollingEnabled(false);
allchatlist.setLayoutManager(lm);
here's my code calling the method:
ChatRef = FirebaseDatabase.getInstance().getReference().child("Forums").child(ChatRoomNameKey).child("Forum ChatRoom");
ChatRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()){
LoadChat();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
To achieve that you will have to use RecyclerView DiffUtill class, more info here:
https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil
In a nutshell you have to create a diff util class:
class CustomItemDiffUtils(
private val oldList: List<CustomItem>,
private val newList: List<CustomItem>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldList.size
override fun getNewListSize(): Int = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition].data == newList[newItemPosition].data
}
}
And use this diff class in your adapter fro example with a method which can be called from the view:
fun updateList(newList: List<CustomItem>) {
val diffResult = DiffUtil.calculateDiff(CustomItemDiffUtils(oldList, newList))
oldList = newList
diffResult.dispatchUpdatesTo(this)
}
Hope this helps.
I fixed the problem by removing the line:
Query orderPosts = ChatRef.orderByChild("servertimestamp");
options = new FirebaseRecyclerOptions.Builder<Chat>().setQuery(orderPosts, Chat.class).build();
Removing that 2 lines of code from that method and putting it somewhere else inside the Activity fixed the blinking problem of my app when a new data has been added.

RecyclerView does not work sometimes when trying to display Firebase data

I have two RecyclerViews inside a LinearLayout in which I'm trying to display Firebase Storage data on one and some Products data queried from Real-Time Database on the other. While I am able to retrieve the data successfully, I have trouble showing it on the RecyclerView(s).
There are 1 of 3 things that happen spontaneously when I try to display the data:
Case 1: Data does not show on both RecyclerViews OR
Case 2: Data is shown for the first RecyclerView(displays storage
data) OR
Case 3: Data shows for both (but can sometimes take a verrryy long
time to load even though I have only one data each for both).
For the second RecyclerView, I have written the code to query in-app products data from Google Play Console using the billingclient library and I use the data queried from Real-Time DB to see if there is a match in the product IDs. If there is, I display the matching data on the RecyclerView.
While fetching the data is fine, at various times my code gets stuck on setAdapter() and I don't understand why and I don't know how to get it to work properly?
Here's a reference to my current code:
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
FirebaseStorage storage = FirebaseStorage.getInstance();
FirebaseDatabase database = FirebaseDatabase.getInstance();
storageRef = storage.getReference();
dataRef = database.getReference().child("products");
view = inflater.inflate(R.layout.course_fragment, parent, false);
mainLayout = view.findViewById(R.id.mainLayout);
filesRv = view.findViewById(R.id.file_recycler_view);
productRv = view.findViewById(R.id.product_recycler_view);
//list storage folder/files
listFilesFolders();
//check for premium data on real-time database and see if productID matches with productID on Google Play Console (display data on recycler view if it matches)
checkForPremium();
return view;
}
private void checkForPremium() {
setBillingClient(getContext());
connectToGooglePlay();
}
private void listFilesFolders() {
fileStorageRef.listAll()
.addOnSuccessListener(listResult -> {
for (StorageReference folder : listResult.getPrefixes()) {
parentFolder = folder.getName();
contentList.add(fileStorageRef.child(parentFolder));
}
for (StorageReference file : listResult.getItems()) {
fileName = file.getName();
contentList.add(fileStorageRef.child(fileName));
}
setFilesRecyclerView();
})
.addOnFailureListener(e -> {
// Some code here
})
.addOnCompleteListener(task -> {
// Some code here
});
}
private void setFilesRecyclerView() {
if(pageTitle.equals(rootFolder) || contentList.isEmpty()) {
displayFolders();
}
else {
displayFiles();
}
}
private void displayFolders() {
int columnCount = 2;
DisplayMetrics displayMetrics = view.getResources().getDisplayMetrics();
int width = displayMetrics.widthPixels; //get screen width
//if screen width is large, increase grid columns
if(width > 800 && width < 1500){
columnCount = 3;}
else if(width >= 1500 && width < 1800){
columnCount = 4; }
else if(width >= 1800){
columnCount = 5;
}
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), columnCount);
SubFolderAdapter subFolderAdapter = new SubFolderAdapter(getActivity(), contentList);
filesRv.setLayoutManager(gridLayoutManager);
filesRv.setAdapter(subFolderAdapter);
}
private void displayFiles() {
LinearLayoutManager llm1 = new LinearLayoutManager(getActivity());
fileAdapter = new FileAdapter(getActivity(), contentList);
filesRv.setLayoutManager(llm1);
filesRv.setAdapter(fileAdapter);
}
private void displayPremiumData() {
LinearLayoutManager llm2 = new LinearLayoutManager(getActivity());
productsAdapter = new ProductsAdapter3(getActivity(), billingClient, prodDetailsList, path);
productRv.setLayoutManager(llm2);
productRv.setAdapter(productsAdapter);
}
public void setBillingClient(Context context) {
System.out.println("Set billing client");
billingClient = BillingClient.newBuilder(context) //creates instance of billing client
.enablePendingPurchases()
.setListener(this)
.build();
}
public void connectToGooglePlay() {
//Establish a connection to Google Play
billingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(#NonNull BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
System.out.println("Billing client ready");
listPremium();
} else System.out.println("Billing client NOT ready");
}
#Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
System.out.println("Billing service disconnected");
}
});
}
private void listPremium() {
premiumDBRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
cProductsList.clear();
for (DataSnapshot snap: snapshot.getChildren()) {
Products products = snap.getValue(Products.class);
String sku;
String name;
String url;
if (products != null) {
sku = products.getProductId();
name = products.getName();
url = products.getUrl();
if(sku != null) {
skuList.add(sku);
}
} else {
System.out.println("Product does not exist!");
}
}
for(String sku : skuList) {
productList.add(
QueryProductDetailsParams.Product.newBuilder()
.setProductId(sku)
.setProductType(BillingClient.ProductType.INAPP)
.build()
);
}
if (!productList.isEmpty()) {
querySkuDetails(productList);
} else {
System.out.println("No products available");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
public void querySkuDetails(List<QueryProductDetailsParams.Product> productList) {
QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
.setProductList(productList)
.build();
billingClient.queryProductDetailsAsync(
params,
(billingResult, productDetailsList) -> {
// check billingResult
// process returned productDetailsList
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) {
System.out.printf(Locale.ENGLISH, "Unable to query sku details: %d - %s%n", billingResult.getResponseCode(), billingResult.getDebugMessage());
} else {
for (ProductDetails details: productDetailsList) {
prodDetailsList.add(details);
}
displayPremiumData();
}
});
}
Note: When I run the code, there are no errors. The issue is that the RecyclerView is not working consistently as intended.
I have been trying to get this to work but I have been stuck for days now and I would really appreciate some help please!

Mesibo first app in Fragment bad connection status

I'm following Mesibo Tutorial for the First App and trying to integrate it in my app. The difference to the source code of tutorial https://github.com/mesibo/samples/tree/master/android/java/FirstApp is only that I have implemented it in Fragment instead of Activity and using databinding for views.
Every time if I'm clicking to LOGIN_AS_USER1 or LOGIN_AS_USER2 Button it shows connection Status 5. The created users are never online.
The users with corresponding user addresses and app ID (app Package) were created manually in Mesibo console. Tokens, addresses and app ID are double checked.
My Fragment code:
public class CommunicationFragment extends Fragment implements Mesibo.ConnectionListener, Mesibo.MessageListener {
private FragmentCommunicationBinding binding;
class DemoUser {
public String token;
public String name;
public String address;
DemoUser(String token, String name, String address) {
this.token = token;
this.name = name;
this.address = address;
}
}
//Refer to the Get-Started guide to create two users and their access tokens
DemoUser mUser1 = new DemoUser("631b138a5bfd2827b20d312721ee6549198539a5041517df2e33311958", "User-1", "1233");
DemoUser mUser2 = new DemoUser("ae80d38f59a814b3f4694055bbd90005c2fdae2ae7a530fe44311959", "User-2", "4566");
DemoUser mRemoteUser;
Mesibo.UserProfile mProfile;
Mesibo.ReadDbSession mReadSession;
Button mSendButton, mUiButton, mAudioCallButton, mVideoCallButton;
Button mLoginButton1, mLoginButton2;
TextView mMessageStatus, mConnStatus;
EditText mMessage;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_communication, container, false);
View view = binding.getRoot();
mLoginButton1 = binding.login1;
mLoginButton2 = binding.login2;
mSendButton = binding.send;
mUiButton = binding.launchUI;
mAudioCallButton = binding.audioCall;
mVideoCallButton = binding.videoCall;
mMessageStatus = binding.msgStatus;
mConnStatus = binding.connStatus;
mMessage = binding.message;
mSendButton.setEnabled(false);
mUiButton.setEnabled(false);
mAudioCallButton.setEnabled(false);
mVideoCallButton.setEnabled(false);
mLoginButton1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mesiboInit(mUser1, mUser2); }
});
mLoginButton2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mesiboInit(mUser2, mUser1); }
});
mSendButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Mesibo.MessageParams p = new Mesibo.MessageParams();
p.peer = mRemoteUser.address;
p.flag = Mesibo.FLAG_READRECEIPT | Mesibo.FLAG_DELIVERYRECEIPT;
Mesibo.sendMessage(p, Mesibo.random(), mMessage.getText().toString().trim());
mMessage.setText("");}
});
mUiButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
MesiboUI.launchMessageView(getActivity(), mRemoteUser.address, 0);
}
});
mAudioCallButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
MesiboCall.getInstance().callUi(getActivity(), mProfile.address, false);
}
});
mVideoCallButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
MesiboCall.getInstance().callUi(getActivity(), mProfile.address, true);
}
});
return view;
}
private void mesiboInit(DemoUser user, DemoUser remoteUser) {
Mesibo api = Mesibo.getInstance();
api.init(getActivity().getApplicationContext());
Mesibo.addListener(this);
Mesibo.setSecureConnection(true);
Mesibo.setAccessToken(user.token);
Mesibo.setDatabase("mydb", 0);
Mesibo.start();
mRemoteUser = remoteUser;
mProfile = new Mesibo.UserProfile();
mProfile.address = remoteUser.address;
mProfile.name = remoteUser.name;
Mesibo.setUserProfile(mProfile, false);
// disable login buttons
mLoginButton1.setEnabled(false);
mLoginButton2.setEnabled(false);
// enable buttons
mSendButton.setEnabled(true);
mUiButton.setEnabled(true);
mAudioCallButton.setEnabled(true);
mVideoCallButton.setEnabled(true);
MesiboCall.getInstance().init(getActivity().getApplicationContext());
// Read receipts are enabled only when App is set to be in foreground
Mesibo.setAppInForeground(getActivity(), 0, true);
mReadSession = new Mesibo.ReadDbSession(mRemoteUser.address, this);
mReadSession.enableReadReceipt(true);
mReadSession.read(100);
}
#Override
public void Mesibo_onConnectionStatus(int status) {
mConnStatus.setText("Connection Status: " + status);
}
#Override
public boolean Mesibo_onMessage(Mesibo.MessageParams messageParams, byte[] data) {
try {
String message = new String(data, "UTF-8");
Toast toast = Toast.makeText(getActivity().getApplicationContext(),
message,
Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast.show();
} catch (Exception e) {
}
return true;
}
#Override
public void Mesibo_onMessageStatus(Mesibo.MessageParams messageParams) {
mMessageStatus.setText("Message Status: " + messageParams.getStatus());
}
#Override
public void Mesibo_onActivity(Mesibo.MessageParams messageParams, int i) {
}
#Override
public void Mesibo_onLocation(Mesibo.MessageParams messageParams, Mesibo.Location location) {
}
#Override
public void Mesibo_onFile(Mesibo.MessageParams messageParams, Mesibo.FileInfo fileInfo) {
}
}
Most likely you are creating a token using the wrong App ID
https://mesibo.com/documentation/faq/other/#i-am-not-getting-connection-status-1-online
If you are not getting connection status 1, and getting 4 or 5, you
are not passing the correct appid while creating a token. The appid
passed to create a token must match the Android package name declared
in the AndroidManifest.xml or iOS bundle id declared in the Xcode
project (for example, com.mesibo.xxx ). If you are using Javascript
API or other platforms, ensure that you pass the same app id to the
setAppName API call.

List<ParseUser> .contains ParseUser always FALSE

I have an if statement written below:
//Set Friend Action OnClickListener & Image
if (ParseUser.getCurrentUser().getList("friendsArray").contains(searchResultsList.get(position))) {
Glide.with(holder.imgFriendAction.getContext()).load(R.drawable.ic_phone_black_24dp).into(holder.imgFriendAction);
ImageViewCompat.setImageTintList(holder.imgFriendAction, ColorStateList.valueOf(searchContext.getColor(R.color.green)));
}
else if (ParseUser.getCurrentUser().getList("pendingFriendsArray").contains(searchResultsList.get(position))) {
Glide.with(holder.imgFriendAction.getContext()).load(R.drawable.ic_check_black_24dp).into(holder.imgFriendAction);
ImageViewCompat.setImageTintList(holder.imgFriendAction, ColorStateList.valueOf(searchContext.getColor(R.color.gray_dark)));
}
else {
Glide.with(holder.imgFriendAction.getContext()).load(R.drawable.ic_person_add_black_24dp).into(holder.imgFriendAction);
ImageViewCompat.setImageTintList(holder.imgFriendAction, ColorStateList.valueOf(searchContext.getColor(R.color.colorPrimary)));
}
The problem is that every single time I run that statement it always returns FALSE for both if statements even though I know for a fact that 'friendsArray' & 'pendingFriendsArray' return TRUE in many circumstances.
Both arrays contain pointers to the _User table.
searchResultsList is declared as follows:
private List<ParseUser> searchResultsList;
I've logged all three items (friendsArray, pendingFriendsArray & searchResultsList.get(position)) to the console and they show the following:
D/friendsArray: [com.parse.ParseUser#ae66779, com.parse.ParseUser#8371cbe, com.parse.ParseUser#32d511f, com.parse.ParseUser#5fd2c6c, com.parse.ParseUser#7dd0235, com.parse.ParseUser#9c446ca, com.parse.ParseUser#5fe03b]
D/pendingFriendsArray: [com.parse.ParseUser#7c6a358, com.parse.ParseUser#3688cb1, com.parse.ParseUser#480596]
D/searchResultsList.get(position) =: com.parse.ParseUser#5fe03b
The entire class is below:
public class SearchUserAdapter extends RecyclerView.Adapter<SearchUserAdapter.ViewHolder> {
private Context searchContext;
private List<ParseUser> searchResultsList;
OnItemClickListener onItemClickListener;
public SearchUserAdapter(Context context, List<ParseUser> dataSet) {
searchContext = context;
searchResultsList = dataSet;
}
public interface OnItemClickListener {
public void onItemClick(View view, ParseUser searchUserObject, int position);
}
public void setOnItemClickListener(final OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(searchContext).inflate(R.layout.ly_search_user, parent,false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
//Set User Name
holder.txtUserName.setText(searchResultsList.get(position).getString("fullName"));
//Set User Location
holder.txtUserLocation.setText(GlobalFunctions.getParseUserLocationAsString(holder.txtUserName.getContext(), searchResultsList.get(position)));
//Set User Profile Image
if (searchResultsList.get(position).getParseFile("profilePicture") != null) {
Glide.with(holder.imgUserProfilePicture.getContext()).applyDefaultRequestOptions(RequestOptions.circleCropTransform()).load(searchResultsList.get(position).getParseFile("profilePicture").getUrl()).into(holder.imgUserProfilePicture);
}
else {
Glide.with(holder.imgUserProfilePicture.getContext()).applyDefaultRequestOptions(RequestOptions.circleCropTransform()).load(R.drawable.ic_profile_place_holder).into(holder.imgUserProfilePicture);
}
//Set Row OnClickListener
holder.rlUserItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (searchResultsList.get(position).getObjectId().equalsIgnoreCase(ParseUser.getCurrentUser().getObjectId())) {
Intent openProfile;
openProfile = new Intent(holder.rlUserItem.getContext(), TimelineActivity.class);
holder.rlUserItem.getContext().startActivity(openProfile);
}
else {
Intent openOtherProfile = new Intent(holder.rlUserItem.getContext(), OtherUserTimelineActivity.class);
openOtherProfile.putExtra("otherUserProfileId", searchResultsList.get(position).getObjectId());
holder.rlUserItem.getContext().startActivity(openOtherProfile);
}
}
});
//Set Friend Action OnClickListener & Image
if (ParseUser.getCurrentUser().getList("friendsArray").contains(searchResultsList.get(position))) {
Glide.with(holder.imgFriendAction.getContext()).load(R.drawable.ic_phone_black_24dp).into(holder.imgFriendAction);
ImageViewCompat.setImageTintList(holder.imgFriendAction, ColorStateList.valueOf(searchContext.getColor(R.color.green)));
}
else if (ParseUser.getCurrentUser().getList("pendingFriendsArray").contains(searchResultsList.get(position))) {
Glide.with(holder.imgFriendAction.getContext()).load(R.drawable.ic_check_black_24dp).into(holder.imgFriendAction);
ImageViewCompat.setImageTintList(holder.imgFriendAction, ColorStateList.valueOf(searchContext.getColor(R.color.gray_dark)));
}
else {
Glide.with(holder.imgFriendAction.getContext()).load(R.drawable.ic_person_add_black_24dp).into(holder.imgFriendAction);
ImageViewCompat.setImageTintList(holder.imgFriendAction, ColorStateList.valueOf(searchContext.getColor(R.color.colorPrimary)));
}
holder.imgFriendAction.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
friendActionListenerAction(holder, searchResultsList.get(position));
}
});
}
private void friendActionListenerAction(ViewHolder holder, ParseUser parseUser) {
if (ParseUser.getCurrentUser().getList("friendsArray").contains(parseUser)) {
FLKCallUtils.showCallDialog(holder.imgFriendAction.getContext());
}
else if (ParseUser.getCurrentUser().getList("pendingFriendsArray").contains(parseUser)) {
//Do nothing
}
else {
//Add Friend
FLKFriendUtils.sendFriendRequestFromUserToUser(ParseUser.getCurrentUser(), parseUser);
//Update Image
Glide.with(holder.imgFriendAction.getContext()).load(R.drawable.ic_check_black_24dp).into(holder.imgFriendAction);
ImageViewCompat.setImageTintList(holder.imgFriendAction, ColorStateList.valueOf(searchContext.getColor(R.color.gray_dark)));
}
}
#Override
public int getItemCount() {
return searchResultsList.size();
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public MediumRobotoTextView txtUserName;
public RegularRobotoTextView txtUserLocation;
public RelativeLayout rlUserItem;
ImageView imgUserProfilePicture;
ImageView imgFriendAction;
public ViewHolder(View itemView) {
super(itemView);
rlUserItem = (RelativeLayout) itemView.findViewById(R.id.rl_user_container);
rlUserItem.setOnClickListener(this);
txtUserName = (MediumRobotoTextView) itemView.findViewById(R.id.txt_user_name);
txtUserLocation = (RegularRobotoTextView) itemView.findViewById(R.id.txt_user_location);
imgUserProfilePicture = (ImageView) itemView.findViewById(R.id.img_profile_picture);
imgUserProfilePicture.setOnClickListener(this);
imgFriendAction = (ImageView) itemView.findViewById(R.id.img_friend_action);
imgFriendAction.setOnClickListener(this);
}
#Override
public void onClick(View v) {
//TODO - do something here if you wish
}
}
Upon further investigation I found that the parse-android SDK does not fetch pointers the same every single time. For example when I fetch 'friendsArray', let's say right now, it will return
[com.parse.ParseUser#ae66779, com.parse.ParseUser#8371cbe, com.parse.ParseUser#32d511f, com.parse.ParseUser#5fd2c6c, com.parse.ParseUser#7dd0235, com.parse.ParseUser#9c446ca, com.parse.ParseUser#5fe03b]
However if I then fetch it, let's say in 5 minutes, it will return
[com.parse.ParseUser#ec99877, com.parse.ParseUser#674bcg, com.parse.ParseUser#749hhc, com.parse.ParseUser#6fh3d6dg, com.parse.ParseUser#jdj8dk, com.parse.ParseUser#4c966ca, com.parse.ParseUser#3f0eeb]
Additionally, I noted that even the pointer to searchResultsList.get(position) changes it's reference every time I loaded it.
The way I got around this was to create a function (seen below) that returns an array of the actual objectId's of the pointers inside the 'friendsArray'. This way I can guarantee that it will always be returning the same items and can therefore create an accurate 'contains' comparison.
public static List<String> friendsArrayObjectIdsArray() {
//Create Array of Friends
List<ParseUser> friendsArray = ParseUser.getCurrentUser().getList("friendsArray");
//Create Temp Array of Object Id's
List<String> tempObjectIdsArray = new ArrayList<>();
//Iterate List
for (ParseUser friendUser : friendsArray) {
tempObjectIdsArray.add(friendUser.getObjectId());
}
return tempObjectIdsArray;
}
I then run the following comparison to get the result I am looking for
if (FLKUserUtils.friendsArrayObjectIdsArray().contains(searchResultsList.get(position).getObjectId())) {
//Do something
}

AutoCompleteTextView with Parse.com (Android)

I'm new to Android in general, so I looked up the documentation for AutoCompleteTextView.
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line, USERS);
AutoCompleteTextView textView = (AutoCompleteTextView)
findViewById(R.id.searchUserTextField);
textView.setAdapter(adapter);
I see that it's up and running with very little code.
private static final String[] COUNTRIES = new String[] {
"user1", "user1", "user3", "user4", "user5"
};
I realize this is a stretch, but what would the next steps be with respect to implementing an autocomplete function based on my ParseUser table, especially as the text in the AutoCompleteTextView is changed by one character at a time?. Obviously, I wouldn't populate the USERS array with a Parse query displaying all of my users on each attempted search. How would I logically arrange such a thing?
To begin with, I'd probably include a TextChangedListener:
adapter.setNotifyOnChange(true);
textView.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before,
int count) {
if (count % 3 == 1) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
textview.setDropDownHeight(LayoutParams.WRAP_CONTENT);
adapter.clear();
// Run my background task here
}
}, 1000);
}
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void afterTextChanged(Editable s) {
}
});
textView.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterview, View v,
int position, long arg3) {
// TODO Auto-generated method stub
searchUserTextField.setText(adapterview.getItemAtPosition(position)
.toString());
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
But what would I provide as the background task? What am I querying so that I'm not searching through, say, 1000 users all at once, which is how many users I have in my app currently?
This seems to work. It's static in the sense that it always prints out the first 100 users in your User class. I'm sure you could add a constraint that matches the first or second letters of the AutoCompleteTextView to the usernames.
ParseQuery<ParseUser> userQuery = ParseUser.getQuery();
userQuery.findInBackground(new FindCallback<ParseUser>() {
public void done(List<ParseUser> parseUsers, ParseException e) {
if (e == null) {
Log.d("users", "Retrieved " + parseUsers.size());
ParseUser[] data = parseUsers.toArray(new ParseUser[parseUsers.size()]);
String[] strings = new String[data.length];
for (int i = 0; i < data.length; i++) {
strings[i] = data[i].getString(ParseConstants.KEY_USERNAME);
}
// Test to see if it was correctly printing out the array I wanted.
// System.out.println(Arrays.toString(strings));
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_dropdown_item_1line, strings);
AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.searchUserTextField);
if(parseUsers.size() < 40) textView.setThreshold(1);
else textView.setThreshold(2);
textView.setAdapter(adapter);
} else {
Log.d("users", "Error: " + e.getMessage());
}
}
});

Categories