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);
}
});
}
Related
Add some fragment continuously then RecyclerView scroll lagging
I am remove image load library but not any improvement i am face same
problem.
I am also check this link click
add fragment then facing this problem. but replace fragment then not facing this problem
more add fragment then RecyclerView lagging. i think fragment memory issue
add more then three fragment continuously then face this problem
fragment xml
<FrameLayout
android:id="#+id/frameLayout_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar_main"
android:layout_above="#+id/linearLayout_adView_main" />
call fragment data
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RelatedFragment relatedFragment = new RelatedFragment();
Bundle bundle = new Bundle();
bundle.putString("type", "related");
bundle.putString("post_id", statusLists.getId());
bundle.putString("cat_id", statusLists.getCid());
bundle.putString("typeLayout", "Landscape");
relatedFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.frameLayout_main, relatedFragment, string).addToBackStack(string).commitAllowingStateLoss();
}
});
xml file
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView_sub_category"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp" />
Fragment
public class RelatedFragment extends Fragment {
private Method method;
private OnClick onClick;
private String type, post_id, cat_id, typeLayout;
private ProgressBar progressBar;
private MaterialTextView textView_noData;
private RecyclerView recyclerView;
private List<SubCategoryList> relatedLists;
private SubCategoryAdapter subCategoryAdapter;
private LayoutAnimationController animation;
private Boolean isOver = false;
private int pagination_index = 1;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.portrait_fragment, container, false);
GlobalBus.getBus().register(this);
MainActivity.toolbar.setTitle(getResources().getString(R.string.related_status));
relatedLists = new ArrayList<>();
onClick = new OnClick() {
#Override
public void position(int position, String title, String type, String status_type, String id, String tag) {
SCDetailFragment scDetailFragment = new SCDetailFragment();
Bundle bundle = new Bundle();
bundle.putString("id", id);
bundle.putString("type", type);
bundle.putString("status_type", status_type);
bundle.putInt("position", position);
scDetailFragment.setArguments(bundle);
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.frameLayout_main, scDetailFragment, title).addToBackStack(title).commitAllowingStateLoss();
}
};
method = new Method(getActivity(), onClick);
assert getArguments() != null;
type = getArguments().getString("type");
post_id = getArguments().getString("post_id");
cat_id = getArguments().getString("cat_id");
typeLayout = getArguments().getString("typeLayout");
int resId = R.anim.layout_animation_fall_down;
animation = AnimationUtils.loadLayoutAnimation(getActivity(), resId);
progressBar = view.findViewById(R.id.progressbar_portrait_fragment);
textView_noData = view.findViewById(R.id.textView_portrait_fragment);
recyclerView = view.findViewById(R.id.recyclerView_portrait_fragment);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.addOnScrollListener(new EndlessRecyclerViewScrollListener(layoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount) {
if (!isOver) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
pagination_index++;
callData();
}
}, 1000);
} else {
subCategoryAdapter.hideHeader();
}
}
});
callData();
setHasOptionsMenu(true);
return view;
}
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.search_menu, menu);
MenuItem searchItem = menu.findItem(R.id.ic_searchView);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
searchView.setOnQueryTextListener((new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
if (method.isNetworkAvailable()) {
backStackRemove();
SearchFragment searchFragment = new SearchFragment();
Bundle bundle = new Bundle();
bundle.putString("search_menu", query);
bundle.putString("typeLayout", "Landscape");
searchFragment.setArguments(bundle);
getActivity().getSupportFragmentManager()
.beginTransaction().replace(R.id.frameLayout_main, searchFragment, query).commitAllowingStateLoss();
return false;
} else {
method.alertBox(getResources().getString(R.string.internet_connection));
}
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
return true;
}
}));
super.onCreateOptionsMenu(menu, inflater);
}
private void backStackRemove() {
for (int i = 0; i < getActivity().getSupportFragmentManager().getBackStackEntryCount(); i++) {
getActivity().getSupportFragmentManager().popBackStack();
}
}
#Subscribe
public void getNotify(Events.FavouriteNotify favouriteNotify) {
for (int i = 0; i < relatedLists.size(); i++) {
if (relatedLists.get(i).getId().equals(favouriteNotify.getId())) {
if (relatedLists.get(i).getStatus_type().equals(favouriteNotify.getStatus_type())) {
relatedLists.get(i).setIs_favourite(favouriteNotify.getIs_favourite());
subCategoryAdapter.notifyItemChanged(i);
}
}
}
}
#Subscribe
public void getMessage(Events.InfoUpdate infoUpdate) {
if (subCategoryAdapter != null) {
for (int i = 0; i < relatedLists.size(); i++) {
if (relatedLists.get(i).getId().equals(infoUpdate.getId())) {
if (relatedLists.get(i).getStatus_type().equals(infoUpdate.getStatus_type())) {
switch (infoUpdate.getType()) {
case "all":
relatedLists.get(i).setTotal_viewer(infoUpdate.getView());
relatedLists.get(i).setTotal_likes(infoUpdate.getTotal_like());
relatedLists.get(i).setAlready_like(infoUpdate.getAlready_like());
break;
case "view":
relatedLists.get(i).setTotal_viewer(infoUpdate.getView());
break;
case "like":
relatedLists.get(i).setTotal_likes(infoUpdate.getTotal_like());
relatedLists.get(i).setAlready_like(infoUpdate.getAlready_like());
break;
}
subCategoryAdapter.notifyItemChanged(i);
}
}
}
}
}
private void callData() {
if (getActivity() != null) {
if (method.isNetworkAvailable()) {
if (method.pref.getBoolean(method.pref_login, false)) {
related(method.pref.getString(method.profileId, null), post_id, cat_id, typeLayout);
} else {
related("0", post_id, cat_id, typeLayout);
}
} else {
method.alertBox(getResources().getString(R.string.internet_connection));
}
}
}
private void related(String userId, String post_id, String cat_id, String typeLayout) {
if (subCategoryAdapter == null) {
relatedLists.clear();
progressBar.setVisibility(View.VISIBLE);
}
if (getActivity() != null) {
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
JsonObject jsObj = (JsonObject) new Gson().toJsonTree(new API(getActivity()));
jsObj.addProperty("method_name", "related_status");
jsObj.addProperty("post_id", post_id);
jsObj.addProperty("cat_id", cat_id);
jsObj.addProperty("user_id", userId);
jsObj.addProperty("page", pagination_index);
jsObj.addProperty("filter_value", typeLayout);
jsObj.addProperty("lang_ids", method.pref.getString(method.language_ids, ""));
params.put("data", API.toBase64(jsObj.toString()));
client.post(Constant_Api.url, params, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
if (getActivity() != null) {
String res = new String(responseBody);
try {
JSONObject jsonObject = new JSONObject(res);
if (jsonObject.has(Constant_Api.STATUS)) {
String status = jsonObject.getString("status");
String message = jsonObject.getString("message");
if (status.equals("-2")) {
method.suspend(message);
} else {
method.alertBox(message);
}
} else {
JSONArray jsonArray = jsonObject.getJSONArray(Constant_Api.tag);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
String id = object.getString("id");
String status_type = object.getString("status_type");
String status_title = object.getString("status_title");
String status_layout = object.getString("status_layout");
String status_thumbnail_b = object.getString("status_thumbnail_b");
String status_thumbnail_s = object.getString("status_thumbnail_s");
String total_likes = object.getString("total_likes");
String total_viewer = object.getString("total_viewer");
String category_name = object.getString("category_name");
String already_like = object.getString("already_like");
String quote_bg = object.getString("quote_bg");
String quote_font = object.getString("quote_font");
String is_favourite = object.getString("is_favourite");
relatedLists.add(new SubCategoryList("", id, status_type, status_title, status_layout, status_thumbnail_b, status_thumbnail_s, total_viewer, total_likes, already_like, category_name, quote_bg, quote_font, is_favourite, "", ""));
}
if (jsonArray.length() == 0) {
if (subCategoryAdapter != null) {
isOver = true;
subCategoryAdapter.hideHeader();
}
}
if (subCategoryAdapter == null) {
if (relatedLists.size() == 0) {
textView_noData.setVisibility(View.VISIBLE);
} else {
textView_noData.setVisibility(View.GONE);
subCategoryAdapter = new SubCategoryAdapter(getActivity(), relatedLists, onClick, type);
recyclerView.setAdapter(subCategoryAdapter);
recyclerView.setLayoutAnimation(animation);
}
} else {
subCategoryAdapter.notifyDataSetChanged();
}
}
} catch (JSONException e) {
e.printStackTrace();
method.alertBox(getResources().getString(R.string.failed_try_again));
}
}
progressBar.setVisibility(View.GONE);
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
progressBar.setVisibility(View.GONE);
method.alertBox(getResources().getString(R.string.failed_try_again));
}
});
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
// Unregister the registered event.
GlobalBus.getBus().unregister(this);
}
}
Adapter
public class SubCategoryAdapter extends RecyclerView.Adapter {
private Activity activity;
private Method method;
private int columnWidth;
private String type;
private Animation myAnim;
private List<SubCategoryList> subCategoryLists;
private final int VIEW_TYPE_LOADING = 0;
private final int VIEW_TYPE_ITEM = 1;
private final int VIEW_TYPE_QUOTES = 2;
public SubCategoryAdapter(Activity activity, List<SubCategoryList> subCategoryLists, OnClick interstitialAdView, String type) {
this.activity = activity;
this.type = type;
this.subCategoryLists = subCategoryLists;
method = new Method(activity, interstitialAdView);
columnWidth = (method.getScreenWidth());
myAnim = AnimationUtils.loadAnimation(activity, R.anim.bounce);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(activity).inflate(R.layout.sub_category_adapter, parent, false);
return new ViewHolder(view);
} else if (viewType == VIEW_TYPE_QUOTES) {
View v = LayoutInflater.from(activity).inflate(R.layout.quotes_adapter, parent, false);
return new Quotes(v);
} else if (viewType == VIEW_TYPE_LOADING) {
View v = LayoutInflater.from(activity).inflate(R.layout.layout_loading_item, parent, false);
return new ProgressViewHolder(v);
}
return null;
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, #SuppressLint("RecyclerView") final int position) {
if (holder.getItemViewType() == VIEW_TYPE_ITEM) {
final ViewHolder viewHolder = (ViewHolder) holder;
if (status_type.equals("gif")) {
Glide.with(activity)
.asBitmap()
.load(subCategoryLists.get(position).getStatus_thumbnail_s())
.placeholder(R.drawable.placeholder_landscape).into(viewHolder.imageView);
} else {
Glide.with(activity)
.load(subCategoryLists.get(position).getStatus_thumbnail_s())
.placeholder(R.drawable.placeholder_landscape).into(viewHolder.imageView);
}
viewHolder.imageView.setLayoutParams(new RelativeLayout.LayoutParams(columnWidth, columnWidth / 2 - 60));
viewHolder.textView_title.setText(subCategoryLists.get(position).getStatus_title());
viewHolder.relativeLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
method.onClickData(position, subCategoryLists.get(position).getStatus_title(), type, subCategoryLists.get(position).getStatus_type(), subCategoryLists.get(position).getId(), "");
}
});
} else if (holder.getItemViewType() == VIEW_TYPE_QUOTES) {
final Quotes quotes = (Quotes) holder;
quotes.relativeLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, columnWidth / 2));
Typeface typeface = Typeface.createFromAsset(activity.getAssets(), "text_font/" + subCategoryLists.get(position).getQuote_font());
quotes.textView.setTypeface(typeface);
quotes.textView.setText(subCategoryLists.get(position).getStatus_title());
quotes.textView.post(new Runnable() {
#Override
public void run() {
ViewGroup.LayoutParams params = quotes.textView.getLayoutParams();
if (params == null) {
params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
final int widthSpec = View.MeasureSpec.makeMeasureSpec(quotes.textView.getWidth(), View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(quotes.textView.getHeight(), View.MeasureSpec.UNSPECIFIED);
quotes.textView.measure(widthSpec, heightSpec);
quotes.textView.setMaxLines(heightSpec / quotes.textView.getLineHeight());
quotes.textView.setEllipsize(TextUtils.TruncateAt.END);
}
});
quotes.linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
method.onClickData(position, subCategoryLists.get(position).getStatus_title(), type, subCategoryLists.get(position).getStatus_type(), subCategoryLists.get(position).getId(), "");
}
});
}
}
#Override
public int getItemCount() {
return subCategoryLists.size() + 1;
}
public void hideHeader() {
ProgressViewHolder.progressBar.setVisibility(View.GONE);
}
#Override
public int getItemViewType(int position) {
if (position != subCategoryLists.size()) {
if (subCategoryLists.get(position).getStatus_type().equals("quote")) {
return VIEW_TYPE_QUOTES;
} else {
return VIEW_TYPE_ITEM;
}
} else {
return VIEW_TYPE_LOADING;
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
private RelativeLayout relativeLayout;
private ImageView imageView;
private MaterialTextView textView_title;
public ViewHolder(View itemView) {
super(itemView);
relativeLayout = itemView.findViewById(R.id.relativeLayout_subCat_adapter);
imageView = itemView.findViewById(R.id.imageView_subCat_adapter);
textView_title = itemView.findViewById(R.id.textView_title_subCat_adapter);
}
}
public class Quotes extends RecyclerView.ViewHolder {
private LinearLayout linearLayout;
private RelativeLayout relativeLayout;
private MaterialTextView textView;
public Quotes(#NonNull View itemView) {
super(itemView);
linearLayout = itemView.findViewById(R.id.ll_quotes_adapter);
textView = itemView.findViewById(R.id.textView_quotes_adapter);
relativeLayout = itemView.findViewById(R.id.rel_quotes_adapter);
}
}
public static class ProgressViewHolder extends RecyclerView.ViewHolder {
public static ProgressBar progressBar;
public ProgressViewHolder(View v) {
super(v);
progressBar = v.findViewById(R.id.progressBar);
}
} }
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.
I have a model class:
public class Home_Model_ViewPager {
public String buttonLink;
public String tipsDescription;
public String tipsButton;
public Context context;
public Home_Model_ViewPager( Context context, String tipsDescription, String tipsButton, String buttonLink) {
this.context = context;
this.tipsDescription = tipsDescription;
this.tipsButton = tipsButton;
this.buttonLink = buttonLink;
}
public String getButtonLink() {
return buttonLink;
}
public void setButtonLink(String buttonLink) {
this.buttonLink = buttonLink;
}
public String getTipsDescription() {
return tipsDescription;
}
public void setTipsDescription(String tipsDescription) {
this.tipsDescription = tipsDescription;
}
public String getTipsButton() {
return tipsButton;
}
public void setTipsButton(String tipsButton) {
this.tipsButton = tipsButton;
}
}
I have used this model class to use it in viewpager adapter.
So, I am using a recyclerview and setting data to it. Now I have a problem that I have a viewpager in recycleritem. I want to return the size of viewpager adapter of any element in Home_Model_ViewPager as each element has diff size.
This is what I tried in ViewPagerAdapter:
public class ViewPagerAdapter extends PagerAdapter {
// Declare Variables
Context context;
LayoutInflater inflater;
List<Home_Model_ViewPager> totalList;
public ViewPagerAdapter(Context context, List<Home_Model_ViewPager> totalList) {
this.context = context;
this.totalList = totalList;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return totalList.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public Object instantiateItem(ViewGroup container, final int position) {
// Declare Variables
TextView tricksDescription;
Button tricksButton;
View itemView = inflater.inflate(R.layout.viewpager_item, container,
false);
tricksDescription = itemView.findViewById(R.id.xtv_tricks_description);
tricksButton = itemView.findViewById(R.id.tricks_button);
tricksDescription.setText(Html.fromHtml(totalList.get(position).getTipsDescription()));
tricksButton.setText(Html.fromHtml(totalList.get(position).getTipsButton()));
tricksButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
String url = totalList.get(position).getButtonLink();
intent.setData(Uri.parse(url));
startActivity(intent);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
container.addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
container.removeView(view);
}
}
I am using volley to get the values as JSON..
private void Home() {
try {
if (getActivity()!=null)
Commonfunctions.LoadPreferences(getActivity());
System.out.println("Authtoken:" + Commonfunctions.Token_key);
appservice.View_All_Events(Commonfunctions.Token_key, String.valueOf(pagenumber), new Server_Callback() {
#Override
public void onSuccess(String response) {
System.out.println("HOME Response :" + response);
try {
JSONObject signObject = new JSONObject(response);
String resStatus = signObject.getString(AppConstants.STATUS);
String resCode = signObject.getString(AppConstants.CODE);
String resMsg = signObject.getString(AppConstants.MSG);
if (resCode.equals(AppConstants.SUCCESS_CODE)) {
JSONArray allEvents = signObject.getJSONArray("all");
System.out.println("INNER Response :" + allEvents);
for (int i = 0; i < allEvents.length(); i++) {
JSONObject innerObj1 = allEvents.getJSONObject(i);
String backgroundImg = innerObj1.getString("backg_img");
String declinedCount = innerObj1.getString("decli_count");
String acceptedCount = innerObj1.getString("accep_count");
String invitedCount = innerObj1.getString("invi_count");
String messages = innerObj1.getString("i_chat");
String name = innerObj1.getString("name");
String eventTime = innerObj1.getString("duration");
String userPhoto = innerObj1.getString("photo");
JSONArray viewpagerEvents = innerObj1.getJSONArray("action");
for (int u = 0; u < viewpagerEvents.length(); u++) {
JSONObject innerObj3 = viewpagerEvents.getJSONObject(u);
String buttonText = innerObj3.getString("text");
String tipsDesc = innerObj3.getString("action_text");
String buttonLink = innerObj3.getString("button_link");
final Home_Model home_data = new Home_Model(name, messages,invitedCount,declinedCount,acceptedCount,eventTime,
userPhoto,backgroundImg);
data.add(home_data);
final Home_Model_ViewPager home_viewpager = new Home_Model_ViewPager(getContext(),tipsDesc,buttonText, buttonLink);
viewPagerData.add(home_viewpager);
}
}
adapter = new HomeAdapter(getContext(),data);
pagerAdapter = new ViewPagerAdapter(getActivity(), viewPagerData);
home_recycler.setAdapter(adapter);
adapter.notifyDataSetChanged();
if (adapter.getItemCount()==0) {
noeventLayout.setVisibility(View.VISIBLE);
}
else {
noeventLayout.setVisibility(View.GONE);
}
} else if (resCode.equals(AppConstants.UPDATE_CODE)) {
//Version_Update versionUpdate=new Version_Update(SignIn.this,response);
} else {
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Commonfunctions.showerrorsnackbar(resMsg, getActivity(), parentLayout);
}
} catch (JSONException e) {
e.printStackTrace();
}
}//on success close
});//server callback closed
} catch (Exception e) {
e.printStackTrace();
}
}
HomeAdapter:
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.ViewHolder> {
Context context;
List<Home_Model> students;
public HomeAdapter(Context context,List<Home_Model> students) {
this.context = context;
this.students = students;
}
#Override
public HomeAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.event_home_list, viewGroup, false);
return new HomeAdapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(final HomeAdapter.ViewHolder holder, final int position) {
holder.title.setText(students.get(position).getName());
holder.invited.setText(students.get(position).getInvited());
holder.accepted.setText(students.get(position).getAccept());
holder.declined.setText(students.get(position).getDecline());
holder.eventTime.setText(students.get(position).getEvent_time());
holder.messages.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(getActivity(),Chat_view.class));
}
});
holder.viewPager.setAdapter(pagerAdapter);
holder.dots = new ImageView[holder.dotsCount];
for (int i = 0; i < holder.dotsCount; i++) {
holder.dots[i] = new ImageView(context);
holder.dots[i].setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_dot_gray ));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(8, 0, 8, 0);
holder.sliderDots.addView(holder.dots[i], params);
}
holder.dots[0].setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_dot_colorprimary));
holder.viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
for (int i = 0; i < holder.dotsCount; i++) {
holder.dots[i].setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_dot_gray));
}
holder.dots[position].setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_dot_colorprimary));
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
if (students.get(position).getMessages().contentEquals("false")) {
holder.status.setVisibility(View.INVISIBLE);
}
else {
holder.status.setVisibility(View.VISIBLE);
}
holder.status.setVisibility(View.INVISIBLE);
try {
Glide.with(getActivity()).load(students.get(position).getProimg()).into(holder.pro_img);
Glide.with(getActivity()).load(students.get(position).getBgimg()).into(holder.card_main);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public int getItemCount() {
return students.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView title, messages, invited, accepted, declined, eventTime;
private PorterShapeImageView pro_img;
ImageView card_main, status;
ViewPager viewPager;
LinearLayout sliderDots;
private ImageView[] dots;
private int dotsCount;
public ViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.xtv_welcome);
messages = itemView.findViewById(R.id.xtv_message);
invited = itemView.findViewById(R.id.xtv_invited);
accepted = itemView.findViewById(R.id.xtv_accepted);
declined = itemView.findViewById(R.id.xtv_decline);
eventTime = itemView.findViewById(R.id.contact_number);
pro_img = itemView.findViewById(R.id.pro_pic);
card_main = itemView.findViewById(R.id.card_main);
status = itemView.findViewById(R.id.incoming_image);
viewPager = itemView.findViewById(R.id.viewPagerTips);
sliderDots = itemView.findViewById(R.id.sliderDots);
dotsCount = pagerAdapter.getCount();
}
}
}
Please try to make one different array list for your viewpager's adapter:
ArrayList<Home_Model_ViewPager> tempList = new ArrayList<>();
for(int k=0;k<viewpagerData.size();k++){
Home_Model_ViewPager object = viewPagerData.get(k);
if(object.getTripDesc()!=null && object.getTripDesc().length() >0){
tempList.add(object);
}
}
ViewPagerAdapter pagerAdapter = new ViewPagerAdapter(getActivity(), tempList);
home_recycler.setAdapter(adapter);
adapter.notifyDataSetChanged();
i am currently working with recyclerview in Xamarin android where i wish to filter the data displayed. I used to work with java on android and has successfully create a filter on recyclerview with using searchview. But for this one , i wish to display only the incomplete data where either one of the item in the view is empty. Below is my code for activity class and also recyclerview adapter class.Replies with code or explanation would be really helpful. Thank you.
class RemoveAlertActivity : Activity
{
private RecyclerView mRecyclerView_remove;
private RecyclerView.LayoutManager mLayoutManager_remove;
private RecyclerView.Adapter mAdapter_remove;
private List<Removerecyclerholder> mRemoverecyclerholder;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.RemoveAlert);
SQLiteDb obj = new SQLiteDb();
List<ScanSummary> scan = new List<ScanSummary>();
scan = obj.GetAllScanSummaryData();
ScanSummary[] array = scan.ToArray();
mRemoverecyclerholder = new List<Removerecyclerholder>();
for (int i = 0; i < array.Length; i++)
{
mRemoverecyclerholder.Add(new Removerecyclerholder() { partnumber_r = scan[i].SSPartNo, containernumber_r = scan[i].SSContainerSN, scanquantity_r = scan[i].SSPackType, totalquantity_r = scan[i].SSStatus });
}
mRecyclerView_remove = FindViewById<RecyclerView>(Resource.Id.recyclerview_remove);
mLayoutManager_remove = new LinearLayoutManager(this);
mRecyclerView_remove.SetLayoutManager(mLayoutManager_remove);
mAdapter_remove = new RecyclerAdapter_remove(mRemoverecyclerholder);
mRecyclerView_remove.SetAdapter(mAdapter_remove);
}
}
public class RecyclerAdapter_remove : RecyclerView.Adapter
{
private List<Removerecyclerholder> mRemoverecyclerholder;
public RecyclerAdapter_remove(List<Removerecyclerholder> removerecyclerholder)
{
mRemoverecyclerholder = removerecyclerholder;
}
public class MyView : RecyclerView.ViewHolder
{
public View mMainView { get; set; }
public TextView mpartnumber_r { get; set; }
public TextView mcontainernumber_r { get; set; }
public TextView mtotalquantity_r { get; set; }
public TextView mscanquantity_r { get; set; }
public MyView(View view) : base(view)
{
mMainView = view;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
SQLiteDb obj = new SQLiteDb();
List<ScanSummary> scan = obj.GetAllScanSummaryData();
View RemoveRecycleLayout = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.RemoveAlertRecycleLayout, parent, false);
TextView txtpartnumber_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.partnumber_remove);
TextView txtcontainernumber_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.containernumber_remove);
TextView txttotalquantity_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.totalquantity_remove);
TextView txtscanquantity_r = RemoveRecycleLayout.FindViewById<TextView>(Resource.Id.scanquantity_remove);
MyView view = new MyView(RemoveRecycleLayout) { mpartnumber_r = txtpartnumber_r, mcontainernumber_r = txtcontainernumber_r, mtotalquantity_r = txttotalquantity_r, mscanquantity_r = txtscanquantity_r };
return view;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
MyView myholder = holder as MyView;
myholder.mpartnumber_r.Text = mRemoverecyclerholder[position].partnumber_r;
myholder.mcontainernumber_r.Text = mRemoverecyclerholder[position].containernumber_r;
myholder.mtotalquantity_r.Text = mRemoverecyclerholder[position].totalquantity_r;
myholder.mscanquantity_r.Text = mRemoverecyclerholder[position].scanquantity_r;
((MyView)holder).mMainView.Click += delegate (object sender, EventArgs e)
{
View mMainView = (View)sender;
mMainView.SetBackgroundColor(color: Color.Blue);
var activity = new Intent(Application.Context, typeof(RemoveDataDetails));
activity.PutExtra("partnumber_r", mRemoverecyclerholder[position].partnumber_r);
activity.PutExtra("containernumber_r", mRemoverecyclerholder[position].containernumber_r);
Application.Context.StartActivity(activity);
};
}
public override int ItemCount
{
get { return mRemoverecyclerholder.Count; }
}
}
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?