Changing the specific item in row in recycler view - java

How to change specific view in row in RecyclerView. Adapter.notifyDataSetChanged or Adapter.notifyItemChanged updating row. But I need change the specific view in row, without touching other views in this row.

First of all, use Glide (By Google) instead of Picasso. It's more efficient.
Secondly, your device won't download the same image again if it's already present inside your Cache memory.
Now,
Simply change the data inside your List and then update your adapter or recycler view.
Inside your AdapterClass
Create an Interface, let's say
public interface TheUpdater{
public void updateMyAdapter(int position);
}
Then implement this interface in your Activity and override this method.
Now, in order to get the position of the View.
You can override onClick() of a View (Button or even the Whole Parent View i.e. Layout) and perform the following statement.
mTappedPosition = getAdapterPosition();
listener.updateMyAdapter(mTappedPosition); //Update the adapter
Where mTappedPosition is your global variable.
Inside your Activity
#Override
updateMyAdapter(int position){
---- //Do stuff
mAdapter.notifyItemSetChanged(position);
}

you can use following code
MyRecyclerAdapter.ViewHolder viewHolder= (MyRecyclerAdapter.ViewHolder) recycleView.findViewHolderForAdapterPosition(1);
viewHolder.txtView.SetText("Some Text");

I think to avoid the image loading issue you have to use image caching technique. So that already loaded image won't be load again.
or
If the image is already loaded and each and every row is showing same image set then you can keep a boolean flag to your itemModel (The dto which has the adapter item's data ). and change that model and then call
yourListToAdapter(index).setFlag(showImage1); // showImage1 boolean flag
yourAdapter.notifyItemChanged(index);

Related

Is there a way to add a button or anything under a RecyclerView

The RecyclerView have to load n number of items initially, when the user scroll to the bottom of it I want a button or any other View on the bottom so that the user can click on it and a method to add n more items is triggered.
I'm new to android app development and I really need help, Thanks.
Android recyclerview is used to display large amount of items on
screen, but with improved performance and other benefits. RecyclerView
in Android uses an adapter to represent the information we want to
show as list. The data to be displayed is sent to adapter, which handles the view.
Coming to your custom approach of adding a button. You can control the amount of data being sent to adapter at beginning. Considering you have a server that will send data when requested with a tweak to send data in set of row. Add a floating button which is displayed when user reaches end of recyclerview, this button requests further data from server and send a signal to adapter that your variable containing the data has been updated. So, this will add data to your view and you can scroll further until that data ends.
So you require to design your server for custom data range request.
Variable to keep track of current data range present.
Code to check end of RecyclerView data feed.
function to request more data on button click and signal adapter for update.
You can search endless scrolling using RecyclerView to get tutorial
related to this.
what you are asking is basically an endless scrolling recyclerview with a loaderview at the bottom that accepts click to load additional data.
You have to make use of multiple viewType in the RecyclerView.Adapter
I encourage you to search more before asking a new question as there are countless tutorials for this and similar questions on stackOverflow. Here's a link to an example on stack on how to implement multiple viewTypes.
I'll share some points on one of the ways to achieve what you are looking for.
First in your adapter you need to declare two constants
private final int VIEW_ITEM = 0;
private final int VIEW_LOADER = 1;
and a boolean showLoadMore
create a public method
public void showLoader(boolean status) {
this.showLoadMore = status;
}
this can be used to show/hide loader from your activity
You need to override getItemCount() method to return the correct number of rows as it keeps changing base on your loader
#Override
public int getItemCount() {
if (yourList.isEmpty()) {
return 0;
} else {
if (showLoadMore)
return yourList.size() + 1;
else
return yourList.size();
}
}
Override getItemViewType(int position), since your loader needs to be at the bottom , it should
return (position == yourList.size() && showLoadMore) ? VIEW_LOAD : VIEW_ITEM;
Next as shown in the link i shared above, you need to inflate your layout in onCreateViewHoldermethod and then bind your layout in onBindViewHolder method based on your viewTypes. you can simply use if else condition as this case only has 2 viewtypes.
Now in your activity after you setAdapter on the recyclerview and have fetched the n data set adapter.showLoader(true) to show the loader view and notifyDataSetChanged(). You can customize the loaderview to show progress bar or however you like , on click fetch the next set of data, if new count is less than required count count <= n then make set adapter's showLoader(false) and adapter.notifyDataSetChanged() this will hide your loader view after adding the data.
Hope this answer helps you in some way,
Meanwhile here's a tutorial from web implementing endless scrolling recyclerview in another way

Lazy load recyclerview images from mediastore

I want to load images I have in my recyclerview after 350ms and I think I'm using wrong method for that. This is my code:
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.songView.setText(objects_.get(position).getAlbum());
holder.artistView.setText(objects_.get(position).getArtist());
holder.cover.setImageDrawable(context.getResources().getDrawable(R.drawable.song));
if(holder.r!=null){
handler.removeCallbacks(holder.r);
}
holder.r = new Runnable() {
#Override
public void run() {
Drawable img = Drawable.createFromPath(objects_.get(position).getCover());
if (img != null) {
holder.cover.setImageDrawable(img);
Bitmap bitmap = ((BitmapDrawable) img).getBitmap();
Palette palette = Palette.from(bitmap).generate();
Palette.Swatch p = palette.getVibrantSwatch();
if (p != null) {
holder.albumholder.setBackgroundColor(p.getRgb());
}
}
}
};
handler.postDelayed(holder.r,300);
}
But I have a problem with this. when I fast scroll recyclerview images of previous items loads at first then changes to new items picture. You can see result in GIF from this link:
http://8pic.ir/images/nkaaeqdvigqy4c6g2h5n.gif
what can I do to fix it?
I don't understand why do you need this 350ms delay but if you want to do it try some other approach:
Your problem is linked to the fact that RecyclerView recycles (suprise...) item views instead of creating new. That means that you will see previously load image, and if you have posted delayed task (handler.postDelayed(...)) it will be executed event if view was recycled, so wrong image can be loaded for particular list item.
General problem is that you're doing to much work in your onBindViewHolder. You should try to reduce computations here, or at least try to move them to some separate thread (handler is using this same thread it was created - in this case the UI thread).
Create handler inside view holder instead of inside your adapter.
Set some placeholder as an image
clear tasks (messages) currently waiting to be executed:
holder.handler.removeCallbacksAndMessages(null);
post load task (handler.postDelayed(...))
It's also possible that all you need is some nice image loading library like Picasso.
As we know recycler view reuse same view during scroll so it is displaying older images while you lazy load for some moments and after that it will update your imageview.
Solution is simply reset your imageview to default( ie white background or default image) state before lazyload .
You should avoid setimageresource() ,instead use setimagedrawable()
setImageResource Vs setDrawable
Instead of using the runnable for loading images, use AsyncTask. You'll need to execute a separate AsyncTask for each image. This AsyncTask will be saved as a WeakReference inside the drawable object which will be set in the respective ImageView.
WeakReferences are used for mapping purposes. The advantage of using WeakReferences is that the entries can be removed from the memory as soon as they are not required by your app. They will be removed by the Garbage Collector. We need to use the WeakReferences because there can be a large number of AsyncTasks getting executed (equal to the number of items present in the RecyclerView) at the same time and Android system or your app will not be able to identify which AsyncTask belongs to which ImageView without these references.
Now, as the drawable is set in the ImageView, it will contain the WeakReference to its respective AsyncTask. This AsyncTask will process the respective bitmap or drawable to be set on the ImageView and all this will be done off the UI thread.
In order to set the AsyncTask in the drawable object, you'll need to create a custom drawable class which will work as a Drawable object but will have the benefit of attaching an AsyncTask to it.
This Drawable object and AsyncTask will take care of loading the images.
The complete explanation and code for this concept has been provided on Android Developers website. Visit the link: http://developer.android.com/training/displaying-bitmaps/process-bitmap.html

android ViewFlipper - slideshow of images with async image loading

I'm implementing a custom view where I use ViewFlipper which shows my custom View that consists of RelativeLayout parent and two children - ImageView and ProgressBar.
Initially I display thumbnail images in the ViewFlipper and when the particular child View is shown, I want to inintiate the full size image download for display. The problem is that in ViewFlipper I need to add all child View at the beginning (in onCreate of my Acticity). There are situations where my gallery consists of > 200 images and I do not want to initiate download of all the fullsize images because user may not navigate to all pages of the ViewFlipper at all. Is there a way to be notified in ViewFlipper that a particular view gets activated? I can hardly see it in this class.
Regards
It seems that there is no callback to inform you that a view gets activated; you need to implement this yourself. It's not hard: you need to subclass ViewFlipper and create a custom listener ViewFlipperListener with a method public void onViewFlip(ViewFlipper view, View newView).
Then override the ShowNext() and ShowPrevious() methods inherited from ViewAnimatior. In these methods, call their super counterparts and then call the listener's onViewFlip callback passing in the new view (which you can get with getCurrentView()).
Hope this helps.

List Adapter and getView function explanation

I'm thoroughly confused about the life cycle of list view. More specifically, what does the list adapter do exactly? Does it just provide data to the given view? And when/where does the getView() function gets called? And what purpose does this getView() function provide? From just looking at the code, it looks like getView() is "assigning" data to the view to be displayed. I'd like to be able to use list views without having to memorize, do this and then this in order for it to work. I'd much rather understand it so I can use it properly. Someone please help me understand all of this.
Also, if someone can explain to me.. what's the difference between BaseAdapter and ArrayAdapter? and any other kind of adapters that comes with Android.
What I have understood is your adapter constructor instantiated by activity and then on activity launch the getView() method is called. the {#param position, view, viewGroup}
position: it refers to the position of the view as given by adapter. Please Note it is different from the position in {OnItemClick(AdapterView adapter, View v, int position,long id)} here position is the list item position. The {position} in {getView()} changes after particular object in the list are displayed again for eg. when you scroll.
view: the view here is the view you want to be presented through getView(). It can be a particular XML layout for each row. So this states clearly that getView is called to plot every row. this view needs to be valid one or another layout (LinearLayout by default) will be selected to maintain uniqueness.
viewgroup: as you might know and as name says will be the container of your #param:view
any other point is appreciated.
getView() fills in the data into the item's view with the given index. The view which is given as a parameter may be a pre-inflated view. If it is not, you have to infalte it yourself.
An ArrayAdapter simply calls setText on the given view with the result of toString() of the object with the respective index from the array. If you override it, you can do more complex stuff, like assigning a picture or filling in more TextViews.
I recommend the following tutorial: http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/
Hi list adaper provides view for listview.
when user scrolls listview at that time getview is called.
getview is used to populate your view with data hence the name adapter.
The Adapter does all the "rember to do this" for you. If you change a list view's backing data structure through the adapter's methods (e.g. "add()") it will fire all the datachanged and update events you'll need for the list view to show the new state of the data.

How to get getSelectedView() to work in GridView?

I have a GridView in a layout. It is populated with Foo views by the activity using a extended BaseAdapter.
When I select an item in this grid it gets orange tinted (thus selected). That's nice. But I want to access this selection from outside the GridView and it's parent activity: from within another View higher in the layout hierarchy. I therefor call upon gridView.getSelectedItem(). However it always returns null.
How could I get this to work?
"Selection" doesn't mean the same thing in AndroidOS as it does in other UIs. In particular, there isn't any "selected item" when you're in touch mode. You probably need to use a click listener instead of relying on there being a "selected item". See this article for details.
You can use the following to get the view:
View childView = gridView.getChildAt(position - gridView.getFirstVisiblePosition());

Categories