改进大列表视图适配器平滑滚动,有时跳动

我试图看看是什么让我的列表视图在滚动时变得混蛋,有时它很糟糕,特别是当应用程序首次启动时。

我拥有的所有条件都是必要的,除非有我不知道的东西(极有可能)。我没有在单独的线程上运行某些任务,因为它们依赖于我从后端接收的数据(我正在对两者都进行编码,因此也欢迎后端建议)。产品处于测试阶段,但确实需要使它稍微平滑一些。我正在压缩图像,它们有点长,但这不是问题,因为当我从设备上传图像时,我还包括图像的宽度和高度,并将其发送到后端。加载列表时,这些维度会返回。

我想知道的一件事是,计算/转换特定设备屏幕的尺寸是否会导致轻微的滞后。不知道该任务占用了多少资源,但没有它(在不知道尺寸的情况下,每行都会从平面开始,然后扩展到实际的图片大小,这将导致列表跳跃,所以我也不能在后台运行该计算。

基本上滚动还不错,但我需要以某种方式改进这一点。

这是我的适配器:

public class VListAdapter extends BaseAdapter {

    ViewHolder viewHolder;
    private boolean isItFromProfile;

    /**
     * fields For number formating, ex. 1000
     * would return 1k in the format method
     */
    private static final NavigableMap<Long, String> suffixes = new TreeMap<>();

    static {
        suffixes.put(1_000L, "k");
        suffixes.put(1_000_000L, "M");
        suffixes.put(1_000_000_000L, "G");
        suffixes.put(1_000_000_000_000L, "T");
        suffixes.put(1_000_000_000_000_000L, "P");
        suffixes.put(1_000_000_000_000_000_000L, "E");
    }

    private Context mContext;
    private LayoutInflater mInflater;
    private ArrayList<Post> mDataSource;
    private static double lat;
    private static double lon;

    public VListAdapter(Context context, ArrayList<Post> items) {
        mContext = context;
        mDataSource = items;
        //mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        isItFromProfile = false;
        mInflater = LayoutInflater.from(context);
    }

    public VListAdapter() {

    }

    public VListAdapter(Context baseContext, ArrayList<Post> posts, boolean b) {
        mContext = baseContext;
        mDataSource = posts;
        //mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        isItFromProfile = b;
        mInflater = LayoutInflater.from(baseContext);
    }


    public void addElement(Post post) {
        mDataSource.add(0, post);
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return mDataSource.size();
    }

    @Override
    public Object getItem(int position) {
        return mDataSource.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }


    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        int limit = Math.min(position + 4, getCount());
        for (int i = position; i < limit; i++) {
            Glide.with(mContext).load(((Post) getItem(i)).getFilename().toString()).preload();
        }


//        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads()
//                .detectDiskWrites().detectNetwork()
//                .penaltyLog().build());



        View rowView = convertView;

        if (rowView == null) {
            viewHolder = new ViewHolder();
            rowView = mInflater.inflate(R.layout.mylist, parent, false);

            viewHolder.titleTextView = (TextView) rowView.findViewById(R.id.usernameinlist);
            viewHolder.timeago = (TextView) rowView.findViewById(R.id.timeago);
            //viewHolder.sharebutton = (ImageView) rowView.findViewById(R.id.sharebutton);
            viewHolder.likesTextView = (TextView) rowView.findViewById(R.id.likestext);
            viewHolder.viewcount = (TextView) rowView.findViewById(R.id.viewcount);
            viewHolder.distance = (TextView) rowView.findViewById(R.id.distance);
            viewHolder.footprints = (TextView) rowView.findViewById(R.id.footprintcount);
            viewHolder.postText = (TextView) rowView.findViewById(R.id.posttext);
            viewHolder.profilePic = (ImageView) rowView.findViewById(R.id.profilethumb);
            viewHolder.caption = (TextView) rowView.findViewById(R.id.captiontext);
            viewHolder.moremenu = (ImageView) rowView.findViewById(R.id.dots);
            viewHolder.likesPic = (ImageView) rowView.findViewById(R.id.likeimage);
            viewHolder.mapitPic = (ImageView) rowView.findViewById(R.id.mapimage);
            viewHolder.playbutton = (ImageView) rowView.findViewById(R.id.playbutton);
            viewHolder.videoThumb = (ImageView) rowView.findViewById(R.id.videothumb);
            viewHolder.listphoto = (ImageView) rowView.findViewById(R.id.listphoto);
            viewHolder.rainbow = (ImageView) rowView.findViewById(R.id.rainbow);
            rowView.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) rowView.getTag();
        }


        final Post post = (Post) getItem(position);
        int color = Color.parseColor("#dddddd");
        viewHolder.likesPic.setColorFilter(color);
        viewHolder.mapitPic.setColorFilter(color);
        viewHolder.moremenu.setColorFilter(color);


        if (Hawk.count() == 0)
            initHawkWithDataFromServer();

        if (isItFromProfile) {
            viewHolder.profilePic.setVisibility(View.GONE);
            viewHolder.titleTextView.setVisibility(View.GONE);
            viewHolder.distance.setVisibility(View.GONE);
        }

        viewHolder.titleTextView.setText(post.getUsername());
        PrettyTime prettyTime = new PrettyTime();
        DateTime dateTime = new DateTime(post.getUploadDate().get$date());
        viewHolder.timeago.setText(prettyTime.format(dateTime.toDate()));
        viewHolder.likesTextView.setText(String.valueOf(format(post.getLikes())));
        viewHolder.footprints.setText(String.valueOf(format(post.getLocation().size() - 1)));

        //don't display 0 if there are no likes, just show heart icon
        if (viewHolder.likesTextView.getText().equals("0"))
            viewHolder.likesTextView.setVisibility(View.GONE);
        else
            viewHolder.likesTextView.setVisibility(View.VISIBLE);



        //don't display 0 if there are no footprints
        if (viewHolder.footprints.getText().equals("0"))
            viewHolder.footprints.setVisibility(View.GONE);
        else
            viewHolder.footprints.setVisibility(View.VISIBLE);

        double[] loc = post.getLocation().get(0);
        viewHolder.distance.setText("~" + PostListFragment.distance(loc[0], loc[1], 'M') + " Miles");
        if (post.getViews() != null)
            viewHolder.viewcount.setText(format(post.getViews()) + (post.getViews() == 1 ? " View" : " Views"));

        String profilePictureS3Url = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + post.getUsername()
                + ".jpg";

        String filename = post.getS3link();
        final String videoThumbURL = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + filename;


        Glide.with(mContext).load(profilePictureS3Url).asBitmap().centerCrop().into(new BitmapImageViewTarget(viewHolder.profilePic) {
            @Override
            protected void setResource(Bitmap resource) {
                RoundedBitmapDrawable circularBitmapDrawable =
                        RoundedBitmapDrawableFactory.create(mContext.getResources(), resource);
                circularBitmapDrawable.setCircular(true);
                viewHolder.profilePic.setImageDrawable(circularBitmapDrawable);
            }
        });

        int height = ((Post) getItem(position)).getHeight();
        int width = ((Post) getItem(position)).getWidth();

        if (height != 0 && width != 0) {
            ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
            Resources r = mContext.getResources();
            height = (int) getHeight(height, width);
            params.height = height;
            params.width = ViewGroup.LayoutParams.MATCH_PARENT;
            viewHolder.listphoto.setLayoutParams(params);

        } else {
            ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
            params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
            params.width = ViewGroup.LayoutParams.MATCH_PARENT;
            viewHolder.listphoto.setLayoutParams(params);
        }

        if (post.getType() == null) {
            Glide.clear(viewHolder.listphoto);
            viewHolder.listphoto.setVisibility(View.GONE);
            //Glide.clear(viewHolder.listphoto);
            viewHolder.videoThumb.setVisibility(View.VISIBLE);
            viewHolder.rainbow.setVisibility(View.VISIBLE);
            Glide.with(mContext).load(videoThumbURL).fitCenter()
                    .diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate().into(viewHolder.videoThumb);
            viewHolder.playbutton.setVisibility(View.VISIBLE);

        }

        if (post.getType() != null) {
            if (post.getType().equals("video")) {
                viewHolder.playbutton.setVisibility(View.VISIBLE);
                Glide.clear(viewHolder.listphoto);
                viewHolder.listphoto.setVisibility(View.GONE);
                Glide.clear(viewHolder.postText);
                viewHolder.postText.setVisibility(View.GONE);
                viewHolder.videoThumb.setVisibility(View.VISIBLE);
                viewHolder.rainbow.setVisibility(View.VISIBLE);

                Glide.with(mContext).load(videoThumbURL).fitCenter()
                        .diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate().into(viewHolder.videoThumb);

            }

            if (post.getType().equals("image")) {
                Glide.clear(viewHolder.videoThumb);
                viewHolder.videoThumb.setVisibility(View.GONE);
                viewHolder.rainbow.setVisibility(View.GONE);
                Glide.clear(viewHolder.playbutton);
                viewHolder.playbutton.setVisibility(View.GONE);
                Glide.clear(viewHolder.postText);
                viewHolder.postText.setVisibility(View.GONE);
                viewHolder.listphoto.setVisibility(View.VISIBLE);
                viewHolder.listphoto.setBottom(0);

                Glide.with(mContext).load(post.getFilename().toString())
                        .diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate()
                        .into(viewHolder.listphoto);
            }

            if (post.getType().equals("text")) {
                Glide.clear(viewHolder.videoThumb);
                viewHolder.videoThumb.setVisibility(View.GONE);
                viewHolder.rainbow.setVisibility(View.GONE);
                Glide.clear(viewHolder.playbutton);
                viewHolder.playbutton.setVisibility(View.GONE);
                Glide.clear(viewHolder.listphoto);
                viewHolder.listphoto.setVisibility(View.GONE);
                viewHolder.postText.setVisibility(View.VISIBLE);
                viewHolder.postText.setText(post.getText());
            }

        }

        if (Hawk.contains("liked" + post.getId().get$oid())) {
            viewHolder.likesPic.clearColorFilter();
            Glide.with(mContext).load(R.drawable.heartroundorange).into(viewHolder.likesPic);
            ((ImageView) viewHolder.likesPic).setColorFilter(Color.parseColor("#ff3a6f"));
        } else {

            Glide.with(mContext).load(R.drawable.heartroundgray).diskCacheStrategy(DiskCacheStrategy.ALL)
                    .into(viewHolder.likesPic);
        }


        if (Hawk.contains("mapped" + post.getId().get$oid())) {
            viewHolder.mapitPic.clearColorFilter();
            ((ImageView) viewHolder.mapitPic).setImageResource(R.drawable.dropmaincolororange);
            ((ImageView) viewHolder.mapitPic).setColorFilter(Color.parseColor("#444444"));
        } else {
            Glide.with(mContext).load(R.drawable.dropdarkgray).diskCacheStrategy(DiskCacheStrategy.ALL)
                    .into(viewHolder.mapitPic);
        }


        if (!Hawk.contains("mapped" + post.getId().get$oid())) {
            viewHolder.mapitPic.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Hawk.put("mapped" + post.getId().get$oid(), 1);
                    ((ImageView) viewHolder.mapitPic).setImageResource(R.drawable.dropmaincolororange);
                    viewHolder.footprints.setText(String.valueOf(post.getLocation().size() + 1));
                    post.getLocation().add(new double[]{PostListFragment.lon, PostListFragment.lat});
                    notifyDataSetChanged();
                    Thread t = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            postMappedToServer(post.getId().get$oid());
                        }
                    });
                    t.start();
                    TastyToast.makeText(mContext, "Post dropped off here.", TastyToast.LENGTH_SHORT, TastyToast.CONFUSING);
                }
            });
        } else {
            viewHolder.mapitPic.setClickable(false);
        }

        if (!Hawk.contains("liked" + post.getId().get$oid())) {
            viewHolder.likesPic.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    Hawk.put("liked" + post.getId().get$oid(), 1);
                    viewHolder.likesPic.setClickable(false);
                    ((ImageView) viewHolder.likesPic).setImageResource(R.drawable.heartroundorange);
                    viewHolder.likesTextView.setText(String.valueOf(post.getLikes() + 1));
                    post.setLikes(post.getLikes() + 1);
                    notifyDataSetChanged();
                    Thread t = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            postLikeToServer(post);
                        }
                    });
                    t.start();
                }
            });
        } else {
            viewHolder.likesPic.setClickable(false);
        }


        if (post.getType() == null || post.getType().equals("video"))
            viewHolder.videoThumb.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    if (VListAdapter.this.mContext instanceof ProfileFeed) {
                        ((ProfileFeed) VListAdapter.this.mContext).closeActivity();
                    }

                    Intent broadcast = new Intent();
                    broadcast.setAction("com.molehead.openout.POST");

                    broadcast.putExtra("postId", post.getFilename().toString());
                    broadcast.putExtra("hawkId", post.getId().get$oid());
                    broadcast.putExtra("s3link", post.getS3link());
                    broadcast.putExtra("username", post.getUsername());

                    if (Hawk.contains("liked" + post.getId().get$oid()))
                        broadcast.putExtra("liked", "yes");
                    else
                        broadcast.putExtra("liked", "no");

                    broadcast.putExtra("likecount", post.getLikes().toString());

                    App.post = post;
                    LocalBroadcastManager.getInstance(mContext.getApplicationContext()).sendBroadcast(broadcast);
                }
            });

        viewHolder.moremenu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                PopupMenu popup = new PopupMenu(mContext.getApplicationContext(), viewHolder.moremenu, Gravity.CENTER);
                //Inflating the Popup using xml file
                popup.getMenuInflater().inflate(R.menu.menu_main, popup.getMenu());

                //registering popup with OnMenuItemClickListener
                popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    public boolean onMenuItemClick(MenuItem item) {
                        switch (item.getItemId()) {
                            case R.id.action_share:
                                String postId = post.getId().get$oid();
                                Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
                                sharingIntent.setType("text/plain");
                                String shareBody = postId + ".jpg"; //https://openout.herokuapp.com/posts/" + postId;
                                String shareSub = "Shared via Molehead";
                                sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, shareSub);
                                sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
                                sharingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                Intent new_intent = Intent.createChooser(sharingIntent, "Share");
                                new_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                mContext.getApplicationContext().startActivity(new_intent);
                                break;
                        }
                        return true;
                    }
                });

                popup.show();
            }
        });
        return rowView;
    }


    private void initHawkWithDataFromServer() {
        SharedPreferences settings = mContext.getApplicationContext().getSharedPreferences("userinfo", 0);
        String username = settings.getString("username", "ok");
        String password = settings.getString("password", "ok");


        LoginService loginService =
                ServiceGenerator.createService(LoginService.class, username, password);
        final Call<List<Post>> call = loginService.getLikes(username);
        Log.i("lonlat", String.valueOf(lon) + " and  " + String.valueOf(lat));


        call.enqueue(new Callback<List<Post>>() {
            @Override
            public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {

                ArrayList<Post> posts = new ArrayList<>();
                posts = (ArrayList<Post>) response.body();
                if (!posts.isEmpty())
                    for (Post p : posts) {
                        Hawk.put("liked" + p.getId().get$oid(), 1);
                    }
            }

            @Override
            public void onFailure(Call<List<Post>> call, Throwable t) {
            }
        });
    }


    private void postMappedToServer(String oid) {
        SharedPreferences settings = mContext.getSharedPreferences("userinfo", 0);
        String username = settings.getString("username", "ok");
        String password = settings.getString("password", "ok");
        LoginService loginService =
                ServiceGenerator.createService(LoginService.class, username, password);

        Log.i("postlistfraglat", String.valueOf(PostListFragment.lat));
        Call<ResponseBody> call = loginService.addLocation(oid, PostListFragment.lon, PostListFragment.lat);

        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.isSuccessful())
                    Log.i("mapped", "success");
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {

            }
        });
    }


    public void postLikeToServer(Post post) {

        SharedPreferences settings = mContext.getSharedPreferences("userinfo", 0);
        String username = settings.getString("username", "ok");
        String password = settings.getString("password", "ok");

        LoginService loginService =
                ServiceGenerator.createService(LoginService.class, username, password);

        Call<ResponseBody> call = loginService.like(post, 1, username);


        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

                if (response.isSuccessful()) {
                    try {
                        Log.i("call", response.body().string());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.i("MFEED", "like request failed");
            }
        });
    }


    public static String format(long value) {
        //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
        if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
        if (value < 0) return "-" + format(-value);
        if (value < 1000) return Long.toString(value); //deal with easy case

        Map.Entry<Long, String> e = suffixes.floorEntry(value);
        Long divideBy = e.getKey();
        String suffix = e.getValue();

        long truncated = value / (divideBy / 10); //the number part of the output times 10
        boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);

        return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
    }


    static class ViewHolder {
        private TextView titleTextView;
        private TextView timeago;
        private TextView likesTextView;
        private TextView viewcount;
        private TextView distance;
        private TextView footprints;
        private ImageView profilePic;
        private ImageView moremenu;
        private ImageView likesPic;
        private ImageView mapitPic;
        private ImageView rainbow;
        //private ImageView sharebutton;
        private TextView caption;
        private ImageView listphoto;
        private ImageView videoThumb;
        private ImageView playbutton;
        private TextView postText;
        private Post post;

    }


    private float getHeight(float height, float width) {
        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        return (height * size.x / width);

    }
}

答案 1

不可能指出特定问题,因为适配器中有太多代码。不过,有一件事是肯定的 - 在这种情况下,切换到对你没有帮助。RecyclerView

适配器不应包含业务逻辑 - 它们只应将输入对象“适应”基础视图。在您的例子中,适配器似乎执行计算,生成新线程,执行网络请求等。

您需要重构代码,以便适配器类似于以下内容:

public class PostsListAdapter extends ArrayAdapter<Post> {


    private Context mContext;

    public PostsListAdapter(Context context, int resource) {
        super(context, resource);
        mContext = context;
    }

    public void bindPosts(List<Post> posts) {
        clear();
        addAll(posts);
        notifyDataSetChanged();
    }


    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            // assign new View to convertView
            // create new ViewHolder
            // set ViewHolder as tag of convertView
            // set listeners
        } else {
            // get a reference to existing ViewHolder
        }

        // populate ViewHolder's elements with data from getItem(position)
        // kick off asynchronous loading of images
        // NOTE: no calculations allowed here - just simple bidding of data to Views

        return convertView;
    }

}

您的代码需要以这种方式进行结构化,即涉及在将新数据绑定到 之前执行的数据的计算和转换的业务逻辑,以及传递给方法的对象已经包含上述计算和转换的结果。ListViewPostbindPosts()

适配器只是“适应”最终数据 - 仅此而已。PostsViews

如果你现在时间紧迫,只需要“让它工作”,那么我会从删除生成新线程和发出网络请求的逻辑开始。查看这是否提高了性能。


答案 2
  • 更改在废弃视图或回收方面更有效的实现。RecyclerView
  • 如果项目是静态的,并且不会更改以明显平滑地滚动,我们也可以启用优化:

    recyclerView.setHasFixedSize(true);
    
  • 创建意向服务,并在API请求、业务规则、数据修改完成后注册为数据返回回调或错误回调。使用同步调用提前执行,从API获得结果后继续修改或应用业务逻辑。之后,创建新的适配器或更新现有的适配器数据集。BroadcastReceiverinitHawkWithDataFromServer()

  • 将以下所有数据计算或数据值格式化逻辑从适配器的函数服务移动到上述目的服务。getView()

    您可以向现有的Post pojo添加更多的getter和setter。

    DateTime dateTime = new DateTime(post.getUploadDate().get$date()); 
    viewHolder.timeago.setText(prettyTime.format(dateTime.toDate()));
    viewHolder.likesTextView.setText(String.valueOf(format(post.getLikes())));
    viewHolder.footprints.setText(String.valueOf(format(post.getLocation().size)) - 1)));
    
    Post{
        //Your existing property
        @Expose(serialize = false, deserialize = false)
        //equals neither serialize nor deserialize or
        private DateTime uploadedDateTime;
        //etc. prettyTime.format, String.valueOf
    }
    
  • 删除不必要的反射:

    GsonBuilder builder = new GsonBuilder();
    builder.excludeFieldsWithoutExposeAnnotation();
    Gson gson = builder.create();
    new  Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).build();
    

    并将其添加到您的改造服务创建类。您还可以使用瞬态(private transient DateTime uploadedDateTime;)

  • 删除,每当您需要通知单个或更多项目插入,删除等。使用以下命令:public void addElement(Post post) { mDataSource.add(0, post); this.notifyDataSetChanged();}

    notifyItemChanged(int)
    notifyItemInserted(int)
    notifyItemRemoved(int)
    notifyItemRangeChanged(int, int)
    notifyItemRangeInserted(int, int)
    notifyItemRangeRemoved(int, int)
    

我们可以从活动或片段中使用这些:

//Add a new contact
items.add(0, new Post("Barney"));
//Notify the adapter that an item was inserted at position 0
adapter.notifyItemInserted(0);

以上方法更有效率。每次我们想要在 中添加或删除项目时,我们都需要显式通知适配器该事件。与适配器不同,适配器不应依赖,因为应使用更精细的操作。有关更多详细信息,请参阅 API 文档RecyclerViewListViewRecyclerViewnotifyDataSetChanged()

此外,如果您打算更新现有列表,请确保在进行任何更改之前获取项目的当前计数。例如,应调用适配器上的 a 来记录将要更改的第一个索引。getItemCount()

// record this value before making any changes to the existing list
int curSize = adapter.getItemCount(); // replace this line with wherever you get new records
ArrayList<Post> newItems = Post.createPostsList(20);
// update the existing list
items.addAll(newItems);
// curSize should represent the first element that got added
// newItems.size() represents the itemCount
adapter.notifyItemRangeInserted(curSize, newItems.size());

比较较大的更改

在支持库的 v24.2.0 中添加了一个新类,以帮助计算旧列表和新列表之间的差异。DiffUtil

  • 如果图像大小不同,请勿通过滑动预加载图像。尝试创建自己的也试试看
  • 以类成员身份创建颜色

    int color = Color.parseColor("#dddddd");
    
  • 写入或在Post pojo本身中,这将在Retrofit的后台线程中执行,如果意图服务。尝试 api 在 json 中返回布尔值,而不是将“0”作为字符串。View.GONEView.VISIBLE

  • 如果没有喜欢,请将下面的所有内容移动到 IntentService //不要显示 0,如果 (viewHolder.likesTextView.getText().equals(“0”)) viewHolder.likesTextView.setVisibility(View.GONE);else viewHolder.likesTextView.setVisibility(View.VISIBLE);

    //don't display 0 if there are no footprints
    if (viewHolder.footprints.getText().equals("0"))
        viewHolder.footprints.setVisibility(View.GONE);
    else
        viewHolder.footprints.setVisibility(View.VISIBLE);
    
    double[] loc = post.getLocation().get(0);
    viewHolder.distance.setText("~" + PostListFragment.distance(loc[0], loc[1], 'M') + " Miles");
    
  • 所有字符串串联也在 Post 或 IntnetService 中,例如:

    String profilePictureS3Url = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + post.getUsername() + ".jpg";
    

此外,您可以提前创建彩色滤镜,并且只能创建一次。从列表视图中删除滚动条,因为它计算高度以显示滚动条。


推荐