I'm trying to create a RecyclerView with ImageViews. Here is what I get:
As you can see all the artist covers are messed up and in the wrong order. If I scroll or reload, the respective images might change.
Here is my adapter onBindViewHolder:
public class ArtistsAdapter extends RecyclerView.Adapter<ArtistViewHolder> implements ListPreloader.PreloadModelProvider {
private static final String TAG = ArtistsAdapter.class.getSimpleName();
private final LayoutInflater mInflater;
private final GlideRequest<Bitmap> fullRequest;
ArtistsAdapter(Context context) {
this.mContext = context;
this.artists = new ArrayList<>();
this.mInflater = LayoutInflater.from(context);
this.fullRequest = GlideApp.with(context).asBitmap();
}
private final Context mContext;
public List<CompactdArtist> getArtists() {
return artists;
}
void swapArtists (List<CompactdArtist> artists) {
this.artists.clear();
this.artists.addAll(artists);
notifyDataSetChanged();
}
private final List<CompactdArtist> artists;
#Override
public ArtistViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_artist_item, parent, false);
return new ArtistViewHolder(view);
}
#Override
public void onViewRecycled(ArtistViewHolder holder) {
super.onViewRecycled(holder);
Log.d(TAG, "onViewRecycled: ");
GlideApp.with(mContext).clear(holder.artistImageView);
holder.artistImageView.setImageDrawable(null);
}
#Override
public void onBindViewHolder(final ArtistViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder: " + position);
final CompactdArtist current = artists.get(position);
// holder.setIsRecyclable(false);
holder.artistImageView.setImageDrawable(null);
try {
fullRequest.load(new MediaCover(current))
.fallback(ImageUtils.getFallback(mContext))
.into(new ImageViewTarget<Bitmap>(holder.artistImageView) {
#Override
protected void setResource(#Nullable Bitmap resource) {
if (resource == null) {
// holder.setIsRecyclable(true);
return;
}
holder.artistImageView.setImageBitmap(resource);
int color = Palette.from(resource).generate().getMutedColor(0xFFFFFF);
try {
current.fetch();
} catch (CouchbaseLiteException e) {
e.printStackTrace();
holder.artistNameText.setText(R.string.unknown_artist_name);
}
holder.artistBackground.setBackgroundColor(color);
holder.bindArtist(current);
holder.artistSub.setText(current.getAlbumCount() + " albums");
holder.artistNameText.setText(current.getName());
// holder.setIsRecyclable(true);
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
super.onLoadCleared(placeholder);
// holder.setIsRecyclable(true);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public long getItemId(int position) {
return artists.get(position).getId().hashCode();
}
#Override
public int getItemCount() {
return this.artists.size();
}
#NonNull
#Override
public List getPreloadItems(int position) {
return this.artists.subList(position, position + 1);
}
#Nullable
#Override
public RequestBuilder<?> getPreloadRequestBuilder(Object item) {
MediaCover cover = (MediaCover) item;
return fullRequest.clone().thumbnail(0.2f).load(cover);
}
}
Here is code in my fragment container:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_artists, container, false);
mArtistRecyclerView = rootView.findViewById(R.id.artists_recyclerview);
LinearLayoutManager layoutManager = new GridLayoutManager(getContext(), 3);
mArtistRecyclerView.setLayoutManager(layoutManager);
mArtistsAdapter = new ArtistsAdapter(getActivity());
mArtistRecyclerView.setAdapter(mArtistsAdapter);
mArtistRecyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() {
#Override
public void onViewRecycled(RecyclerView.ViewHolder holder) {
ArtistViewHolder artistViewHolder = (ArtistViewHolder) holder;
GlideApp.with(holder.itemView).clear(artistViewHolder.getArtistImage());
}
});
FixedPreloadSizeProvider<MediaCover> coverSizeProvider = new FixedPreloadSizeProvider<>(64, 64);
RecyclerViewPreloader<MediaCover> preloader = new RecyclerViewPreloader<MediaCover>(GlideApp.with(this), mArtistsAdapter, coverSizeProvider, 2);
return rootView;
}
As a bonus, I add the fetcher for my MediaCover:
/**
* Created by vinz243 on 13/12/2017.
*/
public class MediaCoverFetcher implements DataFetcher<InputStream> {
private final MediaCover mediaCover;
private boolean cancelled = false;
private InputStream stream;
public MediaCoverFetcher(MediaCover mediaCover) {
this.mediaCover = mediaCover;
}
#Override
public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
CompactdArtwork artwork = mediaCover.getArtwork();
try {
stream = artwork.getImage(ArtworkSize.LARGE);
if (cancelled) {
callback.onLoadFailed(new RuntimeException("Cancelled"));
} else {
callback.onDataReady(stream);
}
} catch (NullPointerException e) {
callback.onLoadFailed(e);
}
}
#Override
public void cleanup() {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void cancel() {
cancelled = true;
}
#NonNull
#Override
public Class<InputStream> getDataClass() {
return InputStream.class;
}
#NonNull
#Override
public DataSource getDataSource() {
return DataSource.LOCAL;
}
}
I guess it comes from the recycling part, but I don't know how to fix the behavior. As you may see in the code, I tried setIsRecyclable but I would get errors saying unmatched calls and it wouldn't fix it
You should try to change a couple of things :
move your setters on your ArtistViewHolder object in the setResource function
define your CompactdArtist variable as a final
#Override
public void onBindViewHolder(final ArtistViewHolder holder, int position) {
Log.d(TAG, "onBindViewHolder: " + position);
final CompactdArtist current = artists.get(position);
// holder.setIsRecyclable(false);
holder.bindArtist(artists.get(position));
holder.artistImageView.setImageDrawable(null);
try {
current.fetch();
fullRequest.load(new MediaCover(current))
.fallback(ImageUtils.getFallback(mContext))
.into(new ImageViewTarget<Bitmap>(holder.artistImageView) {
#Override
protected void setResource(#Nullable Bitmap resource) {
if (resource == null) {
// holder.setIsRecyclable(true);
return;
}
holder.artistImageView.setImageBitmap(resource);
int color = Palette.from(resource).generate().getMutedColor(0xFFFFFF);
holder.artistBackground.setBackgroundColor(color);
// holder.setIsRecyclable(true);
holder.artistNameText.setText(current.getName());
holder.artistSub.setText(current.getAlbumCount() + " albums");
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
super.onLoadCleared(placeholder);
// holder.setIsRecyclable(true);
}
});
} catch (CouchbaseLiteException e) {
e.printStackTrace();
holder.artistNameText.setText(R.string.unknown_artist_name);
} catch (IOException e) {
e.printStackTrace();
}
}
I assume that the way you load your images is asynchronous, so in this case your problems resides in the fact that you set your variables as if they were in a synchronous process, that's why you get your information displayed on the wrong blocks.
Related
This kind of crash happens too much!!!
Found this problem today.
I am getting the above mention crash in a few devices lately. I think this has something to do with RecyclerView inside of a ScrollView??
But I am not sure, as it was working fine for months but suddenly started to see it. Recycler View Inconsistency Detected error, coming while scrolling fast or scrolling while loading more items.
I get it in Fabric Crashlytics.
Fatal Exception: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{2e20039 position=4 id=-1, oldPos=-1, pLpos:-1 no parent} android.support.v7.widget.RecyclerView{9d0ee32 VFED..... .F...... 0,0-1440,191 #7f0a037d app:id/recylerCategoryList}, adapter:ahs#8a75b3d, layout:android.support.v7.widget.LinearLayoutManager#b3c9f32, context:com.ui.activity.NEWBusinessCardMainActivity#fe48a6e
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition + 5715(RecyclerView.java:5715)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline + 5898(RecyclerView.java:5898)
at android.support.v7.widget.GapWorker.prefetchPositionWithDeadline + 286(GapWorker.java:286)
at android.support.v7.widget.GapWorker.flushTaskWithDeadline + 343(GapWorker.java:343)
at android.support.v7.widget.GapWorker.flushTasksWithDeadline + 359(GapWorker.java:359)
at android.support.v7.widget.GapWorker.prefetch + 366(GapWorker.java:366)
at android.support.v7.widget.GapWorker.run + 397(GapWorker.java:397)
at android.os.Handler.handleCallback + 751(Handler.java:751)
at android.os.Handler.dispatchMessage + 95(Handler.java:95)
at android.os.Looper.loop + 154(Looper.java:154)
at android.app.ActivityThread.main + 6682(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run + 1520(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main + 1410(ZygoteInit.java:1410)
Adapter:
public class CategoryHomeAdapter extends RecyclerView.Adapter<CategoryHomeAdapter.ItemViewHolder> {
public static final String TAG = "CategoryAdapter";
private Context activity;
private ArrayList<NEWCategoryList> categoryList = new ArrayList<>();
private ArrayList<NEWCategoryList> originalList = new ArrayList<>();
private RecyclerViewItemInterface viewItemInterface;
int i = 0;
int defaultSelectedValue;
private int selectedPosition = 0;
public CategoryHomeAdapter(Context activity, ArrayList<NEWCategoryList> categoryList) {
this.categoryList = categoryList;
this.activity = activity;
this.defaultSelectedValue = defaultSelectedValue;
Log.i(TAG, "categoryList Size :" + categoryList.size());
}
public void setViewItemInterface(RecyclerViewItemInterface viewItemInterface) {
Log.i(TAG, "setViewItemInterface: ");
this.viewItemInterface = viewItemInterface;
}
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_home_category_list, parent, false);
return new ItemViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull final ItemViewHolder holder, final int position) {
try {
final NEWCategoryList category = categoryList.get(position);
holder.categoryName.setText(category.getTagName());
holder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i(TAG, "[onClick] getAdapterPosition:" + holder.getAdapterPosition());
try {
if (holder.getAdapterPosition() != -1 && category.getSubCategoryTagId() != null) {
Log.i(TAG, "onClick: Category ID selected :" + category.getSubCategoryTagId());
if (categoryList != null && categoryList.size() > 0) {
for (NEWCategoryList newList : categoryList) {
if (!newList.getSubCategoryTagId().equals(category.getSubCategoryTagId())) {
Log.i(TAG, "onClick: FALSE");
holder.CategoryImage.setVisibility(View.GONE);
newList.setSelected(false);
} else {
holder.CategoryImage.setVisibility(View.VISIBLE);
Log.i(TAG, "onClick: TRUE");
newList.setSelected(true);
}
}
}
Log.i(TAG, "Category Name : " + category.getTagName() + "Category Id : " + category.getSubCategoryTagId());
if (viewItemInterface != null) {
viewItemInterface.onItemClick(holder.getAdapterPosition(), categoryList.get(holder.getAdapterPosition()));
}
} else {
Log.i(TAG, "onClick: category Id is Wrong....");
}
} catch (Throwable e) {
// e.printStackTrace();
AppUtils.throwFatalException(e);
}
}
});
} catch (Exception e) {
// e.printStackTrace();
AppUtils.throwFatalException(e);
}
}
public void changeImage(int index) {
categoryList.get(index).setSelected(true);
notifyItemChanged(index);
}
#Override
public int getItemCount() {
return this.categoryList.size();
}
class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView categoryName;
private ImageView CategoryImage;
public ItemViewHolder(View view) {
super(view);
this.categoryName = view.findViewById(R.id.textCaregoryname);
this.CategoryImage = view.findViewById(R.id.CategoryImage);
}
}
public void makeSearchList() {
this.originalList.clear();
this.originalList.addAll(this.categoryList);
}
}
Fragment:
public class Fragment extends DefaultFragment implements OnLoadMoreListener, RecyclerViewItemInterface {
#Override
public void onAttach(Context context) {
super.onAttach(context);
Log.e(TAG, "****** onAttach *******");
this.activity = baseActivity;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_sample_img_list_home, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
populateList();
populatedCategoryList();
loadCategory();
}
private void populateList() {
if (AppUtils.isValidContext(activity) && isAdded()) {
try {
sampleJsonList.clear();
LinearLayoutManager mLayoutManager = new LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false);
listBgImg.setLayoutManager(mLayoutManager);
bgImageAdapterNEW = new CategoryImageAdapterNew(activity, listBgImg, new GlideImageLoader(activity.getApplicationContext()), sampleJsonList, freeSampleList);
listBgImg.setAdapter(bgImageAdapterNEW);
bgImageAdapterNEW.setViewItemInterface(new RecyclerViewItemInterface() {
bgImageAdapterNEW.setPageAppendListener(new PageAppendListener() {
#Override
public void onPageAppendClick(final int page) {
Log.i(TAG, "onPageAppendClick : " + page);
listBgImg.post(new Runnable() {
public void run() {
// Remove Append Button
try {
Log.i(TAG, "List Size : " + sampleJsonList.size());
sampleJsonList.remove(sampleJsonList.size() - 1);
bgImageAdapterNEW.notifyItemRemoved(sampleJsonList.size());
onLoadMore(page, true);
} catch (Throwable e) {
e.printStackTrace();
}
}
});
}
#Override
public void onPageAppendClick() {
Log.i(TAG, "btnLoadMore button Click ");
}
#Override
public void showBottomToTop(boolean isShow) {
}
});
bgImageAdapterNEW.setOnLoadMoreListener(this);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
}
private void populatedCategoryList() {
if (AppUtils.isValidContext(activity) && isAdded()) {
try {
Log.i(TAG, "populatedCategoryList: ");
categoryList.clear();
LinearLayoutManager mLayoutManager = new LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false);
CategoryRecylerView.setLayoutManager(mLayoutManager);
categoryHomeAdapter = new CategoryHomeAdapter(activity, categoryList);
categoryHomeAdapter.setViewItemInterface(this);
CategoryRecylerView.setAdapter(categoryHomeAdapter);
} catch (Throwable e) {
e.printStackTrace();
}
}
}
private void loadCategory() {
try {
categoryList.clear();
ArrayList<NEWCategoryList> localList = new ArrayList<>();
String s = SessionManager.getInstance().getKeyCatelogTagtemplate();
Log.i(TAG, "loadCategory: " + s);
if (!s.isEmpty()) {
CategorySampleData data = new Gson().fromJson(s, CategorySampleData.class);
if (data != null && data.getCategorylist() != null && data.getCategorylist().size() > 0) {
localList = data.getCategorylist();
}
}
} catch (JsonSyntaxException e) {
e.printStackTrace();
AppUtils.throwFatalException(e);
}
}
/*Recyler View */
#Override
public void onItemClick(int position, Object obj) {
try {
Log.i(TAG, "onItemClick: Object");
if (categoryHomeAdapter != null && obj instanceof NEWCategoryList) {
if (((NEWCategoryList) obj).getSubCategoryTagId() != null) {
categoryHomeAdapter.notifyDataSetChanged();
NEWCategoryList CategoryList = (NEWCategoryList) obj;
if (subCategoryId != CategoryList.getSubCategoryTagId()) {
subCategoryId = CategoryList.getSubCategoryTagId();
Log.i(TAG, "onItemClick: subCategoryId" + subCategoryId);
if (!sampleJsonList.isEmpty()) {
sampleJsonList.clear();
if (bgImageAdapterNEW != null) {
bgImageAdapterNEW.notifyDataSetChanged();
}
}
tagName = CategoryList.getTagName();
Log.i(TAG, "onItemClick: Tag Name is : - " + tagName);
cancelOldRequest();
getAllSample(1, true, subCategoryId, tagName, false);
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
How can I fix this?
In my project, there is need of searching data from server using keyword. After search, i am displaying results using RecyclerView . While searching fast, the data in RecyclerView is duplicating. If searching slowly, it's working fine. Any suggestions are appreciated. Thank you.
The below code for making server call:
private void callSearchUserApi(final String searchText, int currentPage, boolean clearData) {
isApiCallInProcess = true;
String URL = "userinfo/api/v1/user-search/" + "?page=" + currentPage;
if (!Connectivity.isConnected(activity)) {
Common.snackBarNoConnection(activity, activity.getString(R.string.no_conection));
//setOnProgressbarVisibility(View.GONE);
return;
}
if (clearData) {
globalSearchUsersModelList.clear();
//BS globalSearchUserResultsAdapter.notifyDataSetChanged();
}
ApiInterface apiCall = ApiClient.getApiService(activity);
final Call<SearchUsersModel> globalUserSearchApiCall = apiCall.searchUser(
URL,
searchText);
globalUserSearchApiCall.enqueue(new Callback<SearchUsersModel>() {
#Override
public void onResponse(Call<SearchUsersModel> call, Response<SearchUsersModel> response) {
if (response.isSuccessful() && response.body().getStatus().equalsIgnoreCase(Common.SUCCESS_RESPONSE)) {
//BS globalSearchUsersModelList.addAll(response.body().getData().getData());
for (int i = 0; i < response.body().getData().getData().size(); i++) {
SearchUsersModel.DataBeanX.DataBean dataBean = new SearchUsersModel.DataBeanX.DataBean();
dataBean.setDesignation(response.body().getData().getData().get(i).getDesignation());
dataBean.setFull_name(response.body().getData().getData().get(i).getFull_name());
dataBean.setGender(response.body().getData().getData().get(i).getGender());
dataBean.setId(response.body().getData().getData().get(i).getId());
dataBean.setPlace(response.body().getData().getData().get(i).getPlace());
dataBean.setProfile_pic(response.body().getData().getData().get(i).getProfile_pic());
globalSearchUsersModelList.add(dataBean);
/*BS if (!globalSearchUsersModelList.contains(response.body().getData().getData().get(i)))
globalSearchUsersModelList.add(response.body().getData().getData().get(i));*/
}
CURRENT_PAGE = response.body().getData().getPage();
isLoading = false;
if (response.body().getData().isNext() == false)
isLastPage = true;
else
isLastPage = false;
if (globalSearchUsersModelList.size() == 0) {
rv_GlobalsearchList.setVisibility(View.GONE);
rl_placeholderGSPeople.setVisibility(View.VISIBLE);
tv_placeholderGSPeople.setText(activity.getString(R.string.no_search_found) + " " + searchText);
} else {
rv_GlobalsearchList.setVisibility(View.VISIBLE);
rl_placeholderGSPeople.setVisibility(View.GONE);
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
globalSearchUserResultsAdapter.notifyDataSetChanged();
}
});
}
if (searchTextsList.size() > 0) {
String sText = searchTextsList.get(0);
searchTextsList.remove(0);
callSearchUserApi(sText, FIRST_PAGE, true);
} else
isApiCallInProcess = false;
}
#Override
public void onFailure(Call<SearchUsersModel> call, Throwable t) {
isApiCallInProcess = false;
}
});
}
This is my Adapter.
public class GlobalSearchUserResultsAdapter extends RecyclerView.Adapter<GlobalSearchUserResultsAdapter.SearchViewHolder> {
private Context context;
private List<SearchUsersModel.DataBeanX.DataBean> searchUserList;
public GlobalSearchUserResultsAdapter(Context context, List<SearchUsersModel.DataBeanX.DataBean> searchUserList){
this.context = context;
this.searchUserList = searchUserList;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public SearchViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.v("Search", "Adapter Activity : "+context);
View view = LayoutInflater.from(context).inflate(R.layout.global_search_row, parent, false);
return new GlobalSearchUserResultsAdapter.SearchViewHolder(view);
}
#Override
public void onBindViewHolder(GlobalSearchUserResultsAdapter.SearchViewHolder holder, int position) {
if ( searchUserList.get(position).getGender().equals("M")) {
holder.iv_userImage.setBackgroundResource(R.drawable.white_border_with_circle_appblue);
Common.setGlideImage((GlobalSearchActivity)context,
holder.iv_userImage,
/*searchUsersModel*/searchUserList.get(position).getProfile_pic(),
R.drawable.male,
true);
} else if (searchUserList.get(position).getGender().equals("F")) {
holder.iv_userImage.setBackgroundResource(R.drawable.white_border_with_circle_pink);
Common.setGlideImage((GlobalSearchActivity)context,
holder.iv_userImage,
searchUserList.get(position).getProfile_pic(),
R.drawable.female,
true);
} else {
Common.setGlideImage((GlobalSearchActivity)context,
holder.iv_userImage,
searchUserList.get(position).getProfile_pic(),
R.drawable.deafult_profilepic,
true);
}
holder.tv_userName.setText(searchUserList.get(position).getFull_name());
holder.tv_userName.setTypeface(Common
.getFontTypeface(context, GlobalConstants.FONT_AVENIR_MEDIUM));
holder.tv_place.setText(searchUserList.get(position).getPlace());
holder.tv_place.setTypeface(Common
.getFontTypeface(context, GlobalConstants.FONT_AVENIR_MEDIUM));
holder.designation.setText(searchUserList.get(position).getDesignation());
}
#Override
public int getItemCount() {
return searchUserList.size();
}
public class SearchViewHolder extends RecyclerView.ViewHolder{
private ImageView iv_userImage;
private TextView tv_userName;
private TextView tv_place;
private TextView designation;
public SearchViewHolder(View itemView) {
super(itemView);
this.iv_userImage = (ImageView) itemView.findViewById(R.id.imageSearch);
this.tv_userName = (TextView) itemView.findViewById(R.id.nameSearch);
tv_userName.setTypeface(Common.getFontTypeface(context,
GlobalConstants.FONT_AVENIR_MEDIUM));
this.designation = (TextView) itemView.findViewById(R.id.designation);
designation.setTypeface(Common.getFontTypeface(context,
GlobalConstants.FONT_AVENIR_MEDIUM));
this.tv_place = (TextView) itemView.findViewById(R.id.placeSearch);
tv_place.setTypeface(Common.getFontTypeface(context,
GlobalConstants.FONT_AVENIR_LIGHT));
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
context.startActivity(new Intent(context, ProfileActivity.class)//ThirdParty
.putExtra(GlobalConstants.KEY_THIRD_PARTY_ID, searchUserList.get(getAdapterPosition()).getId()));
}
});
}
}
}
You just had to clear the globalSearchUsersModelList list just before for loop, because API call is asynchronous.
globalSearchUsersModelList.clear();// Important one
for (int i = 0; i < response.body().getData().getData().size(); i++) {
// do your stuff
}
I think the issue come from your getItemId implementation. The way you implement it, the recycler view will identify an item according to its position in the list.
If you change this and use unique identification for instance searchUserList.get(position).id (if your User object has an unique ID) the problem should be fixed
You can also add in your activity adapter.setHasStableIds(true)
I created a vocabulary android app where we can add words to favorites by clicking the star icon near the word. On clicking the star icon it changes to solid star icon but if we scroll the RecyclerView than the solid star icon will again change to the normal star icon.
Image before scrolling:
Image after scrolling:
Here is the code:
public class WordListAdapter extends RecyclerView.Adapter<WordListViewHolder> {
TextToSpeech ttsObject;
private List<WordListModel> mWordList;
private Context context;
private Activity activity;
private int result;
public WordListAdapter(TextToSpeech ttsObject, int result) {
this.ttsObject = ttsObject;
this.result = result;
}
public WordListAdapter(List<WordListModel> mWordList, Context context, TextToSpeech ttsObject, int result) {
this.mWordList = mWordList;
this.context = context;
activity = (Activity)context;
this.result = result;
this.ttsObject = ttsObject;
}
#Override
public WordListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.word_list_layout,parent,false);
return new WordListViewHolder(view);
}
#Override
public void onBindViewHolder(final WordListViewHolder holder, final int position) {
final WordListModel wordmeaning = mWordList.get(position);
holder.mNameTv.setText(wordmeaning.getmWord());
holder.mNameTv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (result == TextToSpeech.LANG_NOT_SUPPORTED || result == TextToSpeech.LANG_MISSING_DATA){
Toast.makeText(activity,"Feature Not Support in your Device",Toast.LENGTH_LONG).show();
}else {
ttsObject.speak(wordmeaning.getmWord(), TextToSpeech.QUEUE_FLUSH, null);
}
}
});
holder.mMeaningTv.setText(wordmeaning.getmMeaning());
holder.mMeaningTv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (result == TextToSpeech.LANG_NOT_SUPPORTED || result == TextToSpeech.LANG_MISSING_DATA){
Toast.makeText(activity,"Feature Not Support in your Device",Toast.LENGTH_LONG).show();
}else {
ttsObject.speak(wordmeaning.getmMeaning(), TextToSpeech.QUEUE_FLUSH, null);
}
}
});
holder.mFavIv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DatabaseHelper mydb = new DatabaseHelper(context);
try {
if (wordmeaning.getIsFav().equals("false")){
boolean check = mydb.updateData("true",wordmeaning.getmWord(),wordmeaning.getDbTable());
if (check){
holder.mFavIv.setImageResource(R.drawable.ic_star_black_24dp);
}
Log.d("TAG",Boolean.toString(check));
}else {
boolean check = mydb.updateData("false",wordmeaning.getmWord(),wordmeaning.getDbTable());
if (check){
holder.mFavIv.setImageResource(R.drawable.ic_star_border_black_24dp);
}
Log.d("TAG",Boolean.toString(check));
}
}catch (Exception e){
Log.d("TAG",e.toString());
}
}
});
if (wordmeaning.getIsFav().equals("false")){
holder.mFavIv.setImageResource(R.drawable.ic_star_border_black_24dp);
}else {
holder.mFavIv.setImageResource(R.drawable.ic_star_black_24dp);
}
}
#Override
public int getItemCount() {
return mWordList.size();
}
it's beacuse the view is recycled when you scroll. Here you just updated value in db but not in list, so you also want to updated the value in arrayList as you want to keep track of items so change your code of mFavIv Onclick method like below
holder.mFavIv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DatabaseHelper mydb = new DatabaseHelper(context);
try {
if (wordmeaning.getIsFav().equals("false")){
boolean check = mydb.updateData("true",wordmeaning.getmWord(),wordmeaning.getDbTable());
if (check){
holder.mFavIv.setImageResource(R.drawable.ic_star_black_24dp);
wordmeaning.setIsFav("true"); // updted your arryListvalue
}
Log.d("TAG",Boolean.toString(check));
}else {
boolean check = mydb.updateData("false",wordmeaning.getmWord(),wordmeaning.getDbTable());
if (check){
holder.mFavIv.setImageResource(R.drawable.ic_star_border_black_24dp);
wordmeaning.setIsFav("false"); // updted your arryListvalue
}
Log.d("TAG",Boolean.toString(check));
}
}catch (Exception e){
Log.d("TAG",e.toString());
}
}
});
I have a button in every cell of a RecyclerView that launches a download network call. The cell displays differently according to whether it's downloading, downloaded or finished.
my simplified code :
#Override public void onBindViewHolder(final CatalogViewHolder holder, int position) {
final DownloadStatusCallback statusCallback = new DownloadStatusCallback() {
#Override public void started() {
mainThreadHandler.post(new Runnable() {
#Override public void run() {
holder.itemView.setBackground(//color1
}
});
}
#Override public void finished() {
mainThreadHandler.post(new Runnable() {
#Override public void run() {
holder.itemView.setBackground(//color 2
}
});
}
#Override public void error(Exception e) {
mainThreadHandler.post(new Runnable() {
#Override public void run() {
holder.itemView.setBackground(//color 3
}
});
}
};
holder.button1.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
assyncCall(statusCallback);
}
});
}
The first time i clic on a cell, everything works fine. If I clic on the download button of another cell, both of them will update.
I understand that's due to recyclerview recycling cells, but I can't figure out how to do better.
Thanks !
my full adapter :
public class CatalogRecyclerAdapter extends RecyclerView.Adapter<CatalogViewHolder> {
public static final String TAG = "CatalogRecyclerAdapter";
private final LayoutInflater inflater;
private final DownloadCenter downloadCenter;
private final ListInterface.FlowController flowController;
private final ResourcesStringRepository resourcesStringRepository;
private final ImageManagerFactory imageManagerFactory;
private final Handler mainThreadHandler;
public CatalogRecyclerAdapter(LayoutInflater inflater, ListInterface.FlowController flowController,
DownloadCenter downloadCenter, ResourcesStringRepository resourcesStringRepository,
ImageManagerFactory imageManagerFactory, Handler mainThreadHandler) {
this.inflater = inflater;
this.flowController = flowController;
this.downloadCenter = downloadCenter;
this.resourcesStringRepository = resourcesStringRepository;
this.imageManagerFactory = imageManagerFactory;
this.mainThreadHandler = mainThreadHandler;
}
private static final int TITLE = 0;
private static final int USER = 2;
private static final int PROGRAM = 3;
private static final int COURSE = 4;
private static final int GROUP = 5;
private static final int MEDIA = 6;
private static final int ERROR = 7;
private static final int DEMO = 8;
//The list of all elements
private List<FilterableUser> users = new ArrayList<>();
private List<CatalogProgram> programs = new ArrayList<>();
private List<CatalogProgram> demos = new ArrayList<>();
private List<CatalogCourse> courses = new ArrayList<>();
private List<FilterableGroup> groups = new ArrayList<>();
private List<CatalogMedia> medias = new ArrayList<>();
//The list that will be displayed after filtering and research.
List<Object> displayedList = new ArrayList<>();
static final String TITLES[] = new String[10];
static {
Context ctx = M360Application.getContext();
TITLES[USER] = ctx.getString(R.string.users);
TITLES[PROGRAM] = ctx.getString(R.string.programs);
TITLES[COURSE] = ctx.getString(R.string.courses);
TITLES[GROUP] = ctx.getString(R.string.groups);
TITLES[MEDIA] = ctx.getString(R.string.documents);
TITLES[DEMO] = ctx.getString(R.string.programs_demo);
}
private String searchString;
#Override public int getItemViewType(int position) {
if (displayedList.get(position) instanceof String) {
return TITLE;
} else if (displayedList.get(position) instanceof FilterableUser) {
return USER;
} else if (displayedList.get(position) instanceof CatalogProgramDemo) {
return DEMO;
} else if (displayedList.get(position) instanceof CatalogProgram) {
return PROGRAM;
} else if (displayedList.get(position) instanceof CatalogCourse) {
return COURSE;
} else if (displayedList.get(position) instanceof FilterableGroup) {
return GROUP;
} else if (displayedList.get(position) instanceof CatalogMedia) {
return MEDIA;
} else if (displayedList.get(position) instanceof CatalogError) {
return ERROR;
} else {
throw new ClassCastException(
"this adapter's displayedList is corrupted" + displayedList.get(position).toString());
}
}
public void setData(List<Filterable> data, String searchedString) {
searchString = searchedString;
setData(data);
}
private void setData(List<Filterable> data) {
LogDev.i(TAG, "setting data size: " + data.size());
groups.clear();
users.clear();
programs.clear();
demos.clear();
courses.clear();
medias.clear();
for (Filterable element : data) {
if (element instanceof CatalogCourse) {
courses.add((CatalogCourse) element);
} else if (element instanceof FilterableUser) {
users.add((FilterableUser) element);
} else if (element instanceof CatalogProgramDemo) {
demos.add((CatalogProgramDemo) element);
} else if (element instanceof CatalogProgram) {
programs.add((CatalogProgram) element);
} else if (element instanceof FilterableGroup) {
groups.add((FilterableGroup) element);
} else if (element instanceof CatalogMedia) {
medias.add((CatalogMedia) element);
}
}
constructDataSet();
}
private void constructDataSet() {
displayedList.clear();
if (!demos.isEmpty()) {
displayedList.add(TITLES[DEMO]);
displayedList.addAll(demos);
}
if (!programs.isEmpty()) {
displayedList.add(TITLES[PROGRAM]);
displayedList.addAll(programs);
}
if (!courses.isEmpty()) {
displayedList.add(TITLES[COURSE]);
displayedList.addAll(courses);
}
if (!users.isEmpty()) {
displayedList.add(TITLES[USER]);
displayedList.addAll(users);
}
if (!groups.isEmpty()) {
displayedList.add(TITLES[GROUP]);
displayedList.addAll(groups);
}
if (!medias.isEmpty()) {
displayedList.add(TITLES[MEDIA]);
displayedList.addAll(medias);
}
if (displayedList.isEmpty()) {
displayedList.add(new CatalogError());
}
LogDev.w(TAG, "displayedList.size() : " + displayedList.size());
notifyDataSetChanged();
}
#Override public CatalogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case TITLE:
return new TitleViewHolder(inflater.inflate(R.layout.item_list_title_catalog, parent, false));
case USER:
return new UserViewHolder(inflater.inflate(R.layout.widget_user_small, parent, false));
case PROGRAM:
case DEMO:
return new ProgramViewHolder(inflater.inflate(R.layout.widget_program_small, parent, false));
case COURSE:
return new CourseViewHolder(inflater.inflate(R.layout.widget_course_small, parent, false));
case GROUP:
return new GroupViewHolder(inflater.inflate(R.layout.widget_group_small, parent, false));
case MEDIA:
return new MediaViewHolder(inflater.inflate(R.layout.widget_media_small, parent, false));
case ERROR:
return new CatalogErrorViewHolder(inflater.inflate(R.layout.widget_noresult_small, parent, false));
default:
LogDev.e(TAG, "view type not supported");
return null;
}
}
#Override public void onBindViewHolder(CatalogViewHolder holder, int position) {
Object displayedObject = displayedList.get(position);
//holder.bind(displayedObject, errorDisplayInterface);
if (holder instanceof TitleViewHolder && displayedObject instanceof String) {
((TitleViewHolder) holder).tv.setText((String) displayedObject);
} else if (holder instanceof ProgramViewHolder && displayedObject instanceof CatalogProgram) {
bindProgramViewHolder((ProgramViewHolder) holder, (CatalogProgram) displayedObject);
} else if (holder instanceof CourseViewHolder && displayedObject instanceof CatalogCourse) {
bindCourseViewHolder((CourseViewHolder) holder, (CatalogCourse) displayedObject);
} else if (holder instanceof GroupViewHolder && displayedObject instanceof FilterableGroup) {
bindGroupViewHolder((GroupViewHolder) holder, (FilterableGroup) displayedObject);
} else if (holder instanceof UserViewHolder && displayedObject instanceof FilterableUser) {
bindUserViewHolder((UserViewHolder) holder, (FilterableUser) displayedObject);
} else if (holder instanceof MediaViewHolder && displayedObject instanceof CatalogMedia) {
bindMediaViewHolder((MediaViewHolder) holder, (CatalogMedia) displayedObject);
} else if (holder instanceof CatalogErrorViewHolder) {
//No binding with any data
} else {
throw new ClassCastException(displayedObject.toString());
}
//Highlight
if (searchString != null && !searchString.isEmpty())
{
TextViewHighlighter.highlight(holder, searchString);
}
}
private void bindCourseViewHolder(final CourseViewHolder courseViewHolder, final CatalogCourse course) {
courseViewHolder.name_textView.setText(course.name);
courseViewHolder.viewNb_textView.setText(course.views != null ? course.views.toString() : "0");
if (course.elementCount == null) {
courseViewHolder.counterLinear.setVisibility(View.GONE);
} else {
courseViewHolder.counterLinear.setVisibility(View.VISIBLE);
courseViewHolder.questionNb_textView.setText(
course.elementCount.questions != null ? course.elementCount.questions.toString() : "0");
courseViewHolder.mediaNb_textView.setText(
course.elementCount.medias != null ? course.elementCount.medias.toString() : "0");
courseViewHolder.sheetNb_textView.setText(
course.elementCount.sheets != null ? course.elementCount.sheets.toString() : "0");
}
imageManagerFactory.course(course.id).thumbnail(courseViewHolder.pic_imageView);
//new CourseImageManager(course.id).load(courseViewHolder.pic_imageView);
View.OnClickListener clickListener = new View.OnClickListener() {
#Override public void onClick(View view) {
flowController.routeToCourse(course.id);
}
};
courseViewHolder.container.setOnClickListener(clickListener);
if (course.canBeOffline) {
courseViewHolder.downloadBlock.setVisibility(View.VISIBLE);
DownloadState state = downloadCenter.getCourseStatus(course.id);
LogDev.i(TAG, "can be offline " + state.name());
if (state == DownloadState.DOWNLOADING) {
updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADING);
}
if (state == DownloadState.TO_DOWNLOAD) {
updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADABLE);
}
if (state == DownloadState.DOWNLOADED || state == DownloadState.DOWNLOADED_WITH_SHARED_MODE) {
updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADED);
} else {
DownloadStatusCallback statusCallback = new DownloadStatusCallback() {
#Override public void started() {
LogDev.i(TAG, "started");
mainThreadHandler.post(new Runnable() {
#Override public void run() {
updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADING);
}
});
}
#Override public void finished() {
mainThreadHandler.post(new Runnable() {
#Override public void run() {
updateDownloadBlock(courseViewHolder, DownloadableStatus.DOWNLOADED);
}
});
}
#Override public void error(Exception e) {
mainThreadHandler.post(new Runnable() {
#Override public void run() {
updateDownloadBlock(courseViewHolder, DownloadableStatus.ERROR);
}
});
}
};
downloadCenter.subscribe(course.id, statusCallback);
courseViewHolder.downloadBlock.setOnClickListener(new View.OnClickListener()
{
#Override public void onClick(View v) {
new Thread() {
#Override public void run() {
super.run();
try {
downloadCenter.downloadCourse(course.id, null);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
});
}
} else {
LogDev.i(TAG, "can't be offline");
courseViewHolder.downloadBlock.setVisibility(View.INVISIBLE);
}
}
private void updateDownloadBlock(CourseViewHolder courseViewHolder, DownloadableStatus status) {
if (status == null) return;
courseViewHolder.downloadBlock.setVisibility(
status.equals(DownloadableStatus.NOT_DOWNLOADABLE) ? View.GONE : View.VISIBLE);
courseViewHolder.downloadImage.setVisibility(
status.equals(DownloadableStatus.DOWNLOADABLE) ? View.VISIBLE : View.GONE);
courseViewHolder.downloadProgress.setVisibility(
status.equals(DownloadableStatus.DOWNLOADING) ? View.VISIBLE : View.GONE);
courseViewHolder.downloadedImage.setVisibility(
status.equals(DownloadableStatus.DOWNLOADED) ? View.VISIBLE : View.GONE);
courseViewHolder.downloadErrImage.setVisibility(
status.equals(DownloadableStatus.ERROR) ? View.VISIBLE : View.GONE);
}
private enum DownloadableStatus {
NOT_DOWNLOADABLE, DOWNLOADABLE, DOWNLOADING, DOWNLOADED, ERROR
}
private void bindProgramViewHolder(ProgramViewHolder programViewHolder, final CatalogProgram program) {
imageManagerFactory.program(program.id).thumbnail(programViewHolder.pic_imageView);
//new ProgramImageManager(program.id).load(programViewHolder.pic_imageView);
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override public void onClick(View view) {
flowController.routeToProgram(program.id);
}
};
programViewHolder.container.setOnClickListener(onClickListener);
programViewHolder.pic_imageView.setOnClickListener(onClickListener);
programViewHolder.title_textView.setText(program.name);
programViewHolder.viewCount_textView.setText(program.views != null ? program.views.toString() : "0");
}
private void bindUserViewHolder(UserViewHolder userViewHolder, final FilterableUser user) {
userViewHolder.name_textView.setText(user.name);
userViewHolder.job_textView.setText(user.description);
imageManagerFactory.user(user.id).thumbnail(userViewHolder.pic_imageView);
//new UserImageManager(user.id).loadProfilePic(userViewHolder.pic_imageView, NetworkUtils.isNetworkAvailable(),
// true);
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override public void onClick(View view) {
flowController.routeToUser(user.id);
}
};
userViewHolder.pic_imageView.setOnClickListener(onClickListener);
userViewHolder.container.setOnClickListener(onClickListener);
}
private void bindMediaViewHolder(MediaViewHolder mediaViewHolder, final CatalogMedia media) {
imageManagerFactory.media(media.id, media.type, media.extention).symbolOnThumbnail(mediaViewHolder.complex);
//new MediaImageManager(media).load(mediaViewHolder.pic_imageView, NetworkUtils.isNetworkAvailable(), false);
mediaViewHolder.title_textView.setText(media.title);
mediaViewHolder.authorName_textView.setText(media.authorName);
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override public void onClick(final View view) {
flowController.routeToDocument(media.id);
}
};
mediaViewHolder.complex.setOnClickListener(onClickListener);
mediaViewHolder.container.setOnClickListener(onClickListener);
}
private void bindGroupViewHolder(GroupViewHolder groupViewHolder, final FilterableGroup group) {
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override public void onClick(View view) {
flowController.routeToGrouop(group.id);
}
};
groupViewHolder.pic_imageView.setOnClickListener(onClickListener);
groupViewHolder.container.setOnClickListener(onClickListener);
groupViewHolder.name_textView.setText(group.name);
String str = resourcesStringRepository.getQuantityString(R.plurals.catalog_group_stat_program,
group.nbProgramsRunning, group.nbProgramsRunning);
str += " - " + resourcesStringRepository.getQuantityString(R.plurals.catalog_group_stat_user, group.nbUser,
group.nbUser);
groupViewHolder.stats_textView.setText(str);
imageManagerFactory.group(group.id).thumbnail(groupViewHolder.pic_imageView);
//new GroupImageManager(group.id).load(groupViewHolder.pic_imageView, NetworkUtils.isNetworkAvailable(), true);
}
#Override public int getItemCount() {
return displayedList.size();
}
}
It is recycling the views.So while clicking the button you have to store its position and change views accordingly.
Maintain a position storing variable globally like this
private int itemClicked=-1;
While clicking the view store the position into itemclicked
holder.button1.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
itemclicked=position;
assyncCall(statusCallback);
}
});
Then while updating views check if the position is same like this
if(position==itemclicked){
//show download for clicked view
}else{
//show download stopped for other views
}
Solution
As Surender and Trickcy Solution suggested, I updated the presented data and then tell the adapter to update the cell accordingly :
DownloadStatusCallback statusCallback = new DownloadStatusCallback() {
#Override public void started() {
LogDev.i(TAG, "started");
course.downloadState = DownloadState.DOWNLOADING;
final int position = courseViewHolder.getAdapterPosition();
mainThreadHandler.post(new Runnable() {
#Override public void run() {
notifyItemChanged(position);
}
});
}
#Override public void finished() {
course.downloadState = DownloadState.DOWNLOADED;
final int position = courseViewHolder.getAdapterPosition();
mainThreadHandler.post(new Runnable() {
#Override public void run() {
notifyItemChanged(position);
}
});
}
#Override public void error(Exception e) {
course.downloadState = DownloadState.ERROR_WHILE_DOWNLOADING;
final int position = courseViewHolder.getAdapterPosition();
mainThreadHandler.post(new Runnable() {
#Override public void run() {
notifyItemChanged(position);
}
});
}
};
I'm developing android App. My app is showing many of pictures from server by image_url with ImageLoader Library such as Picasso, Glide or AUIL.
There are five fragments in main activity. and each of fragments have many image list view.
My question is that after I click specific image view, new activity is created, and then fragment is created that have many images list view.
I clicked different images, and new activities are created. When this gesture occurred , heap memory is not fetched ...
Among of three libraries, AUIL is the best of them.
I tried recursing method at base adapter and drawable callback to null etc...
But This situation was not solved.
Here is my example Adapter sourse:
public class MagazineRelBrandItemAdapter extends BaseAdapter {
ArrayList<String> receivedList;
ArrayList<View> brandThumList = new ArrayList<>();
PrintLog printLog = new PrintLog(Application.isDEBUG(), "MagazineRelBrandItemAdap ", "created");
Activity mActivity;
public MagazineRelBrandItemAdapter(ArrayList<String> dataList, Activity activity) {
receivedList = dataList;
mActivity = activity;
}
#Override
public int getCount() {
return receivedList.size();
}
#Override
public String getItem(int position) {
return receivedList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MagazineRelBrandView itemView;
if (convertView == null) {
itemView = new MagazineRelBrandView(Application.getContext(),mActivity);
} else {
itemView = (MagazineRelBrandView) convertView;
}
try {
itemView.setContent(receivedList.get(position));
brandThumList.add(itemView);
} catch (OutOfMemoryError e) {
if (mRecycleList.size() <= parent.getChildCount()) {
printLog.cutsomPrintLog(Application.isDEBUG(), "img recycle size comment>>", mRecycleList.size() + "");
throw e;
}
recycleHalf();
System.gc();
return getView(position, itemView, parent);
}
mRecycleList.add(new WeakReference<View>(itemView));
return itemView;
}
private List<WeakReference<View>> mRecycleList = new ArrayList<WeakReference<View>>();
public void recycleHalf() {
int halfSize = mRecycleList.size() / 2;
List<WeakReference<View>> recycleHalfList = mRecycleList.subList(0, halfSize);
RecycleUtils.recursiveRecycle(recycleHalfList);
for (int i = 0; i < halfSize; i++)
mRecycleList.remove(0);
}
public void recycle() {
RecycleUtils.recursiveRecycle(mRecycleList);
}
}
And Here is my widget :
public class MagazineRelBrandView extends LinearLayout {
Activity mActivity;
public MagazineRelBrandView(Context context,Activity activity) {
super(context);
mActivity = activity;
init();
}
CircleImageView brandLogo;
TextView brandName;
ImageView brandBg;
View clickV;
private void init() {
inflate(getContext(), R.layout.magazine_rel_brand_view, this);
brandBg = (ImageView) findViewById(R.id.magazine_rel_brand_bg);
brandName = (TextView) findViewById(R.id.magazine_rel_brand_name);
brandLogo = (CircleImageView) findViewById(R.id.magazine_rel_brand_icon);
clickV = findViewById(R.id.content_click_view);
brandName.setTypeface(Typeface.createFromAsset(getContext().getAssets(), CommonKeys.FuturaFont));
clickV.setOnClickListener(goBrandDetailPageListener);
}
public void setContent(String brandName) {
this.brandName.setText(brandName);
try {
String brandTitleUrl;
brandTitleUrl = URLEncoder.encode(brandName, "UTF-8");
totalThumbUrl = CommonKeys.brandThumbUrl + brandTitleUrl;
totalBackUrl = CommonKeys.brandBackgroundUrl + brandTitleUrl;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
showBG(brandName);
showLogo(brandName);
}
String totalThumbUrl;
String totalBackUrl;
public void showLogo(final String brandName){
Glide.with(mActivity).load(totalThumbUrl).override(DpToPxUtil.dp2px(38),DpToPxUtil.dp2px(38)).into(brandLogo);
}public void showBG(final String brandName){
Glide.with(mActivity).load(totalBackUrl).override(DpToPxUtil.dp2px(120),DpToPxUtil.dp2px(144)).into(brandBg);
}
public String getBrandName() {
return brandName.getText().toString();
}
Handler brandHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
MyToast.show("" + msg.obj);
break;
case 1:
BrandInfoZip brandInfoZip = (BrandInfoZip) ((BrandInfoParentZip) msg.obj).getData();
BrandListZip getBrandZip = new BrandListZip();
getBrandZip.setIs_following(brandInfoZip.is_following());
getBrandZip.setBrand_name(getBrandName());
Intent goBrandPage = new Intent(Application.getContext(), BrandDetailActivity.class);
goBrandPage.putExtra("brandZip", getBrandZip);
goBrandPage.putExtra("title", getBrandName());
goBrandPage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Application.getContext().startActivity(goBrandPage);
break;
}
}
};
OnClickListener goBrandDetailPageListener = new OnClickListener() {
#Override
public void onClick(View v) {
BrandDescriptionZip brandDescriptionZip = new BrandDescriptionZip();
brandDescriptionZip.setBrand_name(getBrandName());
new GetBrandInfoFromServer(brandHandler).execute(brandDescriptionZip);
}
};
}
And fragment onDestroyView sourse :
#Override
public void onStop() {
super.onStop();
if (upperBgImgV.getDrawable() != null) {
upperBgImgV.getDrawable().setCallback(null);
}
if (writerThumb.getDrawable() != null) {
writerThumb.getDrawable().setCallback(null);
}
if (otherContentV.getDrawable() != null) {
otherContentV.getDrawable().setCallback(null);
}
}
#Override
public void onDestroyView() {
Glide.clear(writerThumb);
magazineRelBrandItemAdapter.recycle();
unbindDrawables(getView());
//unbindDrawables(writerThumb);
//unbindDrawables(otherContentV);
System.gc();
super.onDestroyView();
Log.i(TAG, "onDestroyView-");
}
private void unbindDrawables(View view) {
if (view == null)
return;
if (view instanceof ImageView) {
((ImageView) view).setImageDrawable(null);
}
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
view.setBackgroundResource(0);
view.setBackgroundDrawable(null);
}
}
and Here is activity onDestroy() course :
#Override
protected void onDestroy() {
RecycleUtils.recursiveRecycle(getWindow().getDecorView());
System.gc();
Glide.get(this).clearMemory();
FlurryAgent.onEndSession(Application.getContext());
printLog.cutsomPrintLog(Application.isDEBUG(),"Magazine Detail Activity onDestroy-","onDestroy-");
super.onDestroy();
finish();
}
These course is used to clear memory heap. But Memory leak is continue....
Please help me.