如何在Android应用中使滚动Feed更加流畅?

如何解决如何在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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-