改进大型ListView适配器平滑滚动,有时生涩

时间:2017-01-13 10:20:17

标签: java android performance android-layout listview

我试图看看滚动时有时候我的listview jerk是什么,有时它很糟糕,特别是当应用程序首次启动时。

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

我想知道的一件事是,计算/转换特定设备屏幕的尺寸是否会导致轻微的延迟。不确定该任务的资源密集程度如何,但没有它(不知道尺寸,每行将开始平坦然后扩展到实际图片大小,这将导致列表跳转,所以我不能运行该计算在背景上。)

基本上滚动并不坏,但我需要以某种方式改进它。

这是我的适配器:

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);

    }
}

3 个答案:

答案 0 :(得分:6)

由于适配器中存在大量代码,因此无法指出特定问题。但有一件事是肯定的 - 在这种情况下切换到RecyclerView无法帮助你。

适配器不应包含业务逻辑 - 它们只应该适应&#34;将对象输入到基础视图。在您的情况下,似乎适配器执行计算,生成新线程,执行网络请求等。

您需要重构代码,以使适配器与此类似:

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;
    }

}

您的代码需要以这样的方式构建,即在将新数据绑定到ListView之前执行的数据的计算和转换以及传递给Post的对象的业务逻辑{1}}方法已包含上述计算和转换的结果。

适配器只是&#34;适应&#34;从bindPosts()Posts的最终数据 - 仅此而已。

如果你现在时间不够短,只需要让它工作&#34;,那么我将首先删除产生新线程并发出网络请求的逻辑。看看这是否会提高性能。

答案 1 :(得分:4)

  • 将您的实施方式更改为RecyclerView,这在废弃视图或回收方面效率更高。
  • 如果项目是静态的,我们也可以启用优化,并且不会更改以实现更顺畅的滚动:

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

  • 将以下所有数据计算或数据值格式化逻辑从适配器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();
    

    它适用于您的改造服务创建类。 您还可以使用transient(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);

以上方法效率更高。每次我们想要添加或删除RecyclerView中的项目时,我们都需要明确地通知适配器事件。与ListView适配器不同,RecyclerView适配器不应依赖notifyDataSetChanged(),因为应使用更细粒度的操作。 See the API documentation for more details

此外,如果您打算更新现有列表,请确保在进行任何更改之前获取当前项目数。例如,应该调用适配器上的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类,以帮助计算旧列表和新列表之间的差异。 Details

  • 如果图像尺寸不同,请不要通过滑行预加载图像。 Try creating your ownAlso try looking at
  • 创建颜色作为类成员

    int color = Color.parseColor("#dddddd");
    
  • 在Post pojo中写View.GONEView.VISIBLE,如果是IntentService,它将在Retrofit的后台线程中执行。在json中尝试api return boolean而不是&#34; 0&#34; as String。

  • 将以下全部内容移至IntentService //如果没有喜欢,请不要显示0,只显示心形图标     if(viewHolder.likesTextView.getText()。equals(&#34; 0&#34;))         viewHolder.likesTextView.setVisibility(View.GONE);     其他         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";
    

您也可以提前创建一次彩色滤镜。从listview中删除滚动条,因为它计算高度以显示滚动条。

答案 2 :(得分:1)

这里需要改进的东西太多了。以下是一些例子。

我看到了这个

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

我相信在列表出现的时候会多次调用initHawkWithDataFromServer方法。

此活动只能在创建活动时完成。

Glide.with(mContext).load(videoThumbURL).fitCenter()

但是你应该首先重构代码,将逻辑移到另一个类。尝试删除一些这样的代码(它应该通过使用一些布局属性来完成)

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);