Recycler list stucks allot while scrolling - android

I have added simple v7.widget.RecyclerView and set the adapter simply but while scrolling the list it jerks allot, scrolling is not working out smoothly. Infact I used few library as well for fast scrolling but nothing works. I have picasso inside adapter to load images while data setting or handling visibility is done in "onBindViewHolder".
If someone have better solution than kindly help me out.
I already tried all the below methods but none of them works
#BindView(R.id.rv_list)
RecyclerView rvList;
ViewCompat.setNestedScrollingEnabled(rvList, false);
rvList.setNestedScrollingEnabled(false);
rvList.setHasFixedSize(true);
rvList.setItemViewCacheSize(20);
rvList.setDrawingCacheEnabled(true);
rvList.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
Below is my Adapter Code:
public class RecyclerAdapter extends RecyclerView.Adapter<cadapter.RecyclerAdapter.MyViewHolder> {
Context ctx;
ArrayList<Model> Modelslist;
GlobalClass gc;
View itemView;
View parentView;
private RecyclerAdapter.RecyclerAdapterListener listener;
PrefManager prefManager;
public RecyclerAdapter(Context context, ArrayList<Model> Modelslist, RecyclerAdapter.RecyclerAdapterListener listener) {
this.Modelslist = Modelslist;
this.ctx = context;
gc = GlobalClass.getInstance();
this.listener = listener;
prefManager = new PrefManager(context);
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public RecyclerAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.layout, parent, false);
if (itemView == null) {
parentView = new RelativeLayout(this.ctx);
} else {
parentView = (RelativeLayout) itemView;
}
return new RecyclerAdapter.MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final RecyclerAdapter.MyViewHolder holder, final int position) {
final Model cat = this.Modelslist.get(position);
holder.txtNumber.setText(cat.getNumber());
holder.txtName.setText(cat.getName());
final String flagPath = cat.getFlag();
if(cat.getForwarding1().equals("0")) {
holder.callForwardingSwitch.setChecked(true);
holder.txtCallRateVal.setText(cat.getForwardingCost());
holder.txtCallRateVal.setVisibility(View.VISIBLE);
holder.txtCallRate.setVisibility(View.VISIBLE);
holder.txtCallRateVal2.setVisibility(View.VISIBLE);
holder.txtCallRateVal2.setTextColor(ctx.getResources().getColor(R.color.text_grey));
////VISIBLE call Forwading Text
holder.txtCallRateVal.setVisibility(View.VISIBLE);
holder.txtCallRate.setVisibility(View.VISIBLE);
}else{
holder.callForwardingSwitch.setChecked(false);
////Hide call Forwading Text
holder.txtCallRateVal.setVisibility(View.INVISIBLE);
holder.txtCallRate.setVisibility(View.INVISIBLE);
holder.txtCallRateVal2.setVisibility(View.INVISIBLE);
}
holder.txtNumberDesc.setText(cat.getDetails());
holder.txtRenewDate.setText(cat.getrenewal_date());
holder.txtSetupVal.setText(cat.getcost());
holder.txtMonthlyVal.setText(cat.getmonthlycost());
String application_status= cat.getapplication_status();
System.out.println("Application status:::::: "+ application_status+" number: "+cat.getNumber());
if(application_status.equals("0")){
holder.txtStatus.setText("* Pending Approval");
holder.txtStatus.setVisibility(View.VISIBLE);
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.account_error));
holder.txtCallRateVal.setVisibility(View.INVISIBLE);
holder.txtCallRateVal2.setVisibility(View.INVISIBLE);
holder.txtCallRate.setVisibility(View.INVISIBLE);
////////Unclicking Highlight Delete and call Forwarding
holder.Delete.setBackgroundResource(R.drawable.number_delete_gray);
holder.Delete.setClickable(false);
holder.callForwardingSwitch.setChecked(false);
holder.callForwardingSwitch.setClickable(false);
// holder.callForwardingSwitch.setHighlightColor(ctx.getResources().getColor(R.color.text_dark_grey));
/////////Visible Tag
holder.rel__number_status.setVisibility(View.VISIBLE);
holder.rel__number_status.setBackground(ctx.getDrawable(R.drawable._submitted_tag));
holder.txtNumberStatus.setText("Registration Submitted *");
/////// Hide Renew Date:
holder.txtRenew.setVisibility(View.GONE);
holder.txtRenewDate.setVisibility(View.GONE);
}else if(application_status.equals("1")){
holder.txtStatus.setText("Click here to complete number registration");
holder.txtStatus.setVisibility(View.VISIBLE);
/////////Visible Tag
holder.rel__number_status.setVisibility(View.VISIBLE);
holder.rel__number_status.setBackground(ctx.getDrawable(R.drawable._saved_tag));
holder.txtNumberStatus.setText("Registration Incomplete");
/////// Hide Renew Date:
holder.txtRenew.setVisibility(View.GONE);
holder.txtRenewDate.setVisibility(View.GONE);
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.app_header));
}else if(application_status.equals("2")){//////Approved///
//holder.txtStatus.setText("Approved");
holder.txtStatus.setVisibility(View.VISIBLE);
holder.txtStatus.setText("Active");
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.green600));
/////////Hide Tag
holder.rel__number_status.setVisibility(View.INVISIBLE);
holder.txtSetupVal.setVisibility(View.GONE);
holder.txtSetup.setVisibility(View.GONE);
/////// VISIBLE Renew Date:
holder.txtRenew.setVisibility(View.VISIBLE);
holder.txtRenewDate.setVisibility(View.VISIBLE);
}else if(application_status.equals("3")){///// Rejected///
//holder.txtStatus.setText("Rejected");
/////////Hide Tag
holder.txtStatus.setVisibility(View.INVISIBLE);
holder.rel__number_status.setVisibility(View.INVISIBLE);
/////// VISIBLE Renew Date:
holder.txtRenew.setVisibility(View.VISIBLE);
holder.txtRenewDate.setVisibility(View.VISIBLE);
}else{
if(cat.getLocal().equals("1") && cat.getAddress().equals("1")
&& cat.getPhoto().equals("1") && cat.getapplication_status().equals("-1")){
holder.txtStatus.setVisibility(View.VISIBLE);
holder.txtStatus.setText("Active");
holder.txtStatus.setTextColor(ctx.getResources().getColor(R.color.green600));
holder.rel__number_status.setVisibility(View.INVISIBLE);
holder.txtSetupVal.setVisibility(View.GONE);
holder.txtSetup.setVisibility(View.GONE);
}else{
holder.txtStatus.setText("");
/////////Hide Tag
holder.txtStatus.setVisibility(View.INVISIBLE);
holder.rel__number_status.setVisibility(View.INVISIBLE);
}
}
System.out.println("Flag::::::::::: "+ flagPath);
/*Picasso.with(ctx)
.load(flagPath) // thumbnail url goes here
.into(holder.CountryFlagim, new Callback() {
#Override
public void onSuccess() {
Picasso.with(ctx)
.load(flagPath) // image url goes here
.placeholder(holder.CountryFlagim.getDrawable())
.into(holder.CountryFlagim);
}
#Override
public void onError() {
}
});*/
Glide
.with(ctx)
.load(flagPath)
.centerCrop()
.placeholder(holder.CountryFlagim.getDrawable())
.into(holder.CountryFlagim);
//Picasso.with(ctx).load(flagPath).into(holder.CountryFlagim);
applyClickEvents(holder,position);
}
#Override
public int getItemCount() {
if (this.Modelslist != null) {
return this.Modelslist.size();
} else {
return 0;
}
}
private void applyClickEvents(final RecyclerAdapter.MyViewHolder holder, final int position) {
holder.mainFrame.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listener.moveToDetailScreen(position);
}
});
holder.Delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final Model cat = Modelslist.get(position);
}
});
holder.callForwardingSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
System.out.println("Call forwarding switch: "+ b);
}
});
}
public interface NumberListAdapterListener {
void deleteItem(int position);
void moveToDetailScreen(int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
RelativeLayout rel__number,rel__setup,rel__number_status;
ImageView CountryFlagim;
TextView txtNumber, txtName;
SwitchCompat callForwardingSwitch;
TextView txtNumberDesc;
TextView txtSetupVal, txtSetup;
TextView txtMonthlyVal;
TextView txtCallRateVal, txtCallRateVal2, txtCallRate;
TextView txtStatus;
TextView txtNumberStatus, txtRenewDate, txtRenew;
Button Delete;
RelativeLayout mainFrame;
public MyViewHolder(View v) {
super(v);
rel__number = (RelativeLayout) v.findViewById(R.id.rel__number);
rel__setup = (RelativeLayout) v.findViewById(R.id.rel__setup);
rel__number_status = (RelativeLayout) v.findViewById(R.id.rel__number_status);
CountryFlagim = (ImageView) v.findViewById(R.id.CountryFlagim);
txtNumber = (TextView) v.findViewById(R.id.txtNumber);
txtName = (TextView) v.findViewById(R.id.txtName);
txtNumberDesc = (TextView) v.findViewById(R.id.txtNumberDesc);
txtSetupVal = (TextView) v.findViewById(R.id.txtSetupVal);
txtSetup = (TextView) v.findViewById(R.id.txtSetup);
txtMonthlyVal = (TextView) v.findViewById(R.id.txtMonthlyVal);
txtCallRate = (TextView) v.findViewById(R.id.txtCallRate);
txtCallRateVal = (TextView) v.findViewById(R.id.txtCallRateVal);
txtCallRateVal2 = (TextView) v.findViewById(R.id.txtCallRateVal2) ;
txtStatus = (TextView) v.findViewById(R.id.txtStatus);
txtNumberStatus = (TextView) v.findViewById(R.id.txtNumberStatus);
Delete = (Button) v.findViewById(R.id.Delete);
callForwardingSwitch = (SwitchCompat) v.findViewById(R.id.callForwardingSwitch);
mainFrame = (RelativeLayout) v.findViewById(R.id.mainFrame);
txtRenewDate = (TextView) v.findViewById(R.id.txtRenewDate);
txtRenew = (TextView) v.findViewById(R.id.txtRenew);
}
}
}

You can try Glide. Glide doesn't load full size picture and uses less memory, which should be faster than Picasso.

Related

RecyclerView problems when scrolling

I have an expandable RecyclerView, when the data is loaded in the Recyclerview everything seems good but when I scroll to the bodem, the data on the items above were muted to. In a normale recycler view I can solve this problem by bind everything in my OnBindViewHolder but now its harder.
this is my code for the expandable adapter:
public class CalendarAdapter extends ExpandableRecyclerViewAdapter<CalendarHeaderViewHolder, CalendarItemViewHolder> {
private Context ctx;
public CalendarAdapter(List<? extends ExpandableGroup> group, Context ctx){
super(group);
this.ctx = ctx;
}
#Override
public CalendarHeaderViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.group_view_holder, parent, false);
return new CalendarHeaderViewHolder(view);
}
#Override
public CalendarItemViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.calendar_item, parent, false);
return new CalendarItemViewHolder(view,ctx);
}
#Override
public void onBindChildViewHolder(CalendarItemViewHolder holder, int flatPosition, ExpandableGroup group, int childIndex) {
final CalenderItem calenderItem = ((CalenderHeader) group).getItems().get(childIndex);
holder.onBind(calenderItem, group);
}
#Override
public void onBindGroupViewHolder(CalendarHeaderViewHolder holder, int flatPosition, ExpandableGroup group) {
holder.setGroupName(group);
}
}
And i bind my Holder in CalendarItemViewHolder
public class CalendarItemViewHolder extends ChildViewHolder {
private TextView tvDescription;
private TextView tvSubDescription;
private TextView tvDate;
private RelativeLayout ivIcon;
private CalenderItem item;
private LinearLayout llItemCal;
private onInteractionListener listener;
private Context ctx;
public CalendarItemViewHolder(View itemView, Context ctx){
super(itemView);
tvDescription = (TextView) itemView.findViewById(R.id.tvDescription);
tvSubDescription = (TextView)itemView.findViewById(R.id.tvSubDescription);
ivIcon = (RelativeLayout) itemView.findViewById(R.id.ivIcon);
tvDate = (TextView) itemView.findViewById(R.id.tvDate);
llItemCal = (LinearLayout) itemView.findViewById(R.id.llItemCal);
this.ctx = ctx;
listener = (onInteractionListener) ctx;
}
public void onBind(CalenderItem calenderItem, ExpandableGroup group){
this.item = calenderItem;
llItemCal.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//MOVE TO DETAIL SCREEN
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tvDescription.setText(Html.fromHtml(calenderItem.getActivitie().getTitle(), Html.FROM_HTML_MODE_COMPACT));
} else {
tvDescription.setText(Html.fromHtml(calenderItem.getActivitie().getTitle()));
}
//HERE IS A PROBLEM WHEN SCROLLING
if(calenderItem.getCalType()== null || calenderItem.getCalType().equals("")){
tvSubDescription.setVisibility(View.GONE);
}else{
tvSubDescription.setText(calenderItem.getCalType());
}
//HERE IS ALSO A PROBLEM WHEN SCROLLING
if (calenderItem.getDate() != null){
tvDate.setText(calenderItem.getDate());
tvDate.setVisibility(View.VISIBLE);
}
//HERE EVERYTHING SEEMS OKE
Drawable background = ctx.getResources().getDrawable(R.drawable.circle);
switch (item.getType()){
case PROTHESE:
background.setColorFilter(ContextCompat.getColor(ctx, R.color.blue_grey_200), PorterDuff.Mode.SRC_IN);
ivIcon.setBackground(background);
break;
case NOTHING:
background.setColorFilter(ContextCompat.getColor(ctx, R.color.blue_grey_400), PorterDuff.Mode.SRC_IN);
ivIcon.setBackground(background);
break;
case DANGER:
background.setColorFilter(ContextCompat.getColor(ctx, R.color.blue_grey_800), PorterDuff.Mode.SRC_IN);
ivIcon.setBackground(background);
break;
}
}
public interface onInteractionListener {
public void moveToDetailFragment(CalenderItem calItem);
}
}
When I scroll, the tvDate is showed randomly in my list
where do I need to write this code to solve this problem?
Please try with below code.
//HERE IS ALSO A PROBLEM WHEN SCROLLING
if (calenderItem.getDate() != null){
tvDate.setText(calenderItem.getDate());
tvDate.setVisibility(View.VISIBLE);
}else {
tvDate.setVisibility(View.GONE);
}
Must be like that :
//HERE IS A PROBLEM WHEN SCROLLING
if(calenderItem.getCalType()== null || calenderItem.getCalType().equals("")){
tvSubDescription.setVisibility(View.GONE);
}else{
tvSubDescription.setText(calenderItem.getCalType());
tvSubDescription.setVisibility(View.VISIBLE);
}
//HERE IS ALSO A PROBLEM WHEN SCROLLING
if (calenderItem.getDate() != null){
tvDate.setText(calenderItem.getDate());
tvDate.setVisibility(View.VISIBLE);
} else {
tvDate.setVisibility(View.GONE);
}

Removing recyclerview items from the Adapter

I have two tabs (fragments), NewOrders and FinishedOrders, I'm populating the orders via Volley requests, now each item inside the New Orders tab has a SwipeLayout which show a clickable textview that makes the order finished, and move it to the other tab (backend stuff..), and I got this working perfectly,
The problem is when I click to finish, the recyclerview isn't updated once the request sent successfully, I have to do pull-to-refresh so it would update..! it seems easy to solve, but the issue is handling the swipelayout listener done inside onBindView method inside the adapter..!! that's only place to access it according to the library I'm using (I guess)..! on the other hand refreshing and populating the list happens in the NewOrder tab fragment..!
So how can I make the item to be removed from the list after the click and becomes updated..?!
Any thoughts..!?
My Adapter Class + ViewHolder
Note: the implemented methods in the adapter are required because of the interface of SwipeLayout library
public class OrdersDataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements SwipeAdapterInterface, SwipeItemMangerInterface {
protected SwipeItemRecyclerMangerImpl mItemManger = new SwipeItemRecyclerMangerImpl(this);
public Context context;
ArrayList<OrderPresenter> orders;
public OrdersDataAdapter(ArrayList<OrderPresenter> orders, Context context) {
this.orders = orders;
this.context = context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_card, parent, false);
return new NewOrderVH(v);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final OrderPresenter order = this.orders.get(position);
final NewOrderVH vh1 = (NewOrderVH) holder;
vh1.setData(orders.get(position));
mItemManger.bindView(vh1.itemView, position);
vh1.swipeLayout.setShowMode(SwipeLayout.ShowMode.PullOut);
vh1.swipeLayout.addDrag(SwipeLayout.DragEdge.Left,
vh1.swipeLayout.findViewById(R.id.bottom_wrapper));
if (order.isFinished()) {
vh1.swipeLayout.setSwipeEnabled(false);
vh1.setBadge("DONE");
vh1.setBadgeColor(order.getBadgeColor());
} else {
vh1.finish.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// get the clicked item position?
final int position = vh1.getAdapterPosition();
// these responsible for the request which make the order finished
OrderPresenter order = orders.get(position);
OrderRepository.setOrderFinURL(order.getID());
OrderRepository.FinishOrder(order.getID(), context);
/*the commented three lines below didn't help with the problem*/
// notifyItemChanged(position);
// notifyItemRemoved(position);
// notifyDataSetChanged();*/
order.setStatus(order.getStatusText(Order.FINISHED));
}
});
}
}
#Override
public int getItemCount() {
return orders.size();
}
public class NewOrderVH extends RecyclerView.ViewHolder {
SwipeLayout swipeLayout;
private TextView finish;
private CardView orderCard;
TextView Badge;
private ImageView cusPic;
private TextView cusName;
private TextView CusAdress;
private TextView vendorsNum;
private TextView itemsNum;
private TextView time;
private TextView emptyView;
public NewOrderVH(View itemView) {
super(itemView);
Badge = (TextView) itemView.findViewById(R.id.badge);
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
finish = (TextView) itemView.findViewById(R.id.finish);
orderCard = (CardView) itemView.findViewById(R.id.OrderCard);
cusPic = (ImageView) itemView.findViewById(R.id.cusPic);
cusName = (TextView) itemView.findViewById(R.id.cusName);
CusAdress = (TextView) itemView.findViewById(R.id.CusAdress);
vendorsNum = (TextView) itemView.findViewById(R.id.vendorsNum);
itemsNum = (TextView) itemView.findViewById(R.id.itemsNum);
time = (TextView) itemView.findViewById(R.id.time);
emptyView = (TextView) itemView.findViewById(R.id.empty_view);
orderCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), OrderDetails.class);
v.getContext().startActivity(intent);
}
});
}
public void setData(final OrderPresenter data) {
time.setText(data.getOrderTime());
cusName.setText(data.getFullName());
vendorsNum.setText(data.getVendorsCount());
itemsNum.setText(data.getItemsCount());
CusAdress.setText(data.getFullAddress());
Picasso.with(context).load(data.getCustomerPicture()).into(cusPic);
}
public void setBadgeColor(int drawable) {
this.Badge.setBackgroundResource(drawable);
}
public void setBadge(String badge) {
this.Badge.setText(badge);
}
}
#Override
public int getSwipeLayoutResourceId(int position) {
return R.id.swipe;
}
#Override
public void openItem(int position) {
}
#Override
public void closeItem(int position) {
}
#Override
public void closeAllExcept(SwipeLayout layout) {
}
#Override
public void closeAllItems() {
}
#Override
public List<Integer> getOpenItems() {
return null;
}
#Override
public List<SwipeLayout> getOpenLayouts() {
return null;
}
#Override
public void removeShownLayouts(SwipeLayout layout) {
}
#Override
public boolean isOpen(int position) {
return false;
}
#Override
public Attributes.Mode getMode() {
return null;
}
#Override
public void setMode(Attributes.Mode mode) {
}
}
My NewOrder Fragment
Note: the FinishedOrders tab (fragment) does the same thing as new order but filters the current the Finished status.
public class NewOrdersTab extends Fragment {
RecyclerView recyclerView;
OrdersDataAdapter adapter;
private SwipeRefreshLayout swiperefresh;
private TextView emptyView;
ArrayList<OrderPresenter> modelData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.new_orders_tab_frag, container, false);
modelData = new ArrayList<>();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
swiperefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.swiperefresh);
recyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
swiperefresh.setColorSchemeResources(R.color.colorPrimary, R.color.color_error, R.color.colorInfo);
adapter = new OrdersDataAdapter(modelData, getActivity());
emptyView = (TextView) rootView.findViewById(R.id.empty_view);
recyclerView.setAdapter(adapter);
adapter.setMode(Attributes.Mode.Single);
OrderRepository.fetchOrders("awaiting-shipment", getActivity(), new DataFetch() {
#Override
public void onResponse(ArrayList<OrderPresenter> data) {
swiperefresh.setRefreshing(true);
if (data.size() != 0) {
swiperefresh.setRefreshing(true);
emptyView.setVisibility(View.GONE);
modelData.clear();
modelData.addAll(data);
adapter.notifyDataSetChanged();
} else {
emptyView.setVisibility(View.VISIBLE);
emptyView.setText(getString(R.string.No_New_Orders));
}
swiperefresh.setRefreshing(false);
}
});
return rootView;
}
}
I figured it out, I just added these two lines after I make the request..!
orders.remove(position);
notifyItemRemoved(position);
//notifyDataSetChanged(position);

How to add click to RecyclerView whole row and a specific row item separately?

I have a RecyclerView with two TextViews and one ImageView. I want to add separate click to whole each row and the ImageViewin each row seperately. Is it possible?
Here is my Adapter class:
public class ContactsListAdapter extends RecyclerView.Adapter<ContactsListAdapter.MyViewHolder> {
private List<ContactsDataModel> dataList;
private Typeface tfSegoeui;
Context context;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, detail;
public ImageView catIcon, imgCall;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
detail = (TextView) view.findViewById(R.id.detail);
catIcon = (ImageView) view.findViewById(R.id.catIcon);
imgCall = (ImageView) view.findViewById(R.id.imgCall);
}
}
public ContactsListAdapter(Context context, List<ContactsDataModel> dataList) {
this.dataList = dataList;
this.context = context;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.contacts_list_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
ContactsDataModel dataModel = dataList.get(position);
tfSegoeui = Typeface.createFromAsset(holder.title.getContext().getResources().getAssets(), "fonts/segoeui.ttf");
holder.title.setText(dataModel.getName());
holder.detail.setText(dataModel.getPersonalNumber());
holder.imgCall.setTag(dataModel.getPersonalNumber());
holder.catIcon.setImageResource(dataModel.getImage());
holder.title.setTypeface(tfSegoeui);
holder.detail.setTypeface(tfSegoeui);
holder.imgCall.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String number = holder.imgCall.getTag().toString();
Log.d("number", number);
String num = "tel:" + number;
try {
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(num));
context.startActivity(dialIntent);
}catch(Exception e) {
Toast.makeText(context,"Your call has failed...",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
EndCallListener callListener = new EndCallListener();
TelephonyManager mTM = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);
}
});
}
#Override
public int getItemCount() {
return dataList.size();
}
private class EndCallListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
String LOG_TAG = "Call contact ";
if(TelephonyManager.CALL_STATE_RINGING == state) {
Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
}
if(TelephonyManager.CALL_STATE_OFFHOOK == state) {
//wait for phone to go offhook (probably set a boolean flag) so you know your app initiated the call.
Log.i(LOG_TAG, "OFFHOOK");
}
if(TelephonyManager.CALL_STATE_IDLE == state) {
//when this state occurs, and your flag is set, restart your app
Log.i(LOG_TAG, "IDLE");
}
}
}
}
Set your single row layout file as
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, detail;
public ImageView catIcon, imgCall;
//add item_row layout e.g
public RelativeLayout rel;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
detail = (TextView) view.findViewById(R.id.detail);
catIcon = (ImageView) view.findViewById(R.id.catIcon);
imgCall = (ImageView) view.findViewById(R.id.imgCall);
rel= (RelativeLayout) view.findViewById(your_id_here);
rel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//whatever you want here
}
});
}
}
Please refer the below code for item click event.
ContactsListAdapter
private List<ContactsDataModel> dataList;
private Typeface tfSegoeui;
Context context;
public interface OnContactClick {
public void onContactClick(int position);
}
OnContactClick onContactClick;
public void setOnContactClick(OnContactClick onContactClick) {
this.onContactClick = onContactClick;
}
Add this in onBindViewHolder
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
ContactsDataModel dataModel = dataList.get(position);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(onContactClick != null) {
onContactClick.onContactClick(position);
}
}
});
Add below line in activity
ContactsListAdapter contactsListAdapter = new ContactsListAdapter(this, dataList);
contactsListAdapter.setOnContactClick(new ContactsListAdapter.OnContactClick() {
#Override
public void onContactClick(int position) {
//You will receive event when clicking item in list
}
});
you can add to click listener to any view like this inside ViewHolder class
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, detail;
public ImageView catIcon, imgCall;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
detail = (TextView) view.findViewById(R.id.detail);
catIcon = (ImageView) view.findViewById(R.id.catIcon);
imgCall = (ImageView) view.findViewById(R.id.imgCall);
imgCall.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
}
});
title.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
}
});
catIcon.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
}
});
detail.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
}
});
}
}
and if you want position of the item clicked.
add this line inside your onBindViewHolder
title.setTag(position);
get position using title.getTag()
save
View itemView
in the holder and do setonclick like you did with the imgCall
also you did two onclick listeners on imgCall

Updating TextView and running Animation on rows in RecyclerView is causing memory leak

In our application, we have recyclerviews with many rows in them. Each one has a TextView whos text is a timestamp representing how long the row has been there, as well as an ImageView that may or may not need to be animated based on the item the row corresponds to.
The complication is this: The TextView needs to be updated every second, and the ImageView may need to be animated every few seconds to shake. While watching the Memory Monitor in Android Studio, the memory climbs and then seems to garbage collect, but does so in a loop for the entirety of the time I remain on this page of the app. When I leave the page with the ListView on it, memory drops down and seems to hold steady.
Here's the current way i'm updating the rows:
listRunnable = new Runnable() {
#Override
public void run() {
ArrayList<SystemEventsAdapter.SimpleViewHolder> holders = mAdapter.getCurrentActiveViews();
for (SystemEventsAdapter.SimpleViewHolder holder : holders) {
holder.alarmDuration.setText(holder.systemEvent.getAge());
if (!holder.systemEvent.IsSilenced && holder.systemEvent.isSquawking && !holder.imageAnimator.isRunning()) {
holder.imageAnimator.start();
}
}
listHandler.removeCallbacks(listRunnable);
listHandler.postDelayed(listRunnable, 1000);
}
};
listHandler.post(listRunnable);
the getAge() method just turns the milliseconds the event has been open into the HH:mm:ss format using String.format().
Here's the relevant code from inside the adapter:
public ArrayList<SimpleViewHolder> getCurrentActiveViews() {
synchronized (activeHolders) {
return activeHolders;
}
}
#Override
public void onViewAttachedToWindow(final SimpleViewHolder holder) {
super.onViewAttachedToWindow(holder);
activeHolders.add(holder);
}
#Override
public void onViewDetachedFromWindow(SimpleViewHolder holder) {
super.onViewDetachedFromWindow(holder);
holder.imageAnimator.cancel();
activeHolders.remove(holder);
}
Here is the SimpleViewHolder class:
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
TextView alarmType, origin;
public TextView alarmDuration;
CircularImageView userImg;
RelativeLayout alarmFieldHolder;
View colorBand;
public SystemEvent systemEvent;
public ObjectAnimator imageAnimator;
public SimpleViewHolder(View itemView) {
super(itemView);
//Items for individual event
userImg = (CircularImageView) itemView.findViewById(R.id.alarm_image);
alarmType = (TextView) itemView.findViewById(R.id.alarm_type);
alarmDuration = (TextView) itemView.findViewById(R.id.alarm_duration);
alarmFieldHolder = (RelativeLayout) itemView.findViewById(R.id.alarm_field_container);
colorBand = (View) itemView.findViewById(R.id.color_band);
origin = (TextView) itemView.findViewById(R.id.alarm_origin);
imageAnimator = new ObjectAnimator();
imageAnimator.setPropertyName("rotation");
imageAnimator.setFloatValues(0,-15,15,0);
imageAnimator.setDuration(600);
imageAnimator.setInterpolator(new BounceInterpolator());
imageAnimator.setTarget(userImg);
}
}
Previously, i've tried putting a Runnable on each individual row so that it would update itself, which still seemed to be leaking memory. I also tried using using Animator instead of ObjectAnimator, which didn't seem to help either.
The result is that the app performs fine at first, but after about 8 hours of these events getting updated, the whole app has slowed to a crawl.
Update:
Here is the code for the entire adapter
public class SystemEventsAdapter extends RecyclerView.Adapter<SystemEventsAdapter.SimpleViewHolder>{
private ArrayList<SystemEvent> events = new ArrayList<>();
private ArrayList<SimpleViewHolder> activeHolders = new ArrayList<>();
private Activity activity;
private int selectedAlarm;
public SystemEventsAdapter(final Activity activity, ArrayList<SystemEvent> alarms) {
this.events = alarms;
sortAlarms();
this.activity = activity;
}
public int getCount() {
return events.size();
}
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
TextView alarmType, origin;
public TextView alarmDuration;
CircularImageView userImg;
RelativeLayout alarmFieldHolder;
View colorBand;
public SystemEvent systemEvent;
public ObjectAnimator imageAnimator;
public SimpleViewHolder(View itemView) {
super(itemView);
//Items for individual event
userImg = (CircularImageView) itemView.findViewById(R.id.alarm_image);
alarmType = (TextView) itemView.findViewById(R.id.alarm_type);
alarmDuration = (TextView) itemView.findViewById(R.id.alarm_duration);
alarmFieldHolder = (RelativeLayout) itemView.findViewById(R.id.alarm_field_container);
colorBand = (View) itemView.findViewById(R.id.color_band);
origin = (TextView) itemView.findViewById(R.id.alarm_origin);
imageAnimator = new ObjectAnimator();
imageAnimator.setPropertyName("rotation");
imageAnimator.setFloatValues(0,-15,15,0);
imageAnimator.setDuration(600);
imageAnimator.setInterpolator(new BounceInterpolator());
imageAnimator.setTarget(userImg);
}
}
#Override
public int getItemCount() {
return events.size();
}
public ArrayList<SimpleViewHolder> getCurrentActiveViews() {
synchronized (activeHolders) {
return activeHolders;
}
}
#Override
public void onViewAttachedToWindow(final SimpleViewHolder holder) {
super.onViewAttachedToWindow(holder);
activeHolders.add(holder);
}
#Override
public void onViewDetachedFromWindow(SimpleViewHolder holder) {
super.onViewDetachedFromWindow(holder);
holder.imageAnimator.cancel();
activeHolders.remove(holder);
}
#Override
public void onBindViewHolder(final SimpleViewHolder holder, int position) {
final SystemEvent event =events.get(position);
if(event.Image == null || event.Image == "") {
Picasso.with(activity).load(R.drawable.system_events_with_border).fit().into(holder.userImg);
} else {
Picasso.with(activity).load(event.Image).fit().into(holder.userImg);
}
holder.alarmType.setText(event.getEvent());
if(event.Origin == null || event.Origin.equals("")) {
holder.origin.setVisibility(View.GONE);
} else {
holder.origin.setVisibility(View.VISIBLE);
holder.origin.setText(event.Origin);
}
holder.alarmDuration.setText(event.getAge());
holder.alarmFieldHolder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (checkExpandedAlarm(event.ID)) {
selectedAlarm = event.ID;
FragmentTransaction fragTrans = activity.getFragmentManager().beginTransaction();
System_Event_Expanded_Fragment frag = new System_Event_Expanded_Fragment();
Bundle b = new Bundle();
b.putInt("alarmID", event.ID);
b.putString("mode", "normal");
frag.setArguments(b);
fragTrans.setCustomAnimations(R.animator.slide_out_bottom, R.animator.slide_in_bottom, R.animator.slide_out_bottom, R.animator.slide_in_bottom);
fragTrans.replace(R.id.right__frag_container, frag).addToBackStack(null);
fragTrans.commit();
}
}
});
holder.systemEvent = event;
}
#Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate( R.layout.system_event_field, parent, false);
return new SimpleViewHolder(v);
}
public boolean checkExpandedAlarm(int AlarmID) {
if (selectedAlarm != 0 && AlarmID != selectedAlarm)
activity.getFragmentManager().popBackStack();
return AlarmID != selectedAlarm;
}
public void updateAlarms() {
events = AtmosDesk.getAlarmManager().getSystemEvents();
sortAlarms();
notifyDataSetChanged();
}
public void sortAlarms() {
Collections.sort(events, new eventComparator());
}
private class eventComparator implements Comparator<AtmosEvent> {
#Override
public int compare(AtmosEvent o1, AtmosEvent o2) {
return o1.getDate().compareTo(o2.getDate());
}
}
}

Android recyclerview content changes onscroll

I'm using RecyclerView to display a list, and each item in RecyclerView is shown as a CardView. When RecyclerView is scrolled down the content inside CardView changes.
Before scrolling down:
After scrolling down:
As you can see in above two images "UNKNOWN" was changed to "null". The contents shown inside RecyclerView is fetched from SQLite. Could not find any solution after hours and hours of googling.
Adapter Class:
public class DraftListAdapter extends
RecyclerView.Adapter<DraftListAdapter.ViewHolder> {
private static final String TAG = "DraftListAdapter";
private ArrayList<EventDAO> al_item_list;
private int rowLayout;
private Activity obj_activity;
private DisplayImageOptions obj_display_image_options;
private static RecyclerViewClickListener itemListener;
private SimpleDateFormat obj_date_formater_display = new SimpleDateFormat(
"MMMM d, yyyy");
private SimpleDateFormat obj_date_formater_sqlite = new SimpleDateFormat(
"yyyy-MM-dd");
public DraftListAdapter(ArrayList<EventDAO> al_item_list, int rowLayout,
Activity obj_activity, DisplayImageOptions obj_display_image_options) {
this.al_item_list = al_item_list;
this.rowLayout = rowLayout;
this.obj_activity = obj_activity;
this.obj_display_image_options = obj_display_image_options;
}
public DraftListAdapter(ArrayList<EventDAO> al_item_list, int rowLayout,
Activity obj_activity,
DisplayImageOptions obj_display_image_options,
RecyclerViewClickListener itemListener) {
this.al_item_list = al_item_list;
this.rowLayout = rowLayout;
this.obj_activity = obj_activity;
this.obj_display_image_options = obj_display_image_options;
this.itemListener = itemListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(rowLayout,
viewGroup, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
final EventDAO obj_current = al_item_list.get(position);
viewHolder.button_edit.setText("EDIT");
viewHolder.imageview_bookmark.setVisibility(View.INVISIBLE);
viewHolder.imageview_call.setVisibility(View.INVISIBLE);
//display event banner
viewHolder.imageview_event_banner.setTag(position);
viewHolder.textview_event_name.setTag(position);
ImageLoader.getInstance().displayImage("file:///"+obj_current.eventBanner,
viewHolder.imageview_event_banner, obj_display_image_options,null);
viewHolder.imageview_event_banner.setAlpha(200);
//display event location slug
viewHolder.textview_event_name.setText(obj_current.eventName);
if (obj_current.isOnline.equals("1")) {
viewHolder.linearlayout_location.setVisibility(View.GONE);
viewHolder.linearlayout_online.setVisibility(View.VISIBLE);
viewHolder.textview_location_slug.setText("ONLINE EVENT");
} else {
viewHolder.linearlayout_location.setVisibility(View.VISIBLE);
viewHolder.linearlayout_online.setVisibility(View.GONE);
if(obj_current.objLocation != null
&& obj_current.objLocation.locationName != null
&& !obj_current.objLocation.locationName.equalsIgnoreCase(""))
viewHolder.textview_location_slug.setText(obj_current.objLocation.locationName);
}
//display date
//display time
viewHolder.textview_event_time.setText("Time: " + obj_current.startTime);
viewHolder.button_edit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment obj_fragment = CreateEventFragment.newInstance(obj_current);
FragmentTransaction fragment_transaction_eventdetails = ((MainActivity) obj_activity)
.getSupportFragmentManager().beginTransaction();
// Get the details of that view to the EventDetailsFragment..
fragment_transaction_eventdetails.replace(R.id.container,
obj_fragment);
fragment_transaction_eventdetails.addToBackStack(obj_fragment
.getClass().getName());
fragment_transaction_eventdetails.commit();
}
});
viewHolder.button_delete.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new AlertDialog.Builder((MainActivity) obj_activity)
.setTitle("Quit")
.setMessage("Do you really want to delete this drafted event?")
.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
EventDAO obj_delete_event_dao = new EventDAO(obj_activity);
obj_delete_event_dao.deleteEvent(obj_current.localEventID);
obj_delete_event_dao.closeDbConnection();
al_item_list.remove(position);
notifyDataSetChanged();
}
}).setNegativeButton("No", null).show();
}
});
viewHolder.linearlayout_location
.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(obj_activity, "Map intent",
Toast.LENGTH_SHORT).show();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri
.parse("geo:0,0?q=Kothrud"));
obj_activity.startActivity(Intent.createChooser(intent,
"Select "));
}
});
}
#Override
public int getItemCount() {
return al_item_list == null ? 0 : al_item_list.size();
}
/**
* class to hold event list item
*
*
*/
public static class ViewHolder extends RecyclerView.ViewHolder implements
OnClickListener {
public ImageView imageview_event_banner;
public ImageView imageview_bookmark;
public ImageView imageview_call;
public TextView textview_event_name;
// public TextView textview_event_type;
public TextView textview_location_slug;
public TextView textview_event_date;
public TextView textview_event_time;
public Button button_edit;
public Button button_delete;
public LinearLayout linearlayout_location;
public LinearLayout linearlayout_online;
public ViewHolder(View itemView) {
super(itemView);
linearlayout_location = (LinearLayout) itemView
.findViewById(R.id.linearlayout_location);
linearlayout_online = (LinearLayout) itemView
.findViewById(R.id.linearlayout_online);
imageview_event_banner = (ImageView) itemView
.findViewById(R.id.imageview_event_banner);
imageview_bookmark = (ImageView) itemView
.findViewById(R.id.imageview_bookmark);
imageview_call = (ImageView) itemView
.findViewById(R.id.imageview_call);
textview_event_name = (TextView) itemView
.findViewById(R.id.textview_event_name);
textview_event_name.setSelected(true);
textview_location_slug = (TextView) itemView
.findViewById(R.id.textview_location_slug);
textview_location_slug.setSelected(true);
textview_event_date = (TextView) itemView
.findViewById(R.id.textview_event_date);
textview_event_time = (TextView) itemView
.findViewById(R.id.textview_event_time);
button_edit = (Button) itemView
.findViewById(R.id.button_edit);
button_delete = (Button) itemView
.findViewById(R.id.button_delete);
linearlayout_location.setOnClickListener(this);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
itemListener.recyclerViewListClicked(v, getPosition());
}
}
}

Categories

Resources