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
}
Related
I wanted to know how to load more data in recylcer view using firestore.
Query query = FirebaseFirestore.getInstance()
.collection("ie").limit(5);
adapter=new InterviewAdapter(this,query);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
Adapter class looks like this:
public class InterviewAdapter extends FireStoreAdapter<InterviewAdapter.ViewHolder> {
public interface OnInterviewSelectedListener {
void onInterviewSelected(DocumentSnapshot interview);
}
private InterviewAdapter.OnInterviewSelectedListener mListener;
public InterviewAdapter(Query query, OnInterviewSelectedListener listener) {
super(query);
mListener = listener;
}
#Override
public InterviewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new InterviewAdapter.ViewHolder(inflater.inflate(R.layout.ie, parent, false));
}
#Override
public void onBindViewHolder(InterviewAdapter.ViewHolder holder, int position) {
holder.bind(getSnapshot(position), mListener);
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView title,companyName,username,views,isHired;
public ViewHolder(View itemView) {
super(itemView);
title= (TextView) itemView.findViewById(R.id.title);
companyName= (TextView) itemView.findViewById(R.id.companyName);
username= (TextView) itemView.findViewById(R.id.username);
views= (TextView) itemView.findViewById(R.id.views);
isHired= (TextView) itemView.findViewById(R.id.isHired);
}
public void bind(final DocumentSnapshot snapshot,
final OnInterviewSelectedListener listener) {
InterviewExperience experience;
String companyName=snapshot.getString("companyName");
boolean isHired=Boolean.valueOf(snapshot.getBoolean("isHired"));
String username=snapshot.getString("username");
long views=new Double(Double.valueOf(snapshot.getDouble("views"))).longValue();
String id=snapshot.getId();
String title=snapshot.getString("title");
experience=new InterviewExperience(id,title,companyName,username,isHired,views,null,null);
this.title.setText(experience.getTitle());
this.companyName.setText("Company Name: "+experience.getCompanyName());
this.isHired.setText("Hired: "+experience.isHired());
this.views.setText("Views: "+experience.getViews()+"");
this.username.setText("Created By: "+experience.getUsername());
// Click listener
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (listener != null) {
listener.onInterviewSelected(snapshot);
}
}
});
}
}
}
public abstract class FireStoreAdapter<VH extends RecyclerView.ViewHolder>
extends RecyclerView.Adapter<VH>
implements EventListener<QuerySnapshot> {
private static final String TAG = "FirestoreAdapter";
private Query mQuery;
private ListenerRegistration mRegistration;
private ArrayList<DocumentSnapshot> mSnapshots = new ArrayList<>();
public FireStoreAdapter(Query query) {
mQuery = query;
}
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "onEvent:error", e);
onError(e);
return;
}
// Dispatch the event
Log.d(TAG, "onEvent:numChanges:" + documentSnapshots.getDocumentChanges().size());
for (DocumentChange change : documentSnapshots.getDocumentChanges()) {
switch (change.getType()) {
case ADDED:
onDocumentAdded(change);
break;
case MODIFIED:
onDocumentModified(change);
break;
case REMOVED:
onDocumentRemoved(change);
break;
}
}
onDataChanged();
}
public void startListening() {
if (mQuery != null && mRegistration == null) {
mRegistration = mQuery.addSnapshotListener(this);
}
}
public void stopListening() {
if (mRegistration != null) {
mRegistration.remove();
mRegistration = null;
}
mSnapshots.clear();
notifyDataSetChanged();
}
public void setQuery(Query query) {
// Stop listening
stopListening();
// Clear existing data
mSnapshots.clear();
notifyDataSetChanged();
// Listen to new query
mQuery = query;
startListening();
}
#Override
public int getItemCount() {
return mSnapshots.size();
}
protected DocumentSnapshot getSnapshot(int index) {
return mSnapshots.get(index);
}
protected void onDocumentAdded(DocumentChange change) {
mSnapshots.add(change.getNewIndex(), change.getDocument());
notifyItemInserted(change.getNewIndex());
}
protected void onDocumentModified(DocumentChange change) {
if (change.getOldIndex() == change.getNewIndex()) {
// Item changed but remained in same position
mSnapshots.set(change.getOldIndex(), change.getDocument());
notifyItemChanged(change.getOldIndex());
} else {
// Item changed and changed position
mSnapshots.remove(change.getOldIndex());
mSnapshots.add(change.getNewIndex(), change.getDocument());
notifyItemMoved(change.getOldIndex(), change.getNewIndex());
}
}
protected void onDocumentRemoved(DocumentChange change) {
mSnapshots.remove(change.getOldIndex());
notifyItemRemoved(change.getOldIndex());
}
protected void onError(FirebaseFirestoreException e) {};
protected void onDataChanged() {}
}
I used Firestore Adapter code which was given in samples of firestore documentation. Can anyone tell how to use the query object to load more data?
How to load the next 5 items in the recycler view when users scrolls to the end of the list?
You can paginate your Query's result using Query's methods like, startAt(), startAfter(), endAt(), endBefore() with a specified DocumentSnapshot.
If I considered your collection is called "interviews", you can add a method to your FireStoreAdapter like this:
private void paginate(final DocumentSnapshot last, final int limit) {
final Query subset;
if (last == null) {
subset = db.collection("interviews")
.limit(limit);
} else {
subset = db.collection("interviews")
.startAfter(last)
.limit(limit);
}
setQuery(subset);
}
You can perserve the last DocumentSnapshot within onEvent():
final List<DocumentChange> changes = documentSnapshots.getDocumentChanges();
final DocumentSnapshot lastDocument = changes.get(changes.size() - 1).getDocument();
Finally, when users scrolls to the end of the list:
paginate(lastDocument, 5);
And onDocumentAdded() will take care of it. Be carfure NOT to use startAt() because it will not execlude the last one (that already at the end of your list, and will duplicate it).
I have a recyclerview with a lot of items. I use adapter to populate the recyclerview from server, i.e. name, date, time, and so on, and it works OK.
Only issue I have is when I try and populate it based on a boolean value. When I try to add image star (for favourites option), and when I try to set is closed text (for active option), I always get all items with the "favourite icon" and "is closed" message.
For example, what I am trying to do when the working hours are returning active as false is like this:
if (!restaurant.getActive()) {
holder.isClosed.setVisibility(View.VISIBLE);
}
Boolean works just fine when I am setting it from a RestaurantDescriptionActivity, it saves and updates on server as it should, and it also returns the correct value, so I am not sure where my mistake could be.
I am returning values for boolean like this in my RestaurantModel:
#SerializedName("favourites")
private boolean isFavourite;
#SerializedName("active")
private boolean active;
----
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(thumbnailUrl);
parcel.writeString(dateTime);
parcel.writeString(id);
parcel.writeValue(comments_enabled);
// I TRIED WRITING BOOLEAN TO PARCEL IN TWO WAYS, AS SHOWN BELOW
parcel.writeValue(isFavourite);
parcel.writeInt(active ? 1 : 0);
}
//// UPDATED PART
protected restaurant(Parcel in) {
...
isFavourite = (Boolean) in.readValue(Boolean.class.getClassLoader());
active = Boolean.parseBoolean(in.readString());
}
//// UPDATED PART
public boolean getActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
Adapter:
class restaurantsViewHolder extends RecyclerView.ViewHolder {
public TextView restaurantName, date, time, isClosed;
ImageView thumbNail, isFavourite;
restaurantsViewHolder(View itemView) {
super(itemView);
thumbNail = itemView.findViewById(R.id.thumbnail);
isFavourite = itemView.findViewById(R.id.imageViewIsFavourite);
restaurantName= itemView.findViewById(R.id.restaurantNameIcon);
date = itemView.findViewById(R.id.date);
time = itemView.findViewById(R.id.time);
isClosed= itemView.findViewById(R.id.restaurantIsClosed);
}
}
public restaurantsAdapter(List<restaurant> restaurantList, Context context) {
this.restaurantItems = restaurantList;
this.context = context;
}
#Override
public restaurantsAdapter.restaurantsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row_restaurant, parent, false);
return new restaurantsViewHolder(itemView);
}
#Override
public void onBindViewHolder(restaurantsAdapter.restaurantsViewHolder holder, int position) {
// getting restaurant data for the row
restaurant restaurant = restaurantItems.get(position);
holder.restaurantName.setText(restaurant.getrestaurantName());
LocalDateTime ldt = LocalDateTime.parse(restaurant.getDateTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
String formattedDate = ldt.format(getLocalizedDateFormatter(Locale.getDefault()));
holder.date.setText(formattedDate);
//holder.date.setText(convertDate(restaurant.getDateTime())); //string dobiti u formatu, pretvoriti ga u localized i podijeliti na dva dijela
holder.time.setText(convertTime(restaurant.getDateTime()));
holder.isFavourite.clearColorFilter();
if (!restaurant.getActive()) {
holder.isClosed.setVisibility(View.GONE);
}
if (restaurant.getIsFavourite()) {
holder.isFavourite.setImageResource(R.drawable.ic_icon_star_ppdcolor);
}
}
You need to code else part inside RecyclerView item otherwise it will repopulate its previous view state.
if (!restaurant.getActive()) {
holder.isClosed.setVisibility(View.GONE);
} else{
holder.isClosed.setVisibility(View.VISIBLE);
}
if (restaurant.getIsFavourite()) {
holder.isFavourite.setImageResource(R.drawable.ic_icon_star_ppdcolor);
} else{
holder.isFavourite.setImageResource(R.drawable.your_icon_when_not_favourite);
}
make interface for the favourite click event and set that record value as true in main activity used below code ...
onItemClickListner onItemClickListner;
public interface onItemClickListner{
void onItemClick(restaurant restaurantobj); // you can pass or object or value to need to access in recycler view activity.
}
public void setOnItemClickListner(RecyclerViewAdpater.onItemClickListner onItemClickListner) {
this.onItemClickListner = onItemClickListner;
}
#Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
if (!restaurant.getActive()) {
holder.isClosed.setVisibility(View.GONE);
} else{
holder.isClosed.setVisibility(View.VISIBLE);
}
if (restaurant.getIsFavourite()) {
holder.isFavourite.setImageResource(R.drawable.ic_icon_star_ppdcolor);
} else{
holder.isFavourite.setImageResource(R.drawable.your_icon_when_not_favourite);
}
holder.isFavourite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClickListner.onItemClick(restaurant);
}
});
}
and after when you define adapter object in mainactivity that used below code ...
adpater.setOnItemClickListner(new RecyclerViewAdpater.onItemClickListner() {
#Override
public void onItemClick(restaurant restaurantobj) {
restaurantobj.setActive(true);
restaurantList.add(restaurantobj);
adpater.notifyDataSetChanged();
}
});
Heterogeneous RecyclerView
Hello friends I have a simple doubt
Here i am adding singleLineText
`addSingleLine.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String singleLineText = singleline.getText().toString();
if(singleLineText.length() != 0)
{
mAdapter.addItem(singleLineText,null);
mAdapter.notifyDataSetChanged();
Log.e(TAG,"adding single line text");
}
singleline.getText().clear();
}
});`
On this part i am adding MultiLineText
` addMultiLine.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String multiLineText = multiline.getText().toString();
String myList[] = multiLineText.split(",");
for(String item : myList)
{
mAdapter.addItem(null,item);
mAdapter.notifyDataSetChanged();
Log.e(TAG,"adding multi line text");
}
multiline.getText().clear();
}
});
}`
My Adapter part of code:
` public void addItem(String singleLineText, String item) {
Model model = new Model();
if(item == null) {
model.setText1(singleLineText);
model.settingSingleLineText(true); // How to identify single line
}
else
{
model.setText2(item);
model.settingMultiLineText(true); // How to identify multiple line
}
modelList.add(model);
}`
GetViewType Method:
` public int getItemViewType(int position) {
if (modelList.get(position).IfSingleLine() != null)
return VERTICAL;
else {
return HORIZONTAL;
}
}`
Model class code snippet:
private Boolean checkSingleLine = null;
public Boolean IfSingleLine()
{
return checkSingleLine;
}
public void settingSingleLineText(Boolean txt1)
{
checkSingleLine = txt1;
}
public void settingMultiLineText(Boolean txt2)
{
checkMultiLine = txt2;
}
`
Problem: How to identify the singleLineText and multiLineText by using the Model Class??
You have a problem with your if (modelList.get(position).IfSingleLine() != null). IfSingleLine() will never be null. You want to check if it is true or false and this is not how you check for that.
Change your getItemViewType to the following and you will get correct orientation result from this function.
public int getItemViewType(int position) {
if (modelList.get(position).IfSingleLine())
return VERTICAL;
else {
return HORIZONTAL;
}
}`
I have an ArrayList of a custom object. This ArrayList I pass to my RecyclerView Adapter. When an event occurs I need to retrieve the object from the ArrayList that contains a variable with a unique value, make changes to that object and then reload the ViewHolder corresponding to that object. How do I achieve this?
The problem is that I don't have the position of the object within the ArrayList because the positions keep changing dynamically. I just have this unique value corresponding to a object on the basis of which I want to make changes.
I tried doing list.clear() then reassigning objects to the ArrayList with the updated values and then calling adapter.notifyDataSetChanged() but it didn't work.
EDIT:
I have provided the code below of the Activity which contains the recyclerview. The actual code is much larger so I decided to edit it to only show the necessary details regarding this question. Please let me know if I need to add more code.
So, basically what happens here is that IMActivity is bound to a service and passes its context to the service while binding. When an event occurs in the service a database value is changed and updateActivity() is called in the service.
What I want updateActivity() to do is to check the chatMsgList for a ChatMsg object that contains a variable that has a unique value and reload the viewholder corresponding to that ChatMsg object.
Please let me know if I need to clarify further.
public class IMActivity extends AppCompatActivity implements Sertivity {
private RecyclerView recyclerView;
private ImAdapter imAdapter;
private List<ChatMsg> chatMsgList = new ArrayList<>();
EditText etIM;
ImageButton ibSend;
TalkSeeService.TalkSeeBinder talkSeeBinder;
String usernames[]= new String[10];
String otherUserName;
List<Msg> msgList;
DBAct db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService(new Intent(com.abdralabs.talksee.IMActivity.this, TalkSeeService.class), new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
talkSeeBinder = (TalkSeeService.TalkSeeBinder)service;
talkSeeBinder.setSertivity(com.abdralabs.talksee.IMActivity.this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
talkSeeBinder.setSertivity(null);
talkSeeBinder = null;
}
},BIND_AUTO_CREATE);
setContentView(R.layout.activity_im);
recyclerView = (RecyclerView)findViewById(R.id.rv_im);
imAdapter = new ImAdapter(chatMsgList);
LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(imAdapter);
ibSend = (ImageButton)findViewById(R.id.ib_send);
etIM = (EditText)findViewById(R.id.et_im);
ibSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//THE TEXT FROM THE EDITTEXT IS TAKEN AND THEN ADDED TO THE DATABASE
updateChatData();
}
});
db = new DBAct(com.abdralabs.talksee.IMActivity.this,otherUserName);
msgList = db.getAllMessages();
db.close();
prepareChatData();
}
private void prepareChatData() {
for (int i=0; i<msgList.size(); i++) {
ChatMsg chatMsg = new ChatMsg(msgList.get(i).getMessage(),
convertToDayDateTime(Long.valueOf(msgList.get(i).getTime())),
msgList.get(i).getOther(),
getReceiptFromDelivered(i));
chatMsgList.add(chatMsg);
}
imAdapter.notifyDataSetChanged();
}
private void updateChatData(){
msgList = db.getAllMessages();
db.close();
int i = msgList.size() - 1;
ChatMsg chatMsg = new ChatMsg(msgList.get(i).getMessage(),
convertToDayDateTime(Long.valueOf(msgList.get(i).getTime())),
msgList.get(i).getOther(),
getReceiptFromDelivered(i));
chatMsgList.add(chatMsg);
imAdapter.notifyDataSetChanged();
recyclerView.smoothScrollToPosition(imAdapter.getItemCount());
}
#Override
public void updateActivity() {
chatMsgList.clear();
prepareChatData();
recyclerView.smoothScrollToPosition(imAdapter.getItemCount());
}
#Override
public void callActivityMethod() {
updateChatData();
}
private String convertToDayDateTime(long timestamp){
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();
SimpleDateFormat sdf = new SimpleDateFormat("EEE dd/MM/yyyy HH:mm");
sdf.setTimeZone(tz);
String localTime = sdf.format(new Date(timestamp));
return localTime;
}
private String getReceiptFromDelivered(int position){
String receipt;
if (msgList.get(position).getDelivered().equals("0")){
receipt = "...";
}else {
receipt = "S";
}
return receipt;
}
}
IMAdapter.java
public class ImAdapter extends RecyclerView.Adapter <RecyclerView.ViewHolder> {
private List<ChatMsg> chatMsgList = new ArrayList<ChatMsg>();
final int VIEW_TYPE_USER = 1;
final int VIEW_TYPE_OTHER = 0;
public ImAdapter(List<ChatMsg> chatMsgList){
this.chatMsgList = chatMsgList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType==VIEW_TYPE_USER){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_msg_user,parent,false);
return new ImUserViewHolder(itemView);
}
else {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_msg_other,parent,false);
return new ImOtherViewHolder(itemView);
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType()==VIEW_TYPE_USER){
ChatMsg chatMsg = chatMsgList.get(position);
ImUserViewHolder imUserViewHolder = (ImUserViewHolder)holder;
imUserViewHolder.msg.setText(chatMsg.getMsg());
imUserViewHolder.timeStamp.setText(chatMsg.getTime());
}
else {
ChatMsg chatMsg = chatMsgList.get(position);
ImOtherViewHolder imOtherViewHolder = (ImOtherViewHolder) holder;
imOtherViewHolder.msg.setText(chatMsg.getMsg());
imOtherViewHolder.timeStamp.setText(chatMsg.getTime());
}
}
#Override
public int getItemViewType(int position) {
ChatMsg chatMsg = chatMsgList.get(position);
if (chatMsg.getOther().equals("true")){
return VIEW_TYPE_OTHER;
}
else {
return VIEW_TYPE_USER;
}
}
#Override
public int getItemCount() {
return chatMsgList.size();
}
public class ImOtherViewHolder extends RecyclerView.ViewHolder{
public TextView msg;
public TextView timeStamp;
public ImOtherViewHolder(View itemView) {
super(itemView);
msg = (TextView)itemView.findViewById(R.id.tv_chat_msg_other);
timeStamp = (TextView)itemView.findViewById(R.id.tv_time_chat_msg_other);
}
}
public class ImUserViewHolder extends RecyclerView.ViewHolder{
public TextView msg;
public TextView timeStamp;
public ImUserViewHolder(View itemView) {
super(itemView);
msg = (TextView)itemView.findViewById(R.id.tv_chat_msg_user);
timeStamp = (TextView)itemView.findViewById(R.id.tv_time_chat_msg_user);
}
}
}
To you IMAdapter add method
public void setChatMsgList(List<ChatMsg> chatMsgList ) {
this.chatMsgList = chatMsgList;
}
and in your IMActivity in method prepareChatData call this new setChatMsgList method
{
...
chatMsgList.add(chatMsg);
}
imAdapter.setChatMsgList(chatMsgList);
imAdapter.notifyDataSetChanged();
I'm trying to make a simple app that lists all the found Ibeacons in a ListView and changes the RSSI values according to the distance the user is from the beacons itself.
The app works fine, but the problem I'm having is that if a beacon is out of reach it does not get removed from the list. Any ideas on how to remove the item when the beacon isn't in range anymore?
I have the following code:
MainActivity.java:
public class MainActivity extends Activity implements BeaconConsumer {
public ListView list;
public BeaconAdapter adapter;
public ArrayList<Beacon> arrayL = new ArrayList<>();
public LayoutInflater inflater;
public BeaconManager mBeaconManager;
public boolean beaconPresent;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = (ListView)findViewById(R.id.lijst);
mBeaconManager = BeaconManager.getInstanceForApplication(this.getApplicationContext());
mBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
mBeaconManager.setForegroundBetweenScanPeriod(100);
mBeaconManager.bind(this);
adapter = new BeaconAdapter();
list.setAdapter(adapter);
inflater =(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void onBeaconServiceConnect() {
Region region = new Region("all-beacons-region", null, null, null);
try {
mBeaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
mBeaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(final Collection<Beacon> beacons, Region region) {
runOnUiThread(new Runnable() {
#Override
public void run() {
ArrayList<Beacon> allRangedBeacons = (ArrayList<Beacon>) beacons;
ArrayList<Beacon> newRangedBeacons = new ArrayList<>();
ArrayList<Beacon> cloneArraylistIBeacon = (ArrayList<Beacon>) arrayL.clone();
ArrayList<Beacon>nonRangedBeacons = new ArrayList<>();
int index = 0;
for (Beacon presentBeacons : cloneArraylistIBeacon) {
beaconPresent = false;
for (Beacon eachRangedBeacon : allRangedBeacons) {
if (presentBeacons.equals(eachRangedBeacon)) {
arrayL.remove(index);
arrayL.add(index, eachRangedBeacon);
beaconPresent = true;
}
if(beaconPresent = false) {
nonRangedBeacons.add(presentBeacons);
}
}
index++;
}
for (Beacon eachRangedBeacon : allRangedBeacons) {
beaconPresent = false;
for (Beacon presentBeacons : cloneArraylistIBeacon) {
if (eachRangedBeacon.equals(presentBeacons)) {
beaconPresent = true;
}
}
if (!beaconPresent) {
newRangedBeacons.add(eachRangedBeacon);
}
}
arrayL.remove(nonRangedBeacons);
arrayL.addAll(newRangedBeacons);
adapter.notifyDataSetChanged();
}
});
}
});
}
protected void onPause() {
super.onPause();
mBeaconManager.unbind(this);
}
private class BeaconAdapter extends BaseAdapter {
#Override
public int getCount() {
if (arrayL != null && arrayL.size() > 0) {
return arrayL.size();
} else {
return 0;
}
}
#Override
public Beacon getItem(int position) {
return arrayL.get(position);
}
#Override
public long getItemId(int arg0) {
return arg0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
holder = new ViewHolder(convertView = inflater.inflate(R.layout.tupple_monitoring, null));
try {
holder.uuid.setText("UUID: " + arrayL.get(position).getId2());
holder.rssi.setText("RSSI: " + arrayL.get(position).getRssi());
holder.txpow.setText("TXPOW: " + arrayL.get(position).getTxPower());
return convertView;
}catch(Exception e) {
e.printStackTrace();
}
return convertView;
}
}
private class ViewHolder {
private TextView uuid;
private TextView rssi;
private TextView txpow;
public ViewHolder(View view) {
uuid = (TextView)view.findViewById(R.id.BEACON_uuid);
rssi = (TextView)view.findViewById(R.id.BEACON_rssi);
txpow = (TextView)view.findViewById(R.id.BEACON_txpower);
view.setTag(this);
}
}
}
If you only want to display beacons in range, every time you receive a list of beacons simply change the adapter source list.
arrayL.clear();
arrayL.addAll(beacons);
adapter.notifyDataSetChanged();
To avoid jumping around if list items, maybe sort the beacons by their RSSI before displaying them.
Because the Android Beacon Library already tracks the list of visible beacons and updates it in the ranging callback, you can simply refresh the whole list in your BeaconAdapter each time. Like this:
#Override
public void didRangeBeaconsInRegion(final Collection<Beacon> beacons, Region region) {
runOnUiThread(new Runnable() {
#Override
public void run() {
arrayL = new ArrayList<Beacon>(beacons);
adapter.notifyDataSetChanged();
}
});
}