I m creating a sms app for that I am working with chat list appearance here is my Chatlist adapter class.
chatlistAdapter.java:
public class chatList_AdapterClass extends BaseAdapter {
private Context mContext;
private ArrayList<chatList_row> mArrayList;
ViewHolder mHolder=null;
public chatList_AdapterClass(Context context, ArrayList<chatList_row> arrayList) {
mContext = context;
mArrayList = arrayList;
}
public class ViewHolder{
TextView mReceivedMessage;
LinearLayout.LayoutParams mParams;
ViewHolder(View v){
mReceivedMessage=(TextView)v.findViewById(R.id.ChatListMessages);
}
}
#Override
public int getCount() {
return mArrayList.size();
}
#Override
public Object getItem(int i) {
return mArrayList.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int position, View ConvertView, ViewGroup parent) {
View row=ConvertView;
if (row == null){
LayoutInflater inflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row=inflater.inflate(R.layout.chat_list_row,parent,false);
mHolder=new ViewHolder(row);
mHolder.mParams=(LinearLayout.LayoutParams)mHolder.mReceivedMessage.getLayoutParams();
row.setTag(mHolder);
}else {
mHolder=(ViewHolder)row.getTag();
}
mHolder.mReceivedMessage.setText(mArrayList.get(position).getMessageContent());
boolean send=mArrayList.get(position).getTypeofMessage().equals("send");
setChatRowAppearance(send,mHolder);
return row;
}
public void setChatRowAppearance(boolean send,ViewHolder mHolder){
if (send){
mHolder.mParams.gravity= Gravity.END;
mHolder.mReceivedMessage.setTextColor(Color.WHITE);
mHolder.mReceivedMessage.setBackgroundResource(R.drawable.bubble2);
}else {
mHolder.mParams.gravity= Gravity.START;
mHolder.mReceivedMessage.setTextColor(Color.WHITE);
mHolder.mReceivedMessage.setBackgroundResource(R.drawable.bubble1);
}
}
}
when I am sending and receiving SMS I am saving it to a database
Retrieving that from database and passing to a arraylist
From that arraylist I am creating chat appearance left and right
The problem is the after a sms send and receive the new sms should appear below the previous message but here my new messages are also appears in previous sms like ....
SEND SMS
1
3
Received sms
2
4
Related
I'm creating an Android app, the data that i'm sending through intent is being retrieved every time i click on the item.
I'm sending the retrieved data(which it's a subcollection that is being retrieved every time i click on item) through the intent,and all data receives in an arraylist, so the listener don't know if the same data existed in the arraylist,because the data are in the other activity.
when i click for the first time the data displayed normally in ItemMarkerActivity but when i go back and click again on the same item i see the data load again in the recycler view,and added to the previous same data, i'm using the technique of removing the data onStop but it didn't work perfectly,because i need to close all activities to see that the data removed, i tried to send the CollectionReference through intent but i couldn't do. so I need a way of removing the data immediately after closing the activity, and if anyone has another approach for solving this problem it would better.
Thanks in advance
adapter.setOnItemClickListener(new MarketAdapterRecyclerView.OnItemClickListener() {
#Override
public void onItemClick(DocumentSnapshot documentSnapshot, int position) {
CollectionReference path = documentSnapshot.getReference().collection("ShoppingItems");
listener = path.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot queryDocumentSnapshots, #Nullable FirebaseFirestoreException e) {
if (e != null) {
return;
}
for (DocumentChange dc : queryDocumentSnapshots.getDocumentChanges()) {
if (dc.getType() == DocumentChange.Type.ADDED) {
item = dc.getDocument().toObject(Item.class);
itemList.add(item);
}
}
Intent intent = new Intent (shoppingActivity.this, ItemMarkerActivity.class);
Log.v(TAG,"###################################" + itemList.toString());
intent.putExtra("keyName", itemList);
startActivity(intent);
}
});
}
}
The Activity That Receives The data
The Manifest
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> implements Parcelable{
public ArrayList<Item> ItemList;
public Context mContext;
private onMallListener mOnMallListener;
private static final int NO_POSITION = -1;
public ItemAdapter(ArrayList<Item> ItemList, Context mContext, onMallListener mOnMallListener) {
this.ItemList = ItemList;
this.mContext = mContext;
this.mOnMallListener = mOnMallListener;
}
protected ItemAdapter(Parcel in) {
ItemList = in.createTypedArrayList(Item.CREATOR);
}
public static final Creator<ItemAdapter> CREATOR = new Creator<ItemAdapter>() {
#Override
public ItemAdapter createFromParcel(Parcel in) {
return new ItemAdapter(in);
}
#Override
public ItemAdapter[] newArray(int size) {
return new ItemAdapter[size];
}
};
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.activity_card_view_item, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(view, mOnMallListener);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder viewHolder, int i) {
Item item = ItemList.get(i);
viewHolder.itemType.setText(ItemList.get(i).getItemType());
Picasso.with(mContext)
.load(item.getImageUrl())
.fit()
.centerCrop().into(viewHolder.imageUrl);
}
#Override
public int getItemCount() {
return ItemList.size();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(ItemList);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
View mView;
public TextView price;
public TextView description;
public TextView itemType;
public ImageView imageUrl;
onMallListener onMallListener;
public ViewHolder(#NonNull View itemView, onMallListener mOnMallListener) {
super(itemView);
mView = itemView;
itemType = (TextView) mView.findViewById(R.id.card_view_image_title);
imageUrl = (ImageView) mView.findViewById(R.id.card_view_image);
this.onMallListener = mOnMallListener;
mView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(mOnMallListener != null){
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
mOnMallListener.onMallClick(position);
}
}
}
}
public interface onMallListener{
void onMallClick(int position);
}
}
Save data using Room database in first activity and retrieve it in second.
In any place of your code (and in any activity's callback) you can clean db and all lists/recyclers which listen this data.
https://developer.android.com/training/data-storage/room
Hope it'll help
Basically I have in my Parse database two columns "rank" and "rankCount" which are both numbers.
Rank represents the total rank of the item in that row and rankCount represents the number of people who ranked it.
What I'm trying to do is create a method which will sum the average between those two, make an Int out of the number(in case its a Double/Float) and display the corresponding number with stars in a RatingBar between 1-5 stars, inside a specified Fragment with a ListView in it.
Note: I don't want to make changes in the parse database because I'm using it for the iphone version of this app witch is already complete, but I'm having a more difficult time with android.
specific Fragment class:
public class RecommendedTab extends Fragment {
ListView recommendedListView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View tab_recommended = inflater.inflate(R.layout.tab_recommended, container, false);
recommendedListView = (ListView)tab_recommended.findViewById(R.id.recommendedList);
ParseQuery<ParseObject> query = ParseQuery.getQuery("Place");
new RemoteDataTask(){
protected void onPostExecute(List<Places> places) {
recommendedListView.setAdapter(new PlacesAdapter(getActivity(), places, null));
}
}.execute(query);
return tab_recommended;
}
}
Adapter class:
public class PlacesAdapter extends BaseAdapter{
private List<Places> places=null;
private List<Places> filteredPlaces=null;
LayoutInflater inflater;
ImageLoader imageLoader;
private Context context;
private Location loc;
public PlacesAdapter(Context context, List<Places> places, Location loc){
this.context = context;
this.places = places;
inflater = LayoutInflater.from(context);
imageLoader = new ImageLoader(context);
resetPlaces();
}
public void resetPlaces(){
filteredPlaces = places;
}
public void filter(String s){
//validation
filteredPlaces = new ArrayList<Places>();//
for(int i=0;i<places.size();i++){
if(places.get(i).getName().toLowerCase().contains(s.toLowerCase())){
filteredPlaces.add(places.get(i));
}
}
}
public class ViewHolder {
RatingBar ratingBar;
TextView name;
TextView type;
TextView adress;
TextView phone;
TextView hours;
TextView details;
ImageView image;
}
#Override
public int getCount() {
return filteredPlaces.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public Object getItem(int position) {
return filteredPlaces.get(position);
}
#Override
public View getView(final int position, View view, ViewGroup parent) {
final ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = inflater.inflate(R.layout.row_layout, null);
holder.name = (TextView)view.findViewById(R.id.placeName);
holder.type = (TextView) view.findViewById(R.id.placeType);
holder.image = (ImageView) view.findViewById(R.id.placeImage);
holder.ratingBar = (RatingBar)view.findViewById(R.id.placeRate);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.ratingBar.setOnRatingBarChangeListener(onRatingChangedListener(holder, position));
holder.ratingBar.setTag(position);
holder.ratingBar.setRating(places.get(position).getRatingStar());
holder.name.setText(places.get(position).getName());
holder.type.setText(places.get(position).getType());
imageLoader.DisplayImage(places.get(position).getImage(),
holder.image);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent(context, PlaceDetails.class);
intent.putExtra("name", (places.get(position).getName()));
intent.putExtra("phone", (places.get(position).getPhone()));
intent.putExtra("hours", (places.get(position).getHours()));
intent.putExtra("rank", (places.get(position).getRatingStar()));
intent.putExtra("details", (places.get(position).getDetails()));
intent.putExtra("image", (places.get(position).getImage()));
context.startActivity(intent);
}
});
return view;
}
private RatingBar.OnRatingBarChangeListener onRatingChangedListener(final ViewHolder holder, final int position) {
return new RatingBar.OnRatingBarChangeListener() {
#Override
public void onRatingChanged(RatingBar ratingBar, float v, boolean b) {
places.get(position).setRatingStar(v);
}
};
}
}
class for the query:
public class RemoteDataTask extends AsyncTask<ParseQuery<ParseObject>, Void, List<Places>> {
#Override
protected List<Places> doInBackground(ParseQuery<ParseObject>... query) {
List<Places> places = new ArrayList<Places>();
try {
List<ParseObject> ob = query[0].find();
for (ParseObject place : ob) {
ParseFile image = (ParseFile) place.get("image");
Places p = new Places();
p.setName((String) place.get("name"));
p.setType((String) place.get("type"));
p.setHours((String) place.get("hours"));
p.setPhone((String)place.get("phone"));
p.setDetails((String) place.get("details"));
p.setImage(image.getUrl());
places.add(p);
}
} catch (ParseException e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return places;
}
}
I have many other classes in my project but im quite sure they are irrelevant for my question.
PS: what is the android equevilant for Swift's "NSUserDefaults"?
i need to check if an item already been rated and disable the RatingBar.
There are several ways to do it, for example you can:
Add an instance variable int rank to class Place with needed setter & getter.
Using Math.round set to each Place rank rounded value of rank/rankCount, both you can get with relevant ParseObject.getDouble
And then when creating view for Place, just use it's predefined rank variable as a counter for needed stars.
Note:
it's better to use: ParseObject.getString
instead of (String) place.get("name") getting an Object and then casting to String as you did. It's also mentioned in it's Parse Documentation:
In most cases it is more convenient to use a helper function such as ParseObject.getString(String) or ParseObject.getInt(String).
Leave a comment if you need further assistance
I am building a Java android app and I am using realm.io for my database. My problem is I have a RealmList and my Custom ListView adapter only accepts RealmResults. Below is the code and more details.
I have an Chat class that has a RealmList, RealmList, userId and a chatId.
public class Chat extends RealmObject{
private RealmList<Friend> participants;
private RealmList<Message> messages;
#PrimaryKey
private String chatId;
private String userId;
...
}
In my activity where I am trying to display all the messages that the chat has, I can call chat.getMessages() to get all the messages for this chat as a RealmList but my ListView adapter below takes a RealmResult because it extends RealmBaseAdapter
public class MessageAdapter extends RealmBaseAdapter<Message> implements ListAdapter {
private String TAG = getClass().getSimpleName();
public MessageAdapter(Context context,
RealmResults<Message> realmResults,
boolean automaticUpdate) {
super(context, realmResults, automaticUpdate);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
{
convertView = inflater.inflate(R.layout.listitem_message, parent, false);
}
Message message = getRealmResults().get(position);
if (message != null)
{
((TextView) convertView.findViewById(R.id.message_content)).setText(message.getContent());
DateFormat dateFormat = new SimpleDateFormat("HH:mm", Locale.CANADA);
((TextView) convertView.findViewById(R.id.message_time)).setText(dateFormat.format(message.getTimestamp()));
}
return convertView;
}
public RealmResults<Message> getRealmResults() {
return realmResults;
}
}
Here is where I call it all
RealmList<Message> messages = chat.getMessages();
ListView messageList = (ListView) findViewById(R.id.message_list);
adapter = new MessageAdapter(this, messages, true);
messageList.setAdapter(adapter);
I am open to changing my RealmList to a RealmResult if possible (I have looked and it doesn't seem to be) or If I can use a RealmList in the custom realm adapter that would another solution. Anything to help me move forward would be great help.
thanks
Just do
chat.getMessages().where().findAll()
(Answer from here)
RealmBaseAdapter has a very simple implementation.
So in the case, you can pass the specific Chat to you adapter, and overload below methods:
#Override
public int getCount() {
if (realmResults == null || realmResults.size() == 0) {
return 0;
}
return realmResults.first().getMessages().size();
}
#Override
public T getItem(int i) {
if (realmResults == null || realmResults.size() == 0) {
return null;
}
return realmResults.first().getMessages().get(i);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// You message view here
}
protected void onPostExecute( ArrayList<HashMap<String,String>> myArrayList)// for arraylist(ArrayList<String> result)
{
for (HashMap<String, String> data : myArrayList)
{
String sender_no = data.get(TAG_SENDER_NO);
String msg1=data.get(TAG_SEN_MSG);
String receiver_no=data.get(TAG_RECEIVER_NO);
if(sender_no.equals(senderno))
{
ListAdapter adapter = new SimpleAdapter(SinglechatActivity.this, myArrayList,R.layout.list_row_layout_even,
new String[] { TAG_SEN_MSG },new int[] { R.id.message_me });
// CustomList adapter= new CustomList(SinglechatActivity.this,myArrayList);//sender_no, msg1, receiver_no);
ListView lv = (ListView) findViewById(R.id.listview);
lv.setAdapter( adapter);
}
else
{
ListAdapter adapter = new SimpleAdapter(SinglechatActivity.this, myArrayList,R.layout.list_row_layout_odd,
new String[] { TAG_SEN_MSG },new int[] { R.id.message_frnd });
// CustomList adapter= new CustomList(SinglechatActivity.this, sender_no, msg1, receiver_no);
ListView lv = (ListView) findViewById(R.id.listview);
lv.setAdapter( adapter);
}
In this, I would like to have message on right hand side and left hand side based on the sender and receiver.
Use Custom adapter with separate layouts for sender and receiver messages. It is called Heterogeneous ListView.
Something like this
public class MyAdapter extends BaseAdapter {
ArrayList<HashMap<String,String>> messages;
int SENDER_MESSAGE = 0;
int RECEIVER_MESSAGE = 1;
Context context;
#Override
public int getCount() {
return messages.size();
}
#Override
public Object getItem(int position) {
return messages.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
//This is dummy logic
//Write your own logic to differentiate between sender and receiver message
if (position % 2 == 0) {
return SENDER_MESSAGE;
}
else {
return RECEIVER_MESSAGE;
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (getItemViewType(position) == SENDER_MESSAGE) {
convertView = inflater.inflate(R.layout.sender_message_layout, null);
}
else {
//Received message
convertView = inflater.inflate(R.layout.received_message_layout, null);
}
}
//...set text to message layout here
}
}
For more info on Custom Adapter you can refer this
http://www.vogella.com/articles/AndroidListView/article.html#adapterown_example
For heterogeneous ListView (Different row layouts in ListView) tutorial you can refer this
http://chrislee.kr/wp/tag/getitemviewtype-tutorial/
In your onBindViewHolder() method of your recyclerView adapter you can align the sender or receiver view layout programatically using an "if" statement. For example if it is sender align left or right, e.t.c. Use the code below for example to access and set the view layout parameters:
RelativeLayout.LayoutParams params =
(RelativeLayout.LayoutParams)button.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
params.addRule(RelativeLayout.LEFT_OF, R.id.id_to_be_left_of);
button.setLayoutParams(params);
I use ListActivity with SpecialAdapter that show some log information.
I do not use background thread but I get an error when scroll list:
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class android.widget.ListView) with Adapter(class ru.FoxGSM.ui.DebugActivity$SpecialAdapter)]
Please, help me.
(FoxLog is static class that get log information, perhaps from another thread. But in list a want show FoxLog snapshot)
public class DebugActivity extends ListActivity {
private class SpecialAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public SpecialAdapter(Context context) {
super();
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return FoxLog.count();
}
public long getItemId(int index) {
return index;
}
public Object getItem(int index) {
return FoxLog.get(FoxLog.count()-index-1);
}
// Get the type of View
public View getView(int position, View convertView, ViewGroup parent) {
TextView text;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.debug_list, null);
text = (TextView)convertView.findViewById(R.id.text);
convertView.setTag(text);
} else
text = (TextView) convertView.getTag();
String s = (String) getItem(position);
if (s==null)
return convertView;
text.setText(s);
boolean isError = false;
if (s!=null && s.length()>0) {
String prefix = s.substring(0, 1);
if (prefix.equals("E") || prefix.equals("W"))
isError = true;
}
if (isError)
text.setBackgroundResource(R.color.red);
else
text.setBackgroundDrawable(null);
return convertView;
}
}
private void RefreshData() {
FoxLog.ReInit(this);
SpecialAdapter adapter = (SpecialAdapter)this.getListAdapter();
adapter.notifyDataSetChanged();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.debug);
FoxLog.ReInit(this);
SpecialAdapter adapter = new SpecialAdapter(this);
setListAdapter(adapter);
Button mExit = (Button)findViewById(R.id.exit);
mExit.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
finish();
}
});
}
}