2016-09-07 2 views
-2

У меня есть приложение с RecyclerView и настроенный Adapter, который получает это из анализа.Адаптер RecyclerView является лагги из-за onBindViewHolder()

Мой адаптер содержит несколько TextView s, a Button, маленький ImageView. Некоторые из моих TextView s нуждаются в функции (подсчете количества upvote и т. Д.) В моем AdapteronBindViewHolder(), чтобы получить их данные.

Я заметил, что моя прокрутка очень медленная и лагированная из-за функций, вызываемых в onBindViewHolder().

Где я должен устанавливать свои данные и вызывать свои функции, чтобы получить плавную прокрутку?

EDIT 1:

Вот мой адаптер Код:

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.ViewHolder> { 
public static class ViewHolder extends RecyclerView.ViewHolder { 
    public TextView  postName; 
    public ImageView postCatIcon; 

    public TextView  postDays; 
    public TextView  postDaysLabel; 
    public TextView  postHours; 
    public TextView  postHoursLabel; 
    public TextView  postMinutes; 
    public TextView  postMinutesLabel; 
    public TextView  postDistance; 

    public TextView  postLikes; 
    public TextView  postAuthor; 
    public LikeButton likepost; 

    private Post post; 


    public ViewHolder(View itemView) { 
     super(itemView); 
     postName = (TextView) itemView.findViewById(R.id.post_name); 
     postCatIcon = (ImageView) itemView.findViewById(R.id.post_cat_icon); 

     postDays   = (TextView) itemView.findViewById(R.id.post_days); 
     postDaysLabel  = (TextView) itemView.findViewById(R.id.post_days_label); 
     postHours   = (TextView) itemView.findViewById(R.id.post_hours); 
     postHoursLabel  = (TextView) itemView.findViewById(R.id.post_hours_label); 
     postMinutes   = (TextView) itemView.findViewById(R.id.post_minutes); 
     postMinutesLabel = (TextView) itemView.findViewById(R.id.post_minutes_label); 
     postDistance  = (TextView) itemView.findViewById(R.id.post_distance); 

     likePost = (LikeButton) itemView.findViewById(R.id.like_the_post); 
     postAuthor = (TextView) itemView.findViewById(R.id.post_author); 
     postLikes = (TextView) itemView.findViewById(R.id.post_likes); 
    } 

    public void setData(Post post){ 
     this.post = post; 
     updateTimeRemaining(System.currentTimeMillis()); 
    } 

    public void updateTimeRemaining(long currentTime) { 
     long diff = post.getDate().getTime() - currentTime; 

     int minutes = (int) ((diff/(1000*60)) % 60); 
     int hours = (int) ((diff/(1000*60*60)) % 24); 
     int days = (int) (diff/(1000*60*60*24)); 


     String strgMinutes = "00"; 
     String strgHours = "00"; 
     String strgDays = "00"; 

     if(minutes < 10) 
      strgMinutes = "0" + String.valueOf(minutes); 
     else 
      strgMinutes = String.valueOf(minutes); 

     if(hours < 10) 
      strgHours = "0" + String.valueOf(hours); 
     else 
      strgHours = String.valueOf(hours); 

     if(days < 10){ 
      strgDays = "0" + String.valueOf(days); 
     }else 
      strgDays = String.valueOf(days); 

     postDays.setText(strgDays); 
     postHours.setText(strgHours); 
     postMinutes.setText(strgMinutes); 
    } 
} 

public static class ProgressViewHolder extends PostAdapter.ViewHolder { 
    public ProgressBar progressBar; 

    public ProgressViewHolder(View v) { 
     super(v); 
     progressBar = (ProgressBar) v.findViewById(R.id.progressBar); 
    } 
} 

private List<Post> mPosts; 
private Context mContext; 
private ListFragment mFragment; 

private final int VIEW_ITEM = 1; 
private final int VIEW_PROG = 0; 

ArrayList<PostAdapter.ViewHolder> viewHoldersList; 
private Handler handler = new Handler(); 
private Runnable updateRemainingTimeRunnable = new Runnable() { 
    @Override 
    public void run() { 
     long currentTime = System.currentTimeMillis(); 
     synchronized (viewHoldersList) { 
      for (PostAdapter.ViewHolder holder : viewHoldersList) { 
       holder.updateTimeRemaining(currentTime); 
      } 
     } 
     handler.postDelayed(this, 60000); 
    } 
}; 

// The minimum amount of items to have below your current scroll position before loading more. 
private int visibleThreshold = 2; 
private int lastVisibleItem, totalItemCount; 
private boolean loading; 
private OnLoadMoreListener onLoadMoreListener; 

public PostAdapter(List<Post> posts, Context context, ListFragment fragment, RecyclerView recyclerView) { 
    mContext = context; 
    mPosts = posts; 
    mFragment = fragment; 

    if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { 

     final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); 
     recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 
      @Override 
      public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 
       super.onScrolled(recyclerView, dx, dy); 

       totalItemCount = linearLayoutManager.getItemCount(); 
       lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); 
       if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) { 
        // End has been reached 
        // Do something 
        if (onLoadMoreListener != null) { 
         onLoadMoreListener.onLoadMore(); 
        } 
        loading = true; 
       } 
      } 
     }); 
    } 

    viewHoldersList = new ArrayList<>(); 
    startUpdateTimer(); 
} 

public PostAdapter(List<Post> posts, Context context, RecyclerView recyclerView) { 
    mContext = context; 
    mPosts = posts; 

    if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { 

     final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); 
     recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 
      @Override 
      public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 
       super.onScrolled(recyclerView, dx, dy); 

       totalItemCount = linearLayoutManager.getItemCount(); 
       lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition(); 
       if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) { 
        // End has been reached 
        // Do something 
        if (onLoadMoreListener != null) { 
         onLoadMoreListener.onLoadMore(); 
        } 
        loading = true; 
       } 
      } 
     }); 
    } 
    viewHoldersList = new ArrayList<>(); 
    startUpdateTimer(); 
} 

private void startUpdateTimer() { 
    handler.postDelayed(updateRemainingTimeRunnable,60000); 
} 

public PostAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    Context context   = parent.getContext(); 
    LayoutInflater inflater = LayoutInflater.from(context); 
    View postView; 
    ViewHolder viewHolder; 

    if (viewType == VIEW_ITEM) { 
     postView = inflater.inflate(R.layout.list_item, parent, false); 

     viewHolder = new ViewHolder(postView); 
    } else { 
     postView = inflater.inflate(R.layout.loading_item, parent, false); 

     viewHolder = new ProgressViewHolder(postView); 
    } 

    return viewHolder; 
} 

public void onBindViewHolder(final PostAdapter.ViewHolder viewHolder, final int position) { 
    if (viewHolder instanceof ViewHolder) { 
     final Post post = mPosts.get(position); 
     if(post != null){ 
      synchronized (viewHoldersList) { 
       viewHolder.setData(post); 
       viewHoldersList.add(viewHolder); 
      } 

      Category cat     = post.getCategory(); 
      TextView nameTextView   = viewHolder.postName; 
      TextView authorTextView   = viewHolder.postAuthor; 
      final TextView likesTextView = viewHolder.postLikes; 
      ImageView CatIconView   = viewHolder.postCatIcon; 
      final LikeButton likeButtonView = viewHolder.likePost; 
      TextView postDistance   = viewHolder.postDistance; 
      ParseUser postAuthor = null; 

      if(mFragment != null) { 
       if (mFragment.getIfFilteredByDistance()) { 
        postDistance.setVisibility(View.VISIBLE); 
        Location postLocation = new Location("Post location"); 
        if(post.getLocation() != null){ 
         postLocation.setLongitude(post.getLocation().getLongitude()); 
         postLocation.setLatitude(post.getLocation().getLatitude()); 

         GPSTracker gpsTracker = new GPSTracker(mContext); 
         if (gpsTracker.canGetLocation()) { 
          Location myLocation = new Location("My location"); 
          myLocation.setLatitude(gpsTracker.getLatitude()); 
          myLocation.setLongitude(gpsTracker.getLongitude()); 

          postDistance.setText((Math.round(myLocation.distanceTo(postLocation))/1000) + " km"); 
         } else 
          gpsTracker.showSettingsAlert(); 
        } 
       } else 
        postDistance.setVisibility(View.INVISIBLE); 
      } 


      try{ 
       postAuthor = post.getAuthor().fetchIfNeeded(); 
      }catch (ParseException e){ 
       Log.e("Parse:", e.getMessage()); 
      } 

      saveActivitiesToLocalDatastore(post); 

      final int likeCount = ((PostApplication)mContext).getPostLikeCount(post); 
      likesTextView.setText(String.valueOf(likeCount)); 

      likeButtonView.setLiked(((PostApplication)mContext).getIfLiked(post)); 

      viewHolder.itemView.setOnClickListener(new View.OnClickListener(){ 
       @Override 
       public void onClick(View view) { 
        Intent intent = new Intent(mContext, DetailActivity.class); 
        intent.putExtra("PostID",post.getObjectId()); 
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
        mContext.startActivity(intent); 
       } 
      }); 

      likeButtonView.setOnLikeListener(new OnLikeListener() { 
       @Override 
       public void liked(LikeButton likeButton) { 
        if(((PostApplication)mContext).likePost(post)) 
         likesTextView.setText(String.valueOf(Integer.parseInt(likesTextView.getText().toString()) + 1)); 
       } 

       @Override 
       public void unLiked(LikeButton likeButton) { 
        if(((PostApplication)mContext).unlikePost(post)) 
         likesTextView.setText(String.valueOf(Integer.parseInt(likesTextView.getText().toString()) -1)); 

       } 
      }); 


      nameTextView.setText(post.getTitle()); 
      authorTextView.setText(post.getAuthor().getUsername()); 


      CatIconView.setImageDrawable(ContextCompat.getDrawable(mContext,mContext.getResources().getIdentifier(cat.getIconName()+"_18dp","drawable",mContext.getPackageName()))); 

     } 
    } else { 
     ((ProgressViewHolder) viewHolder).progressBar.setIndeterminate(true); 
    } 
} 



public int getItemCount() { 
    return mPosts.size(); 
} 

private void saveActivitiesToLocalDatastore(final Post post){ 
    // Saves Likes to Parse local datastore 
} 

@Override 
public int getItemViewType(int position) { 
    return mposts.get(position) != null ? VIEW_ITEM : VIEW_PROG; 
} 


public void setLoaded() { 
    loading = false; 
} 

public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) { 
    this.onLoadMoreListener = onLoadMoreListener; 
} 

public interface OnLoadMoreListener { 
    void onLoadMore(); 
} 

EDIT 2:

Я последовал за этим, чтобы исправить мерцание моего CountDown в:

Recyclerview with multiple countdown timers causes flickering

EDIT 3:

Я попытался запустить приложение без методов, как saveActivitiesInBackgroud Вспомогательных и слушателей, и она работает очень гладко

+2

Отправьте код пожалуйста. – Enzokie

+1

Ответ на этот вопрос зависит от того, где хранятся загруженные данные. Realm? SQLite? В памяти? Общий префикс (lol)? – EpicPandaForce

+1

RecyclerView не лагги. Вероятно, у вас есть ошибка в коде адаптера. Пожалуйста, присылайте свои коды, чтобы люди могли вам помочь. – eren130

ответ

2

Если и хотят использовать RecyclerView и нужно использовать onBindViewHolder. Это не проблема с OnBindViewHolder. Проблема с ур запутанного кода, а также у не хранить информацию, так что это вызовет ур recyclerview к запаздывает

+0

Не могли бы вы продумать, например, какие большие ошибки с моим кодом и как я должен хранить информацию? Я знаю, что мне нужно использовать onBindViewHolder. Я просто спрашивал, как я могу осветлить его. – Archipel

+0

-U иногда вызывает информацию, которую можно создать один раз (новые объекты). -U может хранить информацию, что, используя для дальнейшего (SharedPreferences, базы данных у прочертовского могут пойти с ошибкой OUT-OF-памятью Попробуйте использовать LeakCanary и посмотреть, что утечка – Rodriquez

+0

я попытался LeakCanary, она не уведомляет меня о чем – Archipel

1
  • Старайтесь не менять ViewHolder состояние вне onBindViewHolder(). ViewHolder представляет представление на экране, но не представляет данные. RecyclerView имеют тенденцию к повторному использованию представлений, когда они становятся невидимыми на экране, и в результате повторное использование ViewHolder прилагается к этому представлению.

  • Никогда не храните ViewHolder - это RecyclerView ответственность за управление ими.

  • Если вы обновили свой таймер только один раз в 60 sec, просто notifyDataSetChanges вместо прямого обновления ViewHolder. И обновите состояние просмотра в onBindViewHolder с надлежащим временем.

+0

Хорошо, я думаю, что получил роль в ViewHolder, но где я должен позвонить notifyDataSetChanges? И должен ли я использовать CountDownTimer для моего таймера в этом случае? – Archipel

+0

вместо этого вызывать его в 'updateRemainingTimeRunnable :: run' – j2ko

+0

Хорошо, поэтому я сохраняю свой метод updateTimeRemaining() у моего зрителя и избавляюсь от setData(), и все синхронизированы с правильными? Мне жаль, что я новичок в разработке Android, и я не знаком с такими вещами. Но спасибо за вашу помощь – Archipel