CustomView in RecyclerView malfunctioning ( items get swapped , disappeared or repeated ) - android

I am implementing a local chat_box like page, I have two Vectors queued_messages and messages. I remove items from queued list and add to the messages and wait in the asynctask to add other items.three kind of messages sent received and multiple choice questions.multiple choice questions have the problems in the title.(especially if you scroll to top page while they get loading)
1.I have already set has fixed size to true
2.tried making custom view directly in adapter instead of inflating a view containing it
3.set is recyclable to off and implemented both selected and unselected mode in onbindviewholder
4.tried different kind of notifies.
5.disabled scroll to last position
my Adapter:
public class MessageListAdapter extends RecyclerView.Adapter {
private List<Message> messages;
MessageListAdapter(List<Message> messages) {
this.messages = messages;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view;
if (i == Message.RECEIVED_MESSAGE) {
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recieved_message, viewGroup, false);
return new Received_Message_Holder(view);
} else if (i == Message.MULTIPLE_CHOICE) {
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.multiple_choice_item, viewGroup, false);
return new Multiple_Choice_Holder(view);
} else if (i == Message.SENT_MESSAGE) {
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.sent_message, viewGroup, false);
return new Sent_Message_Holder(view);
}else
return null;
}
#Override
public int getItemViewType(int position) {
Message message = messages.get(position);
return message.getType();
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
Message msg = messages.get(i);
if (msg.getType() == Message.RECEIVED_MESSAGE)
((Received_Message_Holder) viewHolder).bind(msg);
else if (msg.getType() == Message.MULTIPLE_CHOICE) {
//viewHolder.setIsRecyclable(false);
((Multiple_Choice_Holder) viewHolder).bind((Question) msg);
}
else if (msg.getType() == Message.SENT_MESSAGE)
((Sent_Message_Holder) viewHolder).bind(msg);
}
#Override
public int getItemCount() {
return messages.size();
}
}
class Received_Message_Holder extends RecyclerView.ViewHolder {
TextView messageText, timeText, nameText;
ImageView profileImage;
Received_Message_Holder(View itemView) {
super(itemView);
messageText = itemView.findViewById(R.id.text_message_body);
timeText = itemView.findViewById(R.id.text_message_time);
nameText = itemView.findViewById(R.id.text_message_name);
profileImage = itemView.findViewById(R.id.image_message_profile);
}
void bind(Message message) {
messageText.setText(message.getMessage());
timeText.setText(message.get_date());
nameText.setText(message.getSender().getNickname());
// Insert the profile image from the URL into the ImageView.
profileImage.setImageResource(R.drawable.male);
}
}
class Sent_Message_Holder extends RecyclerView.ViewHolder {
TextView name, text, time;
ImageView profile_image;
public Sent_Message_Holder(#NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.text_message_name);
text = itemView.findViewById(R.id.text_message_body);
time = itemView.findViewById(R.id.text_message_time);
profile_image = itemView.findViewById(R.id.image_message_profile);
}
void bind(Message message) {
text.setText(message.getMessage());
time.setText(message.get_date());
name.setText(message.getSender().getNickname());
// Insert the profile image from the URL into the ImageView.
profile_image.setImageResource(R.drawable.male);
}
}
class Multiple_Choice_Holder extends RecyclerView.ViewHolder {
Collection_Picker picker;
Multiple_Choice_Holder(View itemView) {
super(itemView);
picker = itemView.findViewById(R.id.collection_picker);
}
void bind(Question question) {
List<Choice_Item> items = new ArrayList<>();
for (int i = 0; i < question.getOptions().size(); i++) {
items.add(new Choice_Item(String.valueOf(i), question.getOptions().get(i)));
}
if(question.getAnsPosition() != -1)
{
Log.wtf("TAg","redraw");
picker.draw_fixed(items.get(question.getAnsPosition()));
}else {
Log.wtf("TAg","drwing from zero");
picker.setItems(items);
picker.setListener(question.getListener());
}
}
}
And the Activity which uses this:
public class Chat_activity extends AppCompatActivity implements questionListener{
Vector<Message> queued_messages = new Vector<>();
List<Message> messages = new ArrayList<>() ;
RecyclerView recyclerView ;
MessageListAdapter adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_page_activity);
recyclerView = findViewById(R.id.reyclerview_message_list);
init_messages();
LinearLayoutManager manager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
recyclerView.setNestedScrollingEnabled(false);
adapter = new MessageListAdapter(messages);
recyclerView.setAdapter(adapter);
start_chat_show();
//edit text also add sent message to messages
}
int evaluate_message_size(Message message){
return message.getMessage().length()*50;
}
void start_chat_show(){
new async_task(evaluate_message_size(queued_messages.get(0))).execute();
}
#Override
public void onQuestionAnswered(int ansPosition) {
afterQuestion(ansPosition);
}
class async_task extends AsyncTask<Void,Void,Void> {
int time_interval = 200;
public async_task(int time_interval){
super();
this.time_interval = time_interval;
}
#Override
protected Void doInBackground(Void... voids) {
try {
Thread.sleep(time_interval);
}catch (InterruptedException e){
Log.d("Tavak", "real errors!");
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
next_message();
}
}
private void next_message(){
if(queued_messages.size()>0) {
messages.add(queued_messages.get(0));
queued_messages.remove(0);
Log.wtf("tag", String.valueOf(messages.size()));
adapter.notifyItemInserted(messages.size()-1);
if (messages.get(messages.size() - 1).getType() == Message.MULTIPLE_CHOICE) {
lastQuestionPosition = messages.size() - 1;
}
if (queued_messages.size() > 0 && messages.get(messages.size() - 1).getType() != Message.MULTIPLE_CHOICE && !messages.get(messages.size() - 1).isHas_input())
new async_task(evaluate_message_size(messages.get(messages.size() - 1))).execute();
// recyclerView.scrollToPosition(adapter.getItemCount());
}
}
public void afterQuestion(int ansPosition){
((Question)messages.get(lastQuestionPosition)).setAnsPosition(ansPosition);
((Question)messages.get(lastQuestionPosition)).actOnAnswer();
if(queued_messages.size()>0)
next_message();
}
private void questionChild(int position){
User user = new User();
user.setNickname("us");
Message msg4 = new Message();
msg4.setSender(user);
msg4.setMessage("what kind are you?");
msg4.setHas_input(true);
queued_messages.add(position+1,msg4);
Message msg5 = new Message();
msg5.setSender(user);
msg5.setMessage("whats up?");
msg5.setHas_input(true);
queued_messages.add(position+2,msg5);
Message msg5_5 = new Message();
msg5_5.setSender(user);
msg5_5.setMessage("repeat process?");
queued_messages.add(msg5_5);
Question msg6 = new Question();
msg6.setSender(user);
msg6.setQuestion("repeat process?");
Vector<String> options0 = new Vector<>();
options0.add("yes");
options0.add("no");
msg6.setOptions(options0);
msg6.setListener(this);
msg6.setItem_listener(new questionListener() {
#Override
public void onQuestionAnswered(int ansPosition) {
if(ansPosition == 0){
questionChild(-1);
}
}
});
queued_messages.add(position+3,msg6);
}
private void init_messages(){
final User user = new User();
user.setNickname("us");
Message msg = new Message();
msg.setSender(user);
msg.setMessage("hello");
queued_messages.add(msg);
Message msg2 = new Message();
msg2.setSender(user);
msg2.setMessage("welcome to your place");
queued_messages.add(msg2);
Message msg3 = new Message();
msg3.setSender(user);
msg3.setMessage("good luck");
queued_messages.add(msg3);
Message msg4 = new Message();
msg4.setSender(user);
msg4.setMessage("what kind is it?");
msg4.setHas_input(true);
queued_messages.add(msg4);
Message msg5 = new Message();
msg5.setSender(user);
msg5.setMessage("how old؟");
msg5.setHas_input(true);
queued_messages.add(msg5);
Message msg5_5 = new Message();
msg5_5.setSender(user);
msg5_5.setMessage("any other one?");
queued_messages.add(msg5_5);
Question msg6 = new Question();
msg6.setSender(user);
msg6.setQuestion("any other one?");
Vector<String> options0 = new Vector<>();
options0.add("yes");
options0.add("no");
msg6.setOptions(options0);
msg6.setListener(this);
msg6.setItem_listener(new questionListener() {
#Override
public void onQuestionAnswered(int ansPosition) {
if(ansPosition == 0){
questionChild(-1);
}
}
});
queued_messages.add(msg6);
Message msg6_5 = new Message();
msg6_5.setSender(user);
msg6_5.setMessage("your problem?");
queued_messages.add(msg6_5);
Question q = new Question();
q.setQuestion("your problem?");
Vector<String> options = new Vector<>();
options.add("Im feeling bad");
options.add("stuck in my room");
options.add("kidnapped");
options.add("none of above");
q.setOptions(options);
q.setListener(this);
q.setItem_listener(new questionListener() {
#Override
public void onQuestionAnswered(int ansPosition) {
if(ansPosition == 0){
next_message();
}
}
});
queued_messages.add(q);
Message msg9 = new Message();
msg9.setSender(user);
msg9.setMessage("Its natural");
queued_messages.add(msg9);
Message msg10 = new Message();
msg10.setSender(user);
msg10.setMessage("easilly solvabe.");
queued_messages.add(msg10);
Message msg11 = new Message();
msg11.setSender(user);
msg11.setMessage("join us and learn.");
queued_messages.add(msg11);
Message msg12 = new Message();
msg12.setSender(user);
msg12.setMessage("wanna join us؟");
queued_messages.add(msg12);
Question q2 = new Question();
q2.setQuestion("wanna join us?");
Vector<String> options1 = new Vector<>();
options1.add("yes");
options1.add("no");
q2.setOptions(options1);
q2.setListener(this);
q2.setItem_listener(new questionListener() {
#Override
public void onQuestionAnswered(int ansPosition) {
if(ansPosition == 0){
Toast.makeText(Chat_activity.this,"we;re set to go",Toast.LENGTH_SHORT).show();
Intent mintent = new Intent(Chat_activity.this,Khans_activity.class);
startActivity(mintent);
finish();
}
}
});
queued_messages.add(q2);
}
}
I wish that recyclerview works correctly(without any disappearing , repeated values or swaped items).
Please inform me if you need any further detail.

Related

java.lang.ArrayIndexOutOfBoundsException: length=22; index=-1

i am very new to Android Studio and making app with my WordPress website and using Rest Api to fetch data from my website , all works fine and i have added sort posts menu in my app and users can sort posts by "most views" "most commented" etc. and it also works fine but the problem occurred when i load all posts in app , like i have 12 posts in my website and when i go to end in app and then i click on button sort by "most views" or "most commented" then i see this error ..
java.lang.ArrayIndexOutOfBoundsException: length=22; index=-1
at java.util.ArrayList.remove(ArrayList.java:506)
at com.testtest.test.PostAdapter.showHideProgress(PostAdapter.java:158)
at com.testtest.test.MainActivity$7.onResponse(MainActivity.java:293)
this is PostAdapter
private List<Model> dataset;
private Context mContext;
int total_types;
int viewTypeData = 0,viewTypeProgress = 2 ;
private static final int AD = 1;
private static final int LIST_AD_DELTA = 4;
AdView adview;
public PostAdapter(List<Model> list){
dataset = list;
}
#NotNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NotNull ViewGroup parent, int viewType) {
mContext = parent.getContext();
if (viewType == AD) {
adview = new AdView(mContext);
adview.setAdSize( AdSize.LARGE_BANNER);
adview.setAdUnitId(mContext.getResources().getString(R.string.banner_ad_unit_id));
float density = mContext.getResources().getDisplayMetrics().density;
int height = Math.round(AdSize.LARGE_BANNER.getHeight() * density);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(AbsListView.LayoutParams.FILL_PARENT, height);
adview.setLayoutParams(params);
new RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("C5468C2B8941779E34B14EB796B9EA1B"));
AdRequest request = new AdRequest.Builder().build();
adview.loadAd(request);
return new Holder(adview);
}
if (viewType == viewTypeData){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_list,parent,false);
return new MyDataHolder(view);
}else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading,parent,false);
return new MyProgressHolder(view);
}
}
public void clearApplications() {
int size = this.dataset.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
dataset.remove(0);
}
this.notifyItemRangeRemoved(0, size);
}
}
#Override
public void onBindViewHolder(#NotNull RecyclerView.ViewHolder holder, int position) {
Model model = dataset.get(getRealPosition(position));
String tagID = model.tagsid;
if (holder instanceof MyDataHolder){
((MyDataHolder)holder).showModel(model);
Glide.with(mContext)
.load(model.imageUrl)
.dontAnimate()
.placeholder(R.drawable.icon)
.into( ((MyDataHolder)holder).imageView);
}
}
private int getRealPosition(int position) {
if (LIST_AD_DELTA == 0) {
return position;
} else {
return position - position / LIST_AD_DELTA;
}
}
#Override
public int getItemCount() {
return dataset.size();
}
#Override
public int getItemViewType(int position){
if (position > 0 && position % LIST_AD_DELTA == 0) {
return AD;
}
return viewTypeData;
}
void showHideProgress(boolean shouldShowProgress){
if (shouldShowProgress){
dataset.add(new Model("progress","","","","","","","","","",""));
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
notifyItemInserted(dataset.size()-1);
}
};
handler.post(r);
}else {
dataset.remove(dataset.size()-1);
notifyItemRemoved(dataset.size()-1);
}
}
void addItemsToList(List<Model> newItems){
if (dataset.isEmpty()){
dataset.addAll(newItems);
notifyDataSetChanged();
}else {
int lastItemPosition = dataset.size() -1;
dataset.addAll(newItems);
notifyItemRangeInserted(lastItemPosition,newItems.size());
}
}
class MyDataHolder extends RecyclerView.ViewHolder{
TextView titleView,subTitleView,postViews,tagsView,date;
ImageView imageView;
ImageButton sharebtn;
CardView rootView;
// Use Glide to load image to image view
public MyDataHolder(#NotNull View itemView) {
super(itemView);
titleView = itemView.findViewById(R.id.title);
date = itemView.findViewById(R.id.date);
subTitleView = itemView.findViewById(R.id.subtitle);
postViews = itemView.findViewById(R.id.postview);
tagsView = itemView.findViewById(R.id.tags);
imageView = itemView.findViewById(R.id.Icon);
sharebtn = itemView.findViewById(R.id.share);
rootView = itemView.findViewById(R.id.recycler_item_root_view);
tagsView.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putParcelable("my_key",dataset.get(getRealPosition(getAdapterPosition())));
Model model = bundle.getParcelable("my_key");
if (model != null) {
String tagsID = model.tagsid;
tagsID = tagsID.replace("[", "");
tagsID = tagsID.replace("]", "");
String newTags = null;
if(tagsID.contains(".")){
newTags = tagsID.substring(0, tagsID.indexOf("."));
} else {
newTags = tagsID;
}
String tagsName = model.tags;
tagsID = tagsID.replace("[", "");
tagsID = tagsID.replace("]", "");
Intent webviewIntent = new Intent(mContext, TagsActivity.class);
webviewIntent.putExtra("TagsID", newTags);
webviewIntent.putExtra("TagsName", tagsName);
webviewIntent.putExtra("Toolbar", "Notification");
mContext.startActivity(webviewIntent);
}
});
sharebtn.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putParcelable("my_key",dataset.get(getRealPosition(getAdapterPosition())));
Model model = bundle.getParcelable("my_key");
if (model != null) {
String content = String.valueOf((Html.fromHtml(model.content)));
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT,
model.title + "\n" + content + "\n" +
mContext.getResources().getString(R.string.shareapp) + " " +
mContext.getResources().getString(R.string.shareurl));
sendIntent.setType("text/plain");
mContext.startActivity(sendIntent);
}
});
rootView.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putParcelable("my_key",dataset.get(getRealPosition(getAdapterPosition())));
Intent intent = new Intent(mContext, PostDetails.class);
intent.putExtra("my_bundle",bundle);
mContext.startActivity(intent);
});
}
void showModel(Model model){
titleView.setText(model.title);
tagsView.setText(model.tags);
date.setText(model.date);
subTitleView.setText(model.subTitle);
postViews.setText(model.commentcount);
}
}
static class MyProgressHolder extends RecyclerView.ViewHolder{
ProgressBar progressBar;
public MyProgressHolder(#NotNull View itemView) {
super(itemView);
progressBar = itemView.findViewById(R.id.progressbar);
}
void show(){
progressBar.setVisibility(View.VISIBLE);
}
}
public class Holder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public Holder(View itemView) {
super(itemView);
}
}
}
and this is how i fetch most viewed posts
if (id == R.id.action_view) {
adapter.clearApplications();
yourURL = baseURL + mostView;
getRetrofit();
tv.setVisibility(View.VISIBLE);
return true;
}
i have tried this
public void clearApplications() {
int size = this.dataset.size() -1;
if (size > 0) {
for (int i = 0; i < size; i++) {
dataset.remove(0);
}
this.notifyItemRangeRemoved(0, size);
}
}
but it did not work properly ,, please help

The items added multiple times into the RecyclerView with pagining

I am working on android app with java. and now I have to do messaging activities. I use RecyclerView to display the messages items. Also my messages Api is work with pagining, every time I send the last id and the server return the previous 10 messages.(Page size is 10). For filling the RecyclerView I use an Adapter but my problem is, that the item is added multiple times into the RecyclerView.
I will put my activity code and the adapter code
My Activity:
public class ConversationsActivity extends RootActivity implements ConversationsAdapter.ConversationOnClickHandler {
RetrofitBuilder rB = new RetrofitBuilder();
IApi service = rB.retrofit.create(IApi.class);
String authorization;
RecyclerView rv;
ConversationsAdapter adapter;
ProgressBar progressBar;
LinearLayoutManager layoutManager;
//declare it as global var for future cancel refresh
private SwipeRefreshLayout swipeLayout;
boolean wasSwiped;
// initialise loading state
boolean mIsLoading, mIsLastPage = false;
// amount of items you want to load per page
final int pageSize = 10;
int mCurrentPage =0;
int lastId;
boolean f;
int p =1;
private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.7F);
int chatId, to;
String senderType, name, to_type;
TextView no_data;
Button btnActionBar11, send;
TextView tvActionBar;
EditText message;
Context context;
ArrayList<Conversation.Data> conversationArrayList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_conversations);
context = this;
adapter = new ConversationsAdapter(this,context);
Intent intent = getIntent();
chatId = intent.getIntExtra("chatId",0);
Intent intent1 = getIntent();
senderType = intent1.getStringExtra("senderType");
Intent intent2 = getIntent();
name = intent2.getStringExtra("name");
Intent intent3 = getIntent();
to = intent3.getIntExtra("from",0);
Intent intent4 = getIntent();
to_type = intent4.getStringExtra("from_type");
buttonClick.setDuration(500);
authorization = checkAuthorization();
setContentView(R.layout.activity_conversations);
progressBar = (ProgressBar) findViewById(R.id.progress);
tvActionBar = (TextView) findViewById(R.id.tvActionBar);
tvActionBar.setText(name);
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
layoutManager.setReverseLayout(true);
adapter.setHasStableIds(true);
// layoutManager.setStackFromEnd(true);
rv = (RecyclerView) findViewById(R.id.ConversationList);
no_data = (TextView) findViewById(R.id.no_data);
message = (EditText) findViewById(R.id.message);
send = (Button) findViewById(R.id.send);
rv.setLayoutManager(layoutManager);
btnActionBar11 = (Button) findViewById(R.id.btnActionBar11);
btnActionBar11.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), ChatActivity.class);
startActivity(intent);
}
});
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(message.getText().length() > 0){
sendMessage();
}
}
});
getConversation();
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// number of visible items
int visibleItemCount = ((LinearLayoutManager)recyclerView.getLayoutManager()).getChildCount();
// number of items in layout
int totalItemCount = ((LinearLayoutManager)recyclerView.getLayoutManager()).getItemCount();
// the position of first visible item
int firstVisibleItemPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
boolean isNotLoadingAndNotLastPage = !mIsLoading && !mIsLastPage;
// flag if number of visible items is at the last
boolean isAtLastItem = firstVisibleItemPosition + visibleItemCount >= totalItemCount;
// validate non negative values
boolean isValidFirstItem = firstVisibleItemPosition >= 0;
// validate total items are more than possible visible items
boolean totalIsMoreThanVisible = totalItemCount >= pageSize;
// flag to know whether to load more
boolean shouldLoadMore = isValidFirstItem && isAtLastItem && totalIsMoreThanVisible && isNotLoadingAndNotLastPage;
if (shouldLoadMore) loadMoreItems(false);
}
});
Intent intent11 = getIntent();
wasSwiped = intent11.getBooleanExtra("wasSwiped",false);
//where you initialize your views:
swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
wasSwiped = true;
//your method to refresh content
Intent intent = new Intent(getApplicationContext(), ConversationsActivity.class)
.putExtra("chatId", chatId)
.putExtra("senderType", senderType)
.putExtra("name",name)
.putExtra("from", to)
.putExtra("from_type", to_type)
.putExtra("wasSwiped", wasSwiped);
startActivity(intent);
}
});
if(wasSwiped){
//don't forget to cancel refresh when work is done
if(swipeLayout.isRefreshing()) {
swipeLayout.setRefreshing(false);
}
}
}
#Override
public void onClickConversation(Conversation.Data conversation) {
}
#Override
public void onBackPressed() {
super.onBackPressed();
Intent intent = new Intent(getApplicationContext(), ChatActivity.class);
startActivity(intent);
}
public void sendMessage(){
Call<Message> call = service.sendMessage(authorization, to, to_type, message.getText().toString());
call.enqueue(new Callback<Message>() {
#Override
public void onResponse(Call<Message> call, Response<Message> response) {
if(response.isSuccessful()){
if(response.body()!= null)
if(response.body().getData() != null);
message.setText("");
getConversation();
//
// adapter.notifyDataSetChanged();
} else {
if(response.body()!= null)
if(response.body().getMessage() != null)
Toast.makeText(getApplicationContext(),"error: " + response.body().getMessage(), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<Message> call, Throwable t) {
Toast.makeText(getApplicationContext(),"error: " + t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
public void getConversation(){
Call<Conversation> call = service.getConversation(authorization,chatId,"LANDLORD");
call.enqueue(new Callback<Conversation>() {
#Override
public void onResponse(Call<Conversation> call, Response<Conversation> response) {
if(conversationArrayList != null)
if(!conversationArrayList.isEmpty())
conversationArrayList.clear();
if(response.isSuccessful()){
if(response.body()!= null)
if(response.body().getData() != null)
if(response.body().getData().size() > 0){
if (!conversationArrayList.isEmpty())
conversationArrayList.clear(); //The list for update recycle view
adapter.notifyDataSetChanged();
for(int i =0; i < response.body().getData().size(); i++){
conversationArrayList.add(response.body().getData().get(i));
if( i == ( response.body().getData().size() -1 ))
lastId = conversationArrayList.get(conversationArrayList.size() - 1).getId();
}
progressBar.setVisibility(View.GONE);
if (conversationArrayList.isEmpty()) {
rv.setVisibility(View.GONE);
no_data.setVisibility(View.VISIBLE);
}
else {
rv.setVisibility(View.VISIBLE);
no_data.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
configureRecyclerView(conversationArrayList);
}
} else {
progressBar.setVisibility(View.GONE);
no_data.setVisibility(View.VISIBLE);
rv.setVisibility(View.GONE);
}
} else {
Toast.makeText(getApplicationContext(),"error: " + response.body().getMessage(), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<Conversation> call, Throwable t) {
Toast.makeText(getApplicationContext(),"error: " + t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
private void configureRecyclerView(ArrayList chat) {
rv = (RecyclerView) findViewById(R.id.ConversationList);
rv.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setReverseLayout(true);
rv.setLayoutManager(linearLayoutManager);
adapter = new ConversationsAdapter(this,context);
adapter.setConversationData(chat);
adapter.notifyDataSetChanged();
rv.setAdapter(adapter);
}
private void loadMoreItems(boolean isFirstPage) {
mIsLoading = true;
f = isFirstPage;
p = p +1;
Call<Conversation> call = service.getConversationPagenation(authorization,chatId,senderType, lastId);
call.enqueue(new Callback<Conversation>() {
#Override
public void onResponse(Call<Conversation> call, Response<Conversation> response) {
if(response.isSuccessful()){
if(response.body() != null)
if(response.body().getData()!= null) {
// conversationArrayList.clear();
for(int i =0; i < response.body().getData().size(); i++){
conversationArrayList.add(response.body().getData().get(i));
if( i == ( response.body().getData().size() -1 ))
lastId = conversationArrayList.get(conversationArrayList.size() - 1).getId();
}
progressBar.setVisibility(View.GONE);
if(conversationArrayList == null){
rv.setVisibility(View.GONE);
no_data.setVisibility(View.VISIBLE);
return;
}
else if (!f) {
if (!conversationArrayList.isEmpty())
adapter.notifyDataSetChanged();
adapter.addAll(conversationArrayList);
// conversationArrayList.clear(); //The list for update recycle view
}
else {
rv.setVisibility(View.VISIBLE);
no_data.setVisibility(View.GONE);
configureRecyclerView(conversationArrayList);
}
if(conversationArrayList.size() > 0)
lastId = conversationArrayList.get(conversationArrayList.size() - 1).getId();
mIsLoading = false;
mIsLastPage = mCurrentPage == lastId;
mCurrentPage = lastId;
}
}
}
#Override
public void onFailure(Call<Conversation> call, Throwable t) {
Log.e("SomeActivity", t.getMessage());
}
});
}
public String checkAuthorization(){
SharedPreferences settings = getSharedPreferences("log",0);
return settings.getString("Authorization", null);
}
}
My Adapter:
public class ConversationsAdapter extends
RecyclerView.Adapter<ConversationsAdapter.ConversationsAdapterViewHolder> {
private Context context;
private ArrayList<Conversation.Data> mConversation;
private ConversationsAdapter.ConversationOnClickHandler mConversationOnClickHandler;
private static SharedPreferences pref;
public ConversationsAdapter(ConversationsAdapter.ConversationOnClickHandler conversationOnClickHandler, Context _context) {
mConversationOnClickHandler = conversationOnClickHandler;
pref = _context.getSharedPreferences("log", Context.MODE_PRIVATE);
}
public void setConversationData(ArrayList<Conversation.Data> conversation) {
mConversation = conversation;
notifyDataSetChanged();
}
public void addAll(ArrayList<Conversation.Data> newList) {
int lastIndex = mConversation.size() - 1;
mConversation.addAll(newList);
notifyItemRangeInserted(lastIndex, newList.size());
}
#Override
public ConversationsAdapter.ConversationsAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View contactView = inflater.inflate(R.layout.row_msg, parent, false);
// Return a new holder instance
ConversationsAdapter.ConversationsAdapterViewHolder viewHolder = new ConversationsAdapter.ConversationsAdapterViewHolder(contactView);
return viewHolder;
}
#Override
public void onBindViewHolder(ConversationsAdapter.ConversationsAdapterViewHolder viewHolder, int position) {
Conversation.Data conversation = mConversation.get(position);
TextView tv1 = viewHolder.tv1;
TextView tv2 = viewHolder.tv2;
// SharedPreferences preferences = context.getSharedPreferences("log", Context.MODE_PRIVATE);
String agentId = pref.getString("agentId", "");
String from_type = conversation.getFromType();
int from = conversation.getFrom();
if((agentId.equals(String.valueOf(from))) && from_type.equals("AGENT")){
tv2.setVisibility(View.GONE);
tv1.setVisibility(View.VISIBLE);
tv1.setText(conversation.getBody());
}
else {
tv2.setVisibility(View.VISIBLE);
tv1.setVisibility(View.GONE);
tv2.setText(conversation.getBody());
}
}
// Returns the total count of items in the list
#Override
public int getItemCount() {
if(mConversation == null) {
return 0;
}
return mConversation.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(hasStableIds);
}
public class ConversationsAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView tv1;
public final TextView tv2;
public ConversationsAdapterViewHolder(View view) {
super(view);
tv1 = (TextView) view.findViewById(R.id.tvMsgR);
tv2 = (TextView) view.findViewById(R.id.tvMsgL);
view.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int position = getAdapterPosition();
Conversation.Data selectedNotifiction = mConversation.get(position);
mConversationOnClickHandler.onClickConversation(selectedNotifiction);
}
}
public interface ConversationOnClickHandler {
void onClickConversation(Conversation.Data conversation);
}
public long myTimeInMillis(String givenDateString ){
// String givenDateString = "Tue Apr 23 16:08:28 GMT+05:30 2013";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long timeInMilliseconds = 0;
try {
Date mDate = sdf.parse(givenDateString);
timeInMilliseconds = mDate.getTime();
// System.out.println("Date in milli :: " + timeInMilliseconds);
} catch (ParseException e) {
e.printStackTrace();
}
return timeInMilliseconds;
}
}
any help or advice?
And thankyou
in your addAll() function on ConversationsAdapter class
int lastIndex = mConversation.size() - 1;
mConversation.clear();
mConversation.addAll(newList);
notifyItemRangeInserted(lastIndex, newList.size());
this should do the trick

RecyclerView messes up when scrolling

I never asked any question before but hope you'll get my point.
I am making a chat app in which I am using a RecyclerView to show messages. The problem is when I scroll the RecyclerView some of the items disappear from the top and the whole items messes up when I try to add a message it doesn't even scroll to bottom nor added in the ListView.
Here is my RecyclerView:
<android.support.v7.widget.RecyclerView
android:id="#+id/conversation_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:layout_above="#id/typingConversationLayout"
android:layout_below="#id/topLayout_conversation_activity"
android:layout_marginBottom="-5dp"
android:paddingBottom="7dp" />
Initializing and setting the RecycerView:
linearLayoutManager = new LinearLayoutManager(this);
adapter = new ConversationRecyclerViewAdapter();
conversationRecyclerView.setAdapter(adapter);
conversationRecyclerView.setLayoutManager(linearLayoutManager);
linearLayoutManager.setStackFromEnd(true);
conversationRecyclerView.setHasFixedSize(true);
conversationRecyclerView.setNestedScrollingEnabled(false);
Here is my Adapter class:
private class ConversationRecyclerViewAdapter
extends RecyclerView.Adapter<ConversationRecyclerViewAdapter.ConversationViewHolder> {
#NonNull
#Override
public ConversationViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
Log.d(TAG, "onCreateViewHolder: Users Find started");
View conversationsView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.layout_message_received, parent, false);
return new ConversationViewHolder(conversationsView);
}
#Override
public void onBindViewHolder(#NonNull final ConversationViewHolder holderConversation, int i) {
Log.d(TAG, "onBindViewHolder: Users Find started at position is " + i);
final int position = holderConversation.getAdapterPosition();
if (mOwnUser_1.get(position)) {
holderConversation.receivedMsgLayout.setVisibility(View.GONE);
holderConversation.sentProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.sentMsg.setText(mUserText_3.get(position));
} else {
holderConversation.sentMsgLayout.setVisibility(View.GONE);
holderConversation.receivedProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.receivedMsg.setText(mUserText_3.get(position));
}
Log.d(TAG, "onBindViewHolder: completed at " + position);
}
#Override
public int getItemCount() {
return mOwnUser_1.size();
}
public class ConversationViewHolder extends RecyclerView.ViewHolder {
RelativeLayout receivedMsgLayout, sentMsgLayout;
EmojiTextView receivedMsg, sentMsg;
CircleImageView receivedProfileImg, sentProfileImg;
public ConversationViewHolder(#NonNull View v) {
super(v);
receivedMsgLayout = v.findViewById(R.id.received_message_layout);
sentMsgLayout = v.findViewById(R.id.sent_message_layout);
receivedMsg = v.findViewById(R.id.received_message_text);
sentMsg = v.findViewById(R.id.sent_message_text);
receivedProfileImg = v.findViewById(R.id.received_message_user__profile_image);
sentProfileImg = v.findViewById(R.id.sent_message_user__profile_image);
}
}
}
Here I am adding data to ListView and displaying to the RecyclerView:
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String msg = editText.getText().toString().trim();
if (TextUtils.isEmpty(msg)) {
editText.setError("Please add a message");
editText.requestFocus();
} else {
Log.d(TAG, "onClick: send Btn ADDED TEXT.. ");
mOwnUser_1.add(user);
mUserProfileImg_2.add(image);
mUserText_3.add(message);
editText.setText("");
editText.requestFocus();
adapter.notifyItemInserted(mOwnUser_1.size());
conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);
}
}
});
I don't know what i am doing wrong but it does not seem to work as i wanted.
Update Code:
The three listviews:
private ArrayList<Boolean> mOwnUser_1 = new ArrayList<>();
private ArrayList<Integer> mUserProfileImg_2 = new ArrayList<>();
private ArrayList<String> mUserText_3 = new ArrayList<>();
And the way of adding data to adapter:
mOwnUser_1.add(true);
mUserProfileImg_2.add(R.drawable.boy);
mUserText_3.add(edittext.getText().toString().trim());
adapter.notifyItemInserted(mOwnUser_1.size());
conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);
My Whole Conversation Activity Class:
public class ConversationActivity extends AppCompatActivity {
private static final String TAG = "ConversationActivity";
private EditText editText;
private LinearLayout linearLayout;
private LinearLayoutManager linearLayoutManager;
private ImageView sendBtn;
private ImageView emojiImage;
private View rootView;
private Boolean popUpShown = false;
private Boolean micShown = false;
private ImageView micBtn;
private RelativeLayout micLayout;
private RecyclerView conversationRecyclerView;
// Array Lists for Find USERS
private ArrayList<Boolean> mOwnUser_1 = new ArrayList<>();
private ArrayList<Integer> mUserProfileImg_2 = new ArrayList<>();
private ArrayList<String> mUserText_3 = new ArrayList<>();
private ConversationRecyclerViewAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate: started");
super.onCreate(savedInstanceState);
EmojiManager.install(new TwitterEmojiProvider());
setContentView(R.layout.activity_conversation);
editText = findViewById(R.id.conversationEditText);
linearLayout = findViewById(R.id.optionsOther);
emojiImage = findViewById(R.id.emojiIconOther);
rootView = findViewById(R.id.root_view_conversation);
micBtn = findViewById(R.id.microphoneBtn);
micLayout = findViewById(R.id.microphoneLayout);
conversationRecyclerView = findViewById(R.id.conversation_recyclerView);
sendBtn = findViewById(R.id.sendBtnConversation);
if (!(Build.VERSION.SDK_INT >= 21))
findViewById(R.id.typingConversationLayout).setBackgroundResource(R.drawable.edit_text_conversation_background_below_api);
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String msg = editText.getText().toString().trim();
if (TextUtils.isEmpty(msg)) {
editText.setError("Please add a message");
editText.requestFocus();
} else {
Log.d(TAG, "onClick: send Btn ADDED TEXT.. ");
addData(true, R.drawable.boy0, msg);
}
}
});
initConversationArrayList();
}
private void addData(Boolean user, int image, String message) {
mOwnUser_1.add(user);
mUserProfileImg_2.add(image);
mUserText_3.add(message);
editText.setText("");
editText.requestFocus();
adapter.notifyItemInserted(mOwnUser_1.size());
conversationRecyclerView.scrollToPosition(mOwnUser_1.size() - 1);
}
private void initConversationArrayList() {
Log.d(TAG, "initConversationArrayList: created");
mOwnUser_1.add(true);
mUserProfileImg_2.add(R.drawable.boy0);
mUserText_3.add("Hello How are you?");
Log.d(TAG, "initConversationArrayList: completed");
initConversationRecyclerView();
}
private void initConversationRecyclerView() {
Log.d(TAG, "initConversationRecyclerView: started");
linearLayoutManager = new LinearLayoutManager(this);
adapter = new ConversationRecyclerViewAdapter();
conversationRecyclerView.setAdapter(adapter);
conversationRecyclerView.setLayoutManager(linearLayoutManager);
linearLayoutManager.setStackFromEnd(true);
conversationRecyclerView.setHasFixedSize(true);
conversationRecyclerView.setNestedScrollingEnabled(false);
Log.d(TAG, "initConversationRecyclerView: completed");
}
Currently I am also working on chat module, let me show you how am I doing this. I am going to show you in steps.
Step 1: make two separate layout for recyclerview items, one for message that has been sent from your side and one for message received from another side.
Step 2 : make two view holders to populate different layout according to your scenario, made in above step, like this:
public class ChatNewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Chat> chats;
public ChatNewAdapter(List<Chat> chats) {
this.chats = chats;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == 0) {
View viewSend = (View) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_send, parent, false);
return new ViewHolderSend(viewSend);
} else {
View viewReceive = (View) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_received, parent, false);
return new ViewHolderReceive(viewReceive);
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case 0:
ViewHolderSend viewHolderSend = (ViewHolderSend) holder;
viewHolderSend.messageSend.setText(chats.get(position).getMessage());
break;
case 1:
ViewHolderReceive viewHolderReceive = (ViewHolderReceive) holder;
viewHolderReceive.messageReceived.setText(chats.get(position).getMessage());
break;
}
}
#Override
public int getItemCount() {
return chats.size();
}
#Override
public int getItemViewType(int position) {
if (chats != null && !chats.get(position).fromAdmin) {
return 0;
} else
return 1;
}
class ViewHolderSend extends RecyclerView.ViewHolder {
TextView messageSend;
public ViewHolderSend(View itemView) {
super(itemView);
messageSend = (TextView) itemView.findViewById(R.id.messageSend);
}
}
class ViewHolderReceive extends RecyclerView.ViewHolder {
TextView messageReceived;
public ViewHolderReceive(View itemView) {
super(itemView);
messageReceived = (TextView) itemView.findViewById(R.id.messageReceived);
}
}
public int addMessages(Chat chat) {
chats.add(chat);
notifyDataSetChanged();
return chats.size();
}
Step 3 : now in your activity:
public class Test extends AppCompatActivity {
RecyclerView chatList;
RecyclerView.LayoutManager mLayoutManager;
ChatNewAdapter adapter;
ImageView sendButton;
EditText messageEditText;
boolean keyboardUp = false;
boolean isRunning = false;
ArrayList<Chat> chats;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
isRunning = true;
setUpComponents();
}
public void setUpComponents() {
chatList = (RecyclerView) findViewById(R.id.chat_list);
chatList.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
chatList.setLayoutManager(mLayoutManager);
messageEditText = (EditText) findViewById(R.id.messageText);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
sendButton = (ImageView) findViewById(R.id.send);
adapter = new ChatNewAdapter(chats);
chatList.setAdapter(adapter);
chatList.scrollToPosition(chatList.getAdapter().getItemCount() - 1);
messageEditText.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (keyboardShown(messageEditText.getRootView())) {
Log.d("keyboard", "keyboard UP");
if (keyboardUp == false) {
if (chats.size() > 0)
chatList.smoothScrollToPosition(chats.size() + 1);
keyboardUp = true;
}
} else {
Log.d("keyboard", "keyboard Down");
keyboardUp = false;
}
}
});
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final String message = messageEditText.getText().toString().trim();
if (!message.equals("")) {
Chat chat = new Chat();
String name = message;
chat.setMessage(name);
messageEditText.setText("");
adapter.addMessages(chat);
chatList.scrollToPosition(chatList.getAdapter().getItemCount() - 1);
} else {
Log.d("sending message Error", "error fetching dates");
}
}
});
}
private boolean keyboardShown(View rootView) {
final int softKeyboardHeight = 100;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
int heightDiff = rootView.getBottom() - r.bottom;
return heightDiff > softKeyboardHeight * dm.density;
}
And this is my model class, ignore #PrimaryKey and #Required annotation it just because I am using Realm for local DB. In your case you wont required these annotation.
public class Chat extends RealmObject {
#PrimaryKey
#Required
public Long id;
public boolean fromAdmin;
#Required
public String message;
public int type;
public boolean isRead;
public boolean isSent;
public Date date;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isFromAdmin() {
return fromAdmin;
}
public void setFromAdmin(boolean fromAdmin) {
this.fromAdmin = fromAdmin;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public boolean isRead() {
return isRead;
}
public void setRead(boolean read) {
isRead = read;
}
public boolean isSent() {
return isSent;
}
public void setSent(boolean sent) {
isSent = sent;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
I hope it will be helpful for you, you can ask further if you want to know anything else related to code.
RecyclerView as the name stands recycles the views. When binding data to a view, you need to ensure you set or reset all views that are touched in the adapter. Messups typically occur when there's data that is set only conditionally for some but not all items.
In particular:
if (mOwnUser_1.get(position)) {
holderConversation.receivedMsgLayout.setVisibility(View.GONE);
holderConversation.sentProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.sentMsg.setText(mUserText_3.get(position));
} else {
holderConversation.sentMsgLayout.setVisibility(View.GONE);
holderConversation.receivedProfileImg.setImageResource(mUserProfileImg_2.get(position));
holderConversation.receivedMsg.setText(mUserText_3.get(position));
}
Both of these branches will need to reset the other layout back to visible.
Anyway with this kind of two-layout approach you are likely better off by having them as separate view types in your adapter. See How to create RecyclerView with multiple view type?

changing items in recyclerview adapter

I inserted/removing from particular position in ArrayList onBindViewHolder . Now , i want to show this modified list on recyclerview .
Adapter Code:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyAdapterViewHolder> {
private List<Info> dataList;
private Context mAct;
private List<Info> totalCandidatesList;
private String TAG = "OWD";
public MyAdapter(List<Info> dataList, Context context) {
this.dataList = dataList;
this.mAct = context;
}
public void addApplications(List<Info> candidates) {
if(this.totalCandidatesList == null){
totalCandidatesList = new ArrayList<>();
}
this.dataList.addAll(candidates);
this.totalCandidatesList.addAll(candidates);
this.notifyItemRangeInserted(0, candidates.size() - 1);
}
public void clearApplications() {
int size = this.dataList.size();
if (size > 0) {
for (int i = 0; i < size; i++) {
dataList.remove(0);
totalCandidatesList.remove(0);
}
this.notifyItemRangeRemoved(0, size);
}
}
#Override
public int getItemCount() {
return dataList.size();
}
public void onBindViewHolder(MyAdapterViewHolder mAdapterViewHolder, int i) {
if (i % 2 == 1) {
mAdapterViewHolder.cardView.setCardBackgroundColor(Color.parseColor("#ecf5fe"));
mAdapterViewHolder.layoutRipple.setBackgroundColor(Color.parseColor("#ecf5fe"));
} else {
mAdapterViewHolder.cardView.setCardBackgroundColor(Color.parseColor("#e2f1ff"));
mAdapterViewHolder.layoutRipple.setBackgroundColor(Color.parseColor("#e2f1ff"));
}
final WorkHolders workHolders = SingleTon.getInstance().getWorkHolders();
final String customerName = SingleTon.getInstance().getCustomerName();
String siteName = null;
if(customerName !=null) {
String[] sitenamearray = customerName.split("--");
if (sitenamearray.length > 1) {
siteName = sitenamearray[1];
}
}
final Info ci = dataList.get(i);
mAdapterViewHolder.title.setText(ci.heading1);
mAdapterViewHolder.jobNumber.setText(ci.heading2);
mAdapterViewHolder.distance.setText(ci.distance);
if(siteName != null && siteName.equalsIgnoreCase(ci.heading2)) {
mAdapterViewHolder.cardView.setCardBackgroundColor(Color.parseColor("#a7ffeb"));
mAdapterViewHolder.layoutRipple.setBackgroundColor(Color.parseColor("#a7ffeb"));
if(i!=0){
> //Here i removed and inserted item in list .
> dataList.remove(i);
> dataList.add(0,ci);
}
}
final String finalSiteName = siteName;
final Bundle bundle = new Bundle();
mAdapterViewHolder.layoutRipple.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment;
String name = ci.heading1 + "--" + ci.heading2;
Log.d(TAG,"new Jobname : "+ name);
if (finalSiteName == null || finalSiteName.equalsIgnoreCase("")) {
bundle.putString("name", customerName);
bundle.putString("oldwork", "yes");
bundle.putString("running_job_selected", "yes");
} else {
Log.d(TAG,"StartedOn Before Sending Bundle :" + workHolders.startedOn);
Log.d(TAG, "running Job is not selected");
bundle.putString("name", name);
bundle.putString("oldwork", "yes");
bundle.putString("running_job_selected", "no");
}
FragmentTransaction ft = ((FragmentActivity) mAct).getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.glide_fragment_horizontal_in, R.anim.glide_fragment_horizontal_out);
fragment = new WorkDescriptionFragment();
fragment.setArguments(bundle);
ft.addToBackStack("myadapter");
ft.replace(R.id.content_frame, fragment).commit();
SingleTon.getInstance().setWorkStatus("start");
}
});
}
#Override
public MyAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.single_item1, viewGroup, false);
return new MyAdapterViewHolder(itemView);
}
public static class MyAdapterViewHolder extends RecyclerView.ViewHolder {
protected TextView title;
protected TextView dateTime;
protected TextView distance;
protected TextView jobNumber;
protected CardView cardView;
protected LayoutRipple layoutRipple;
public MyAdapterViewHolder(View v) {
super(v);
title = (TextView) v.findViewById(R.id.title);
dateTime = (TextView) v.findViewById(R.id.dateTimeTextView);
distance = (TextView) v.findViewById(R.id.distanceTextView);
jobNumber = (TextView) v.findViewById(R.id.jobNumber);
cardView = (CardView) v.findViewById(R.id.cv);
layoutRipple = (LayoutRipple)v.findViewById(R.id.singleitemripple);
}
}
}
you will see following lines in above code where i am removing/inserting item in a list onBindview and would like to show same in recyclerview .
But right now i am getting normal datalist(unchanged) .
//Here i removed and inserted item in list .
dataList.remove(i);
dataList.add(0,ci);
Please help me to achieve this .
onBindViewHolder is not the place where you should update your adapter. The staregy is to update item inside your Adapter data list and then notifyDataChanged(). For example thise are the methods for updating info inside my adapter:
public void update(Track track) {
tracks.remove(track);
add(track);
}
public void add (Track track) {
tracks.add(track);
this.notifyDataSetChanged();
}
public void addTracks(List<Track> tracks){
this.tracks.addAll(tracks);
this.notifyDataSetChanged();
}
public void clearAndAddTracks(List<Track> tracks) {
for (int i = 0; i < this.tracks.size(); i++) {
if (!this.tracks.get(i).isRunning()){
}
}
this.tracks.clear();
this.tracks.addAll(tracks);
this.notifyDataSetChanged();
}

list only updates when I scroll - android listview

I'm trying to build a chat app that uses a listview to display messages. I'm using SignalR for realtime communication. The issue I'm having is, the listview adapter only updates the list on the receivers end when I scroll but on the senders end, the message shows immediately.
Here's the activity for that chat:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
ISharedPreferences pref = Application.Context.GetSharedPreferences("UserInfo", FileCreationMode.Private);
loggeduser = pref.GetString("Username", String.Empty);
SetContentView(Resource.Layout.chat_activity);
initControls();
}
private async void initControls()
{
SignalRClientHelper proxySubscriber = SignalRClientHelper.GetInstance();
await proxySubscriber.StartConnection();
proxySubscriber.OnMessageReceived += proxySubscriber_OnMessageReceived;
messagesContainer = FindViewById<ListView>(Resource.Id.messagesContainer);
messageET = FindViewById<EditText>(Resource.Id.messageEdit);
sendBtn = FindViewById<Button>(Resource.Id.chatSendButton);
adapter = new ChatAdapter(this, new List<ChatMessage>(), loggeduser);
messagesContainer.Adapter = adapter;
//loadDummyHistory();
sendBtn.Click += (o, e) =>
{
string messageText = messageET.Text.ToString();
if (TextUtils.IsEmpty(messageText))
{
return;
}
proxySubscriber.InvokeSendMessage("psyoptica", messageText);
ChatMessage chatMessage = new ChatMessage();
chatMessage.Message = messageText;
chatMessage.Username = loggeduser;
messageET.Text = "";
displayMessage(chatMessage);
};
RelativeLayout container = FindViewById<RelativeLayout>(Resource.Id.container);
}
void proxySubscriber_OnMessageReceived(string username, string message)
{
ChatMessage chatMessage = new ChatMessage { Username = username, Message = message };
displayMessage(chatMessage);
}
public void displayMessage(ChatMessage message)
{
adapter.add(message);
adapter.NotifyDataSetChanged();
scroll();
}
private void scroll()
{
messagesContainer.SetSelection(messagesContainer.Count - 1);
}
}
and here's the code for the listview adapter:
class ChatAdapter : BaseAdapter
{
private List<ChatMessage> messages;
private Activity context;
private string loggedUsername;
public ChatAdapter(Activity context, List<ChatMessage> messages, string loggedUsername)
{
this.messages = messages;
this.context = context;
this.loggedUsername = loggedUsername;
}
public override int Count
{
get { return messages.Count; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view;
ViewHolder holder;
if (convertView == null)
{
view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.chatMessage, parent, false);
holder = createViewHolder(view);
}
else
{
view = convertView;
holder = createViewHolder(view);
}
bool isMe = messages[position].Username == loggedUsername;
setAlignment(holder, isMe);
holder.txtMessage.Text = messages[position].Message;
return view;
}
private void setAlignment(ViewHolder holder, bool isMe)
{
if (!isMe)
{
holder.contentWithBG.SetBackgroundResource(Resource.Drawable.in_message_bg);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)holder.contentWithBG.LayoutParameters;
layoutParams.Gravity = GravityFlags.Right;
holder.contentWithBG.LayoutParameters = layoutParams;
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)holder.content.LayoutParameters;
lp.AddRule(LayoutRules.AlignParentLeft, 0);
lp.AddRule(LayoutRules.AlignParentRight);
holder.content.LayoutParameters = lp;
layoutParams = (LinearLayout.LayoutParams)holder.txtMessage.LayoutParameters;
layoutParams.Gravity = GravityFlags.Right;
holder.txtMessage.LayoutParameters = layoutParams;
}
else
{
holder.contentWithBG.SetBackgroundResource(Resource.Drawable.out_message_bg);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)holder.contentWithBG.LayoutParameters;
layoutParams.Gravity = GravityFlags.Left;
holder.contentWithBG.LayoutParameters = layoutParams;
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)holder.content.LayoutParameters;
lp.AddRule(LayoutRules.AlignParentRight, 0);
lp.AddRule(LayoutRules.AlignParentLeft);
holder.content.LayoutParameters = lp;
layoutParams = (LinearLayout.LayoutParams)holder.txtMessage.LayoutParameters;
layoutParams.Gravity = GravityFlags.Left;
holder.txtMessage.LayoutParameters = layoutParams;
}
}
public void add(ChatMessage message)
{
messages.Add(message);
}
public void add(List<ChatMessage> chatMessages)
{
messages.AddRange(chatMessages);
}
private ViewHolder createViewHolder(View v)
{
ViewHolder holder = new ViewHolder();
holder.txtMessage = v.FindViewById<TextView>(Resource.Id.txtMessage);
holder.content = v.FindViewById<LinearLayout>(Resource.Id.content);
holder.contentWithBG = v.FindViewById<LinearLayout>(Resource.Id.contentWithBackground);
holder.txtInfo = v.FindViewById<TextView>(Resource.Id.txtInfo);
return holder;
}
private class ViewHolder
{
public TextView txtMessage { get; set; }
public TextView txtInfo { get; set; }
public LinearLayout content { get; set; }
public LinearLayout contentWithBG { get; set; }
}
}
The method displayMessage() is called each time there's a new message added to the list. I don't understand why I have to scroll for the change to show on the receivers end. Can anyone point out the error in my code?
Try with scrollToPosition() instead of setSelection() and in the add() method in the adapter notifyDataSetChanged();
On your class ChatAdapter:
public void add(ChatMessage message)
{
messages.Add(message);
NotifyDataSetChanged();
}
public void add(List<ChatMessage> chatMessages)
{
messages.AddRange(chatMessages);
NotifyDataSetChanged();
}
Try running the process inside the proxySubscriber_OnMessageReceived():
void proxySubscriber_OnMessageReceived(string username, string message)
{
runOnUiThread(new Runnable() {
#Override
public void run() {
ChatMessage chatMessage = new ChatMessage { Username = username, Message = message };
displayMessage(chatMessage);
}
});
}

Categories

Resources