Here is my code
this is my recyclerview adapter code ..
i dnot konw why my recycler view lagging after schroll
Pleas Help ME
public class Recyclerview1Adapter extends RecyclerView.Adapter<Recyclerview1Adapter.ViewHolder> {
ArrayList<HashMap<String, Object>> _data;
public Recyclerview1Adapter(ArrayList<HashMap<String, Object>> _arr) {
_data = _arr;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater _inflater = getActivity().getLayoutInflater();
View _v = _inflater.inflate(R.layout.video_item, null);
RecyclerView.LayoutParams _lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
_v.setLayoutParams(_lp);
return new ViewHolder(_v);
}
#Override
public void onBindViewHolder(ViewHolder _holder, final int _position) {
View _view = _holder.itemView;
final LinearLayout linear1 = _view.findViewById(R.id.linear1);
final LinearLayout linear2 = _view.findViewById(R.id.linear2);
final LinearLayout linear4 = _view.findViewById(R.id.linear4);
final androidx.cardview.widget.CardView cardview2 = _view.findViewById(R.id.cardview2);
final LinearLayout linear3 = _view.findViewById(R.id.linear3);
final LinearLayout linear7 = _view.findViewById(R.id.linear7);
final ImageView imageview1 = _view.findViewById(R.id.imageview1);
final TextView textview1 = _view.findViewById(R.id.textview1);
final TextView textview2 = _view.findViewById(R.id.textview2);
final LinearLayout linear5 = _view.findViewById(R.id.linear5);
final TextView textview3 = _view.findViewById(R.id.textview3);
final TextView textview4 = _view.findViewById(R.id.textview4);
final LinearLayout linear10 = _view.findViewById(R.id.linear10);
final ImageView imageview3 = _view.findViewById(R.id.imageview3);
_shapeRadius(textview1, "#000000", 6);
_shapeRadius(textview4, "#272731", 8);
textview1.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_regular.ttf"), 0);
textview2.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_bold.ttf"), 0);
textview3.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_regular.ttf"), 0);
textview4.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_bold.ttf"), 0);
textview1.setTextSize((int)8);
cardview2.setBackground(new GradientDrawable() { public GradientDrawable getIns(int a, int b) { this.setCornerRadius(a); this.setColor(b); return this; } }.getIns((int)18, 0xFF272731));
duration = Double.parseDouble(allVideosList.get((int)_position).get("videoDuration").toString());
videoDuration = stringForTime((int)duration);
textview1.setText(videoDuration);
path = allVideosList.get((int)_position).get("videoPath").toString();
//using cardview programmatically inside listview is not good. use recyclerview instead of listview.
androidx.cardview.widget.CardView cardview1 = new androidx.cardview.widget.CardView(VideoListFragmentActivity.this.getContext());
cardview1.setCardElevation(0);
cardview1.setCardBackgroundColor(0xFF272731);
cardview1.setRadius(18);
ViewGroup imageParent = ((ViewGroup)imageview1.getParent()); imageParent.removeView(imageview1);
cardview1.addView(imageview1);
imageParent.addView(cardview1);
textview2.setText(Uri.parse(path).getLastPathSegment());
size = Double.parseDouble(allVideosList.get((int)_position).get("videoSize").toString());
humanReadableSize = bytesIntoHumanReadable((long)size);
textview3.setText(allVideosList.get((int)_position).get("formattedDate").toString());
com.bumptech.glide.Glide.with(getContext().getApplicationContext())
.load(path)
.transition(DrawableTransitionOptions.withCrossFade(factory))
.placeholder(R.drawable.video_background)
.error(R.drawable.video_background)
.fitCenter()
.into(imageview1);
textview4.setText(humanReadableSize);
}
#Override
public int getItemCount() {
return _data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View v) {
super(v);
}
}
}
Iam trying to create a video player app after adding rcyclerview with glide image loader library , recyclerview is lagging after scroll , get all videos from storage using mediastore then add in a list and add list in recyclerview , but after load more than 100 videos recycler view is lagging to much so please help me .
I think you should try moving stuff from onBindViewHolder to onCreateViewHolder, such as all the setTypeface calls. You shouldn't be calling those every time you bind.
Do you need to create those typefaces for every textview in every viewholder? Maybe you could load those once somewhere else, like in the constructor.
Why are you finding all those linearLayouts in onBindViewHolder? They don't seem to be used in the code.
Ultimately, though, I think most of your latency is probably coming from the
com.bumptech.glide.Glide component, which looks like you are loading a video for each item. You could try creating a test loop that all it does is load all those videos using this component, and time how long it takes.
Related
I have the same question like this post "Cardview's data are changed while scrolling RecyclerView".
But taking out the statics isn't working.
Context of what I am doing:
I am adding a couple of buttons inside a FlexboxLayout and again inside a CardView (CardView inside a RecyclerView). Buttons are being added dynamically.
The same thing happens with a couple of TextView, which I add after Buttons to CardView.
Problem:
Buttons and TextViews are being Multiplied, while I Scroll.
Context of different CardViews are being exchanged, while scrolling.
Video: https://sendvid.com/adugp8vh
What I am using:
RecyclerView is inside one of my Fragments (ConstraintLayout), in which I defined the recycler Adapter.
This is my adapter
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
ArrayList<DataModel> dataSet = new ArrayList<DataModel>();
Context currentContext;
public class MyViewHolder extends RecyclerView.ViewHolder {
public Button datumButton;
public FlexboxLayout matchedWordsLayout;
public LinearLayout textviewLayout;
public MyViewHolder(View itemView) {
super(itemView);
this.datumButton = (Button) itemView.findViewById(R.id.datumButton);
this.matchedWordsLayout = (FlexboxLayout) itemView.findViewById(R.id.matchedWordsLayout);
this.textviewLayout = (LinearLayout) itemView.findViewById(R.id.textviewLayout);
}
}
public CustomAdapter(ArrayList<DataModel> data, Context currentContext) {
this.dataSet = data;
// currentContext not getting it from here
}
#NonNull
#Override
public CustomAdapter onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.positive_result_card, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(view);
this.currentContext = parent.getContext();
return myViewHolder;
}
#RequiresApi(api = Build.VERSION_CODES.O)
//#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int listPosition) {
Button DatumButton = holder.datumButton;
FlexboxLayout MatchedWordsLayout = holder.matchedWordsLayout;
LinearLayout TextviewLayout = holder.textviewLayout;
//Modify the button for date
ArrayList <String> TTMMYY = dataSet.get(listPosition).getDatum();
String Datum = String.join(".", TTMMYY);
DatumButton.setText(Datum);
DatumButton.setTag(Datum);
// add button for each word
ArrayList <String> ButtonNames = dataSet.get(listPosition).getButtonnames();
for (String Buttonname : ButtonNames) {
Button sampleButton = new Button(currentContext);
sampleButton.setText(Buttonname);
sampleButton.setTag(Datum);
MatchedWordsLayout.addView(sampleButton);
}
ArrayList <String> textLines = dataSet.get(listPosition).getTextLines();
for (String satzt : textLines){
TextView sampleTextView = new TextView(currentContext);
sampleTextView.setText(satzt);
TextviewLayout.addView(sampleTextView);
}
}
#Override
public int getItemCount() {
return dataSet.size();
}
}
My text has probably mistakes
You are adding Views programmatically on every bind, but you never remove them, so each bind just adds more (remember that ViewHolders are re-used, so the Buttons and TextViews you added last time are still there). To fix it, remove all the children from the ViewGroups before you add the new children:
// Added: remove all the children before we add more
MatchedWordsLayout.removeAllViews();
for (String Buttonname : ButtonNames) {
Button sampleButton = new Button(currentContext);
sampleButton.setText(Buttonname);
sampleButton.setTag(Datum);
MatchedWordsLayout.addView(sampleButton);
}
ArrayList <String> textLines = dataSet.get(listPosition).getTextLines();
// Added: remove all the children before we add more
TextviewLayout.removeAllViews();
for (String satzt : textLines){
TextView sampleTextView = new TextView(currentContext);
sampleTextView.setText(satzt);
TextviewLayout.addView(sampleTextView);
}
I am trying to load images to imageview in my ListAdapter. However while I am passing 10 thumbnail images to listAdapter and set them in imageview, only 1 or none is visible in imageview. As I understand from docs, I dont need to use any asyntask, since picasso library has already working asyntask. Could you please help me how I can handle this issue?
// Calling CustumListAdapter like this;
CustomListAdapter customListAdapter = new CustomListAdapter(this, resultArrayList);
listView = (ListView) findViewById(R.id.listview_score);
listView.setAdapter(customListAdapter)
// And here is my CustomListAdapter class
public class CustomListAdapter extends ArrayAdapter<String> {
private ArrayList<String> resultContent;
//private Integer[] imageid;
private Activity context;
public CustomListAdapter(Activity context, ArrayList<String> resultContent) {
super(context, R.layout.activity_ident_result2, resultContent);
this.context = context;
this.resultContent = resultContent;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View listViewItem = inflater.inflate(R.layout.activity_ident_result2, null, true);
if (position % 2 == 0) {
TextView textViewName = (TextView) listViewItem.findViewById(R.id.textView_score);
textViewName.setText(resultContent.get(position));
ImageView imageView = (ImageView) listViewItem.findViewById(R.id.imageView_score);
//imageView.setImageBitmap(IdentResultActivity.splittedBitmaps.get(position + 1));
Picasso.with(this.context).load(resultContent.get(position + 1)).into(imageView);
}
return listViewItem;
}
}
EDIT:
I used .placeholder(R.drawble.progress) and I can see one image placed without problem, rest are progress.png
EDIT2:
Here is my imageView xml file;
<ImageView
android:layout_width="75dp"
android:layout_height="75dp"
android:id="#+id/imageView_score" />
I believe the parameters of inflater.inflate should be (R.layout.activity_ident_result2, parent, false)
U need to create loop for adding every image to [] and then u need to show it. Becouse of ur posted code u adding just one image.
I just tried to change the color of my drawable inside my row depending on a value but instead of one drawable the adapter changed all of them.
Here is my Adapter:
public class ReportAdapter extends RecyclerView.Adapter<ReportAdapter.ReportViewHolder> {
DataBaseHelper dataBase;
private LayoutInflater inflater;
List<ChoosedSubject> data = Collections.emptyList();
Context context;
OnItemClickListener itemClickListener;
public ReportAdapter(Context context, List<ChoosedSubject> data, OnItemClickListener itemClickListener) {
inflater = LayoutInflater.from(context);
this.data = data;
this.context = context;
this.itemClickListener = itemClickListener;
}
#Override
public ReportViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.report_cell, parent, false);
ReportViewHolder holder = new ReportViewHolder(view);
dataBase = new DataBaseHelper(context);
return holder;
}
//Set Data inside RecyclerView
#Override
public void onBindViewHolder(ReportViewHolder holder, int position) {
ChoosedSubject current = data.get(position);
Grades grades = new Grades(context);
Resources resources = context.getResources();
int iconColor;
Drawable icon;
icon = ContextCompat.getDrawable(context, dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getChoosedIcon());
if (dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getChoosedIcon() != R.drawable.subject_default) {
iconColor = resources.getColor(dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getChoosedColor());
icon.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
holder.icon.setBackground(icon);
} else {
holder.icon.setImageResource(R.drawable.subject_default);
}
holder.subject.setText(current.getName().toString());
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMinimumFractionDigits(0);
formatter.setMaximumFractionDigits(0);
String output = formatter.format(dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getAverage());
int formattedValue = Integer.valueOf(output);
//CHANGING COLOR DEPENDING ON VALUE
int boxColor = 0;
Drawable box = ContextCompat.getDrawable(context, R.drawable.markbox);
Drawable boxBorder = ContextCompat.getDrawable(context, R.drawable.markbox_border);
if (formattedValue >= 10) {
boxColor = resources.getColor(R.color.positive);
} else if (formattedValue >= 4 && formattedValue <= 9) {
boxColor = resources.getColor(R.color.neutral);
} else if (formattedValue < 4) {
boxColor = resources.getColor(R.color.negative);
}
box.setAlpha(204);
box.setColorFilter(boxColor, PorterDuff.Mode.SRC_IN);
boxBorder.setColorFilter(boxColor, PorterDuff.Mode.SRC_IN);
holder.markbox.setImageDrawable(box);
holder.markboxBorder.setImageDrawable(boxBorder);
holder.average.setText(output);
holder.average.setTypeface(EasyFonts.robotoBlack(context));
}
#Override
public int getItemCount() {
return data.size();
}
public class ReportViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView subject;
ImageView icon;
ImageView markbox;
ImageView markboxBorder;
TextView average;
public ReportViewHolder(View itemView) {
super(itemView);
subject = (TextView) itemView.findViewById(R.id.report_subject);
icon = (ImageView) itemView.findViewById(R.id.report_icon);
markbox = (ImageView) itemView.findViewById(R.id.report_markbox);
markboxBorder = (ImageView) itemView.findViewById(R.id.report_markbox_border);
average = (TextView) itemView.findViewById(R.id.report_average);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
itemClickListener.onItemClick(v, this.getAdapterPosition());
}
}
}
Knows anybody what to do? Thank you for your help!!!
It's sort of caching. From the Android docs:
if you instantiate two Drawable objects from the same image resource, then change a property (such as the alpha) for one of the Drawables, then it will also affect the other. So when dealing with multiple instances of an image resource, instead of directly transforming the Drawable, you should perform a tween animation.
Drawable.mutate() after creating should fix the issue.
A mutable drawable is guaranteed to not share its state with any other drawable. This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification.
Something like this:
Drawable box = ContextCompat.getDrawable(context, R.drawable.markbox).mutate();
Drawable boxBorder = ContextCompat.getDrawable(context, R.drawable.markbox_border).mutate();
Thanks to Sergey that guided me to the solution. I share what I did in onBindViewHolder method.
final Drawable drawable = ContextCompat.getDrawable(mContext, R.drawable.ic_icon).mutate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
holder.image.setBackground(drawable);
} else {
holder.image.setBackgroundDrawable(drawable);
}
TL;DR. If you are worried about performance and still want some caching, use TintedIconCache - a single class you can grab from this gist.
TintedIconCache cache = TintedIconCache.getInstance();
Drawable coloredIcon = cache.fetchTintedIcon(context, R.drawable.ic, R.color.color));
How TintedIconCache works?
It manages a cache such that only one instance of a uniquely tinted drawable is kept into memory. It should be fast, and memory efficient.
// Get an instance
TintedIconCache cache = TintedIconCache.getInstance();
// Will be fetched from the resources
Drawable backIcon = cache.fetchTintedIcon(context, R.drawable.icon, R.color.black));
// Will be fetched from the resources as well
Drawable bleuIcon = cache.fetchTintedIcon(context, R.drawable.icon, R.color.bleu));
// Will be fetched from the cache!!!
Drawable backIconTwo = cache.fetchTintedIcon(context, R.drawable.icon, R.color.back));
Check this answer for more details.
Consider looking at the gist to see how it works under the hood.
I'm currently trying to get the hang of android developemnt and so far its been going good(Well until now). I am currently playing around with Custom Cursor adapters for my grid view. I read using a cursor adapter takes the load of the main UI thread which sounds efficient, so i tried to implement my own cursor adapter as follows
public class VideoListAdapter extends SimpleCursorAdapter{
private Context ctx;
private int parent_layout_id;
ArrayList<VideoModel> videoList = new ArrayList<VideoModel>();
public VideoListAdapter(
Context ctx,
int parent_layout_id,
Cursor c,
String[] fromColumns,
int[] toView)
{
super(ctx,parent_layout_id,c,fromColumns,toView);
this.ctx = ctx;
this.parent_layout_id = parent_layout_id;
}
#Override
public void bindView(View v, Context context, Cursor c) {
//gets title column
int titleColumn = c.getColumnIndex(MediaStore.Video.Media.TITLE);
String title = c.getString(titleColumn);
TextView titleView =(TextView) v.findViewById(R.id.video_title);
titleView.setText(title);
//gets duration
int durationColumn = c.getColumnIndex(MediaStore.Video.Media.DURATION);
String duration = c.getString(durationColumn);
TextView durationView = (TextView) v.findViewById(R.id.video_date);
durationView.setText(duration);
//gets Thumb
int videoDataColumn = c.getColumnIndex(MediaStore.Video.Media.DATA);
String videodataUrl = c.getString(videoDataColumn);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(videodataUrl);
Bitmap bm = mmr.getFrameAtTime(1000);
ImageView imgv = (ImageView) v.findViewById(R.id.video_thumb);
imgv.setScaleType(ImageView.ScaleType.CENTER_CROP);
imgv.setImageBitmap(bm);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
//get layout inflater
final LayoutInflater li=LayoutInflater.from(context);
View v = li.inflate(parent_layout_id,parent,false);
//gets title column
int titleColumn = c.getColumnIndex(MediaStore.Video.Media.TITLE);
String title = c.getString(titleColumn);
TextView titleView =(TextView) v.findViewById(R.id.video_title);
titleView.setText(title);
//gets duration
int durationColumn = c.getColumnIndex(MediaStore.Video.Media.DURATION);
String duration = c.getString(durationColumn);
TextView durationView = (TextView) v.findViewById(R.id.video_date);
durationView.setText(duration);
//gets Thumb
int videoDataColumn = c.getColumnIndex(MediaStore.Video.Media.DATA);
String videodataUrl = c.getString(videoDataColumn);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(videodataUrl);
Bitmap bm = mmr.getFrameAtTime(1000);
ImageView imgv = (ImageView) v.findViewById(R.id.video_thumb);
imgv.setScaleType(ImageView.ScaleType.CENTER_CROP);
imgv.setImageBitmap(bm);
return v;
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
return super.runQueryOnBackgroundThread(constraint);
}
}
What i'm trying to achieve is to fetch list of video files from the external media storage and display them in a gridview. the standard thumbnails are abit too small for the style of layout i have in mind so i used the MediaMetadataRetriever to fetch frames from each of the video files and used that as thumbnails. Like so
When i ran the application the scroll performance of my gridView worsened. What am I missing. i know the SimpleCursorAdapter class has an overridable method runQueryOnBackgroundThread but i dont even know what to put in there or how to use it. Any pointers will be very much appreciated and forgive my smudge face ;)
First of all bind your Gridview using ViewHolder and second one is save your thumb(bitmap) in existing arrayList so you can not do have to same process while scrolling.
I have a ListView which is supposed to become a menu with two drawables and two text views per row.
Activity Code:
ArrayList<MenuItem> itemArray = new ArrayList<MenuItem>();
itemArray.add(new MenuItem("Headertexxt", "subbtexdt"));
itemArray.add(new MenuItem("asf", "asf"));
ListView listView = (ListView) findViewById(R.id.listViewCM);
String[] array = getResources().getStringArray(R.array.buttonsCM);
int[] images = new int[] { R.drawable.btn_car, R.drawable.btn_star, R.drawable.btn_bag};
listView.setAdapter(new HomeScreenButtonsAdapterSubtext(this, R.layout.row,
itemArray, images, R.drawable.list_arrow));
Utils.setListViewHeightBasedOnChildren(listView);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
findViewById(R.id.buttonCreditCompilation).performClick();
break;
case 1:
findViewById(R.id.buttonYourCredits).performClick();
break;
}
}
});
Adapter code:
public class HomeScreenButtonsAdapterSubtext extends ArrayAdapter<MenuItem> {
private Drawable[] drawables;
private Drawable arrowDrawable;
private ArrayList<MenuItem> items;
public HomeScreenButtonsAdapterSubtext(Context context, int resourceId,
ArrayList<MenuItem> items, int[] images, int arrowImage) {
super(context, resourceId, items);
this.items = items;
Resources resources = context.getResources();
if (images != null) {
drawables = new Drawable[images.length];
int i = 0;
for (int id : images) {
Drawable drawable = resources.getDrawable(id);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
drawables[i++] = drawable;
}
}
arrowDrawable = resources.getDrawable(arrowImage);
arrowDrawable.setBounds(0, 0, arrowDrawable.getIntrinsicWidth(),
arrowDrawable.getIntrinsicHeight());
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
if (v instanceof TextView) {
Drawable dr = drawables != null ? drawables[position %
drawables.length] : null;
((TextView) v).setCompoundDrawables(dr, null, arrowDrawable, null);
Utils.setFont((TextView) v);
}
// View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
MenuItem station = items.get(position);
if (station != null) {
TextView tt = (TextView) v.findViewById(R.id.headerText);
TextView bt = (TextView) v.findViewById(R.id.subText);
if (tt != null) {
tt.setText(station.getHeaderText());
}
if (bt != null) {
bt.setText(station.getSubText());
}
}
return v;
}
The problem I have right now is that I can't set the listview height based on the children. I'm trying to do that here: Utils.setListViewHeightBasedOnChildren(listView); but getting the error: arrayadapter requires the resource id to be a textview at this row. Does anyone know a solution for this?
Can I use some other method for setting the ListView height?
Thanks
but getting the error: arrayadapter requires the resource id to be a
textview at this row.
R.layout.row is a layout file which it doesn't have just a TextView. If you call the super constructor you have used and you also call the super.getView(in the getView method) method in the adapter, then ArrayAdapter will complain as it expects a single widget in the layout file passed to it(a single TextView).
I don't understand why you have that piece of code in the getView method(with the super call) when you know precisely that the row can't be an instance of Textview .
I'm not sure about setting the height of the ListView either, if you're trying to show all the rows of the ListView, don't do it(as you make the ListView basically useless). If you still want to do this, then it's better to lose the ListView and build the row layouts manually.
In fact it does not really make sense to set the height of ListView depending on its content.
Because the whole point of a ListView is to make its content scrollable (however big it is)...so it is supposed to have a fixed height.