如何解决如何在Android应用中使滚动Feed更加流畅?
我是编程的初学者。这个Android应用程式是滚动资讯提供类型的应用程式。但是问题是当用户上传大尺寸的图像时,提要变得非常慢并且滚动时滞很大。如何消除这种情况并使进料更平滑?我正在使用Firebase作为后端。
请问我是否必须在此处提交任何代码。
我正在使用此代码。
package com.arcdevelopers.readbee.ui.feed;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.squareup.picasso.Picasso;
import com.vanniktech.emoji.EmojiTextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.hdodenhof.circleimageview.CircleImageView;
import com.arcdevelopers.readbee.R;
import com.arcdevelopers.readbee.data.model.Like;
import com.arcdevelopers.readbee.data.model.Post;
import com.arcdevelopers.readbee.data.model.User;
import com.arcdevelopers.readbee.domain.listener.OnValueEventListener;
import com.arcdevelopers.readbee.domain.util.AnimationUtil;
import com.arcdevelopers.readbee.ui.MainViewModel;
import com.arcdevelopers.readbee.ui.common.base.BaseActivity;
import com.arcdevelopers.readbee.ui.common.view.SquareImageView;
import static android.text.TextUtils.isEmpty;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static com.arcdevelopers.readbee.domain.util.AnimationUtil.toggleLike;
import static com.arcdevelopers.readbee.domain.util.Constants.FIELD_ID;
import static com.arcdevelopers.readbee.domain.util.Constants.FIELD_POST_ID;
import static com.arcdevelopers.readbee.domain.util.Constants.TABLE_SAVED;
import static com.arcdevelopers.readbee.domain.util.Constants.TABLE_USERS;
import static com.arcdevelopers.readbee.domain.util.DateUtil.getTimeAgo;
import static java.lang.String.valueOf;
import android.view.View;
import com.google.android.gms.ads.formats.MediaView;
import com.google.android.gms.ads.formats.UnifiedNativeAdView;
import com.google.android.gms.ads.formats.UnifiedNativeAd;
/**
* Feed adapter.
*
* @author Max Sukov (sukovMax@gmail.com)
* Created on 2020/06/01
*/
public class FeedAdapter extends RecyclerView.Adapter<FeedAdapter.ViewHolder> {
/**
* Interface definition for a callback to be invoked when a user or a comment has been clicked.
*/
public interface OnFeedClickListener {
/**
* Callback method to be invoked when a user has been clicked.
*
* @param user A user that was clicked
*/
void onUserClick(User user);
/**
* Callback method to be invoked when a comment has been clicked.
*
* @param post A post to which comment belongs to
* @param view A view that was clicked
*/
void onCommentClick(Post post,View view);
/**
* Callback method to be invoked when options has been clicked.
*
* @param post A post to which options belong to
* @param view A view which is clicked
*/
void onOptionsClick(Post post,View view);
}
/**
* Context.
*/
private Context mContext;
/**
* Contains the list of objects that represent the data of this adapter.
*/
private List<Post> mPosts;
/**
* The listener that receives notifications when an item is clicked.
*/
private OnFeedClickListener mListener;
/**
* Main view model.
*/
private MainViewModel mMainViewModel;
/**
* Firebase database reference.
*/
private DatabaseReference mDatabaseReference;
/**
* Current user id.
*/
private String mCurrentUserId;
/**
* Users cache.
*/
private Map<String,User> mUsersCache;
/**
* Saved status cache.
*/
private Map<String,Boolean> mSavedCache;
/**
* List item animator
*/
private AnimationUtil.ListItemAnimator mListItemAnimator;
// A menu item view type.
private static final int MENU_ITEM_VIEW_TYPE = 0;
// The unified native ad view type.
private static final int UNIFIED_NATIVE_AD_VIEW_TYPE = 1;
RecyclerView recyclerView;
/**
* Constructor.
*
* @param fragment The fragment where recycler view is hosted
* @param listener The listener that receives notifications when an item is clicked
*/
public FeedAdapter(FeedFragment fragment,OnFeedClickListener listener) {
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
mMainViewModel = new ViewModelProvider(fragment.requireActivity()).get(MainViewModel.class);
mCurrentUserId = FirebaseAuth.getInstance().getUid();
mUsersCache = new HashMap<>();
mSavedCache = new HashMap<>();
mPosts = new ArrayList<>();
mListener = listener;
}
/**
* Called by RecyclerView when it starts observing this Adapter.
*
* @param recyclerView The RecyclerView instance which started observing this adapter
*/
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
this.recyclerView=recyclerView;
super.onAttachedToRecyclerView(recyclerView);
// get context
mContext = recyclerView.getContext();
// init list item animator
mListItemAnimator = new AnimationUtil.ListItemAnimator(mContext,this);
}
/**
* Called when RecyclerView needs a new {@link RecyclerView.ViewHolder} of the given type to represent
* an item.
*
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position
* @param viewType The view type of the new View
* @return A new ViewHolder that holds a View of the given view type
*/
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.cell_feed,parent,false);
return new ViewHolder(view);
}
/**
* Called by RecyclerView to display the data at the specified position.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set
* @param position The position of the item within the adapter's data set
*/
@Override
public void onBindViewHolder(@NonNull ViewHolder holder,int position) {
// animate item
mListItemAnimator.animate(holder.itemView,position);
// get post object reference
Post post = mPosts.get(position);
// if user has not been loaded before
if (!mUsersCache.containsKey(post.getUserId())) {
// load user details
Query query = mDatabaseReference.child(TABLE_USERS)
.orderByChild(FIELD_ID)
.equalTo(post.getUserId());
query.addListenerForSingleValueEvent(new OnValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) {
// parse user
User user = singleSnapshot.getValue(User.class);
// cache this user
mUsersCache.put(post.getUserId(),user);
// update views
updateUserViews(holder,user);
}
}
});
} else {
// load user from cache and update views
User user = mUsersCache.get(post.getUserId());
updateUserViews(holder,user);
}
// set post date
String dateDiff = getTimeAgo(post.getDateCreated(),mContext.getResources());
holder.dateView.setText(dateDiff);
// load post photo if present
if (!isEmpty(post.getPhoto())) {
Picasso.get().load(post.getPhoto()).into(holder.imageView);
}
// set like on / off buttons visibility
holder.likeOnView.setVisibility(post.isLikedByUser(mCurrentUserId) ? VISIBLE : GONE);
holder.likeOffView.setVisibility(!post.isLikedByUser(mCurrentUserId) ? VISIBLE : GONE);
// bind click listener to like on button
holder.likeOnView.setOnClickListener(v -> {
Iterator<Like> i = post.getLikes().iterator();
while (i.hasNext()) {
Like like = i.next();
if (like.getUserId().equals(mCurrentUserId)) {
i.remove();
// remove like
mMainViewModel.removeLike(post.getId(),like.getId());
break;
}
}
holder.likeCountView.setText(valueOf(post.getLikes().size()));
toggleLike(holder.likeOnView,holder.likeOffView);
});
// bind click listener to like off button
holder.likeOffView.setOnClickListener(v -> {
// add like
String likeId = mMainViewModel.addLike(post.getId(),post.getUserId());
post.getLikes().add(new Like(likeId,mCurrentUserId));
holder.likeCountView.setText(valueOf(post.getLikes().size()));
toggleLike(holder.likeOnView,holder.likeOffView);
});
// set likes count
holder.likeCountView.setText(valueOf(post.getLikes().size()));
// bind click listener to comment button
holder.commentView.setOnClickListener(v -> {
if (mListener != null) {
mListener.onCommentClick(post,holder.commentView);
}
});
// set comments count
holder.commentCountView.setText(valueOf(post.getComments().size()));
// set caption text
holder.captionView.setText(post.getCaption());
holder.captionView.setVisibility(!isEmpty(post.getCaption()) ? VISIBLE : GONE);
// bind click listener to options view
holder.mOptionsView.setOnClickListener(v -> {
if (mListener != null) {
mListener.onOptionsClick(post,holder.mOptionsView);
}
});
// show options only for user's own posts
holder.mOptionsView.setVisibility(post.getUserId().equals(mCurrentUserId) ? VISIBLE : GONE);
// if saved status has not been loaded before
if (!mUsersCache.containsKey(post.getId())) {
// load saved status
Query query = mDatabaseReference.child(TABLE_SAVED)
.child(mCurrentUserId)
.orderByChild(FIELD_POST_ID)
.equalTo(post.getId());
query.addListenerForSingleValueEvent(new OnValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
// cache result and update save btn
boolean isSaved = dataSnapshot.exists();
mSavedCache.put(post.getId(),isSaved);
holder.mSaveBtn.setImageAlpha(isSaved ? 255 : 50);
holder.mSaveBtn.setVisibility(VISIBLE);
}
});
} else {
// load saved status from cache and update save btn
User user = mUsersCache.get(post.getUserId());
updateUserViews(holder,user);
boolean isSaved = mSavedCache.containsKey(post.getId()) ? mSavedCache.get(post.getId()) : false;
holder.mSaveBtn.setImageAlpha(isSaved ? 255 : 50);
holder.mSaveBtn.setVisibility(VISIBLE);
}
// bind click listener to save btn
holder.mSaveBtn.setOnClickListener(v -> {
// disable save btn
holder.mSaveBtn.setEnabled(false);
// load saved status from cache and toggle it
final boolean save = mSavedCache.containsKey(post.getId()) ? !mSavedCache.get(post.getId()) : true;
// save post or remove it from saved,depending on saved status
mMainViewModel.savePost(post.getId(),save).observe(((BaseActivity) mContext),result -> {
// cache result back and update save btn
mSavedCache.put(post.getId(),result);
holder.mSaveBtn.setImageAlpha(result ? 255 : 50);
// enable save btn
holder.mSaveBtn.setEnabled(true);
});
});
}
@Override
public int getItemViewType(int position) {
Object recyclerViewItem = mPosts.get(position);
if (recyclerViewItem instanceof UnifiedNativeAd) {
return UNIFIED_NATIVE_AD_VIEW_TYPE;
}
return MENU_ITEM_VIEW_TYPE;
}
/**
* Returns the total number of items in the data set held by the adapter.
*/
@Override
public int getItemCount() {
return mPosts.size();
}
/**
* Update user views.
*
* @param holder ViewHolder that contains views for a comment
* @param user A user that left a comment
*/
private void updateUserViews(ViewHolder holder,User user) {
// load user's photo if present,otherwise show default
if (!isEmpty(user.getPhoto())) {
Picasso.get().load(user.getPhoto()).into(holder.userPhotoView);
} else {
holder.userPhotoView.setImageResource(R.drawable.ic_default_photo);
}
// bind click listener to user photo view
holder.userPhotoView.setOnClickListener(v -> {
if (mListener != null) {
mListener.onUserClick(user);
}
});
// show online icon in case user is online
holder.onlineView.setVisibility(user.isOnline() ? VISIBLE : INVISIBLE);
// set username text
holder.usernameView.setText(user.getUsername());
// bind click listener to username view
holder.usernameView.setOnClickListener(v -> {
if (mListener != null) {
mListener.onUserClick(user);
}
});
}
/**
* Set posts list that represent the data of this adapter.
*
* @param posts The list of posts
*/
public void setPosts(List<Post> posts) {
mPosts = (posts != null) ? posts : new ArrayList<>();
notifyDataSetChanged();
}
/**
* A ViewHolder describes an item view and metadata about its place within the RecyclerView.
*/
static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.user_photo_view)
CircleImageView userPhotoView;
@BindView(R.id.online_view)
ImageView onlineView;
@BindView(R.id.username_view)
TextView usernameView;
@BindView(R.id.date_view)
TextView dateView;
@BindView(R.id.image_view)
SquareImageView imageView;
@BindView(R.id.like_on_view)
ImageView likeOnView;
@BindView(R.id.like_off_view)
ImageView likeOffView;
@BindView(R.id.like_count_view)
TextView likeCountView;
@BindView(R.id.comment_view)
ImageView commentView;
@BindView(R.id.comment_count_view)
TextView commentCountView;
@BindView(R.id.caption_view)
EmojiTextView captionView;
@BindView(R.id.options_view)
ImageView mOptionsView;
@BindView(R.id.save_btn)
ImageView mSaveBtn;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
}
}
public class UnifiedNativeAdViewHolder extends RecyclerView.ViewHolder {
private UnifiedNativeAdView adView;
public UnifiedNativeAdView getAdView() {
return adView;
}
UnifiedNativeAdViewHolder(View view) {
super(view);
adView = (UnifiedNativeAdView) view.findViewById(R.id.ad_view);
// The MediaView will display a video asset if one is present in the ad,and the
// first image asset otherwise.
adView.setMediaView((MediaView) adView.findViewById(R.id.ad_media));
// Register the view used for each individual asset.
adView.setHeadlineView(adView.findViewById(R.id.ad_headline));
adView.setBodyView(adView.findViewById(R.id.ad_body));
adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action));
adView.setIconView(adView.findViewById(R.id.ad_icon));
adView.setPriceView(adView.findViewById(R.id.ad_price));
adView.setStarRatingView(adView.findViewById(R.id.ad_stars));
adView.setStoreView(adView.findViewById(R.id.ad_store));
adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser));
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。