notifyDataSetChanged()ListView项目闪烁

时间:2017-05-11 21:24:44

标签: android listview

我遇到了ListView的问题。当应用程序启动时,它会从网上加载10个帖子并显示它们。当你到达ListView的底部时,我开始加载下一个10帖子并在列表末尾添加它们。当我调用notifyDataSetChanged()时,ListView将重绘不会改变的元素。这会导致奇怪的图像闪烁。

我读过hasStableIds()可以提供帮助,并试图在两个值中设置它,但它没有帮助。

这是我的适配器代码:

    public class PostListAdapter extends BaseAdapter {
    Context context;
    ArrayList<Post> posts;
    LayoutInflater inflater;
    View.OnClickListener onClickListener;

    public PostListAdapter(Context context, ArrayList<Post> posts, View.OnClickListener onClickListener){
        this.posts = posts; this.context = context; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.onClickListener = onClickListener;
    }

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

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

    @Override
    public long getItemId(int position) {
        return (long)posts.get(position).id;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        System.out.println("draw " + posts.get(position).id);
        LinearLayout mainLayout;
        if (convertView == null) {
            mainLayout = (LinearLayout) inflater.inflate(R.layout.post, null, false);
        }else {
            mainLayout = (LinearLayout) convertView;
            LinearLayout cont = (LinearLayout) mainLayout.findViewById(R.id.image_container);
            while (cont.getChildCount() != 0){
                cont.removeViewAt(0);
            }

        }


        LinearLayout imageContainer = (LinearLayout) mainLayout.findViewById(R.id.image_container);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        Post post = posts.get(position);
        TextView textView = (TextView)mainLayout.findViewById(R.id.postLink);

        textView.setText("http://joyreactor.cc/post/" + Integer.toString(post.id));
        textView.setPaintFlags(textView.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
        textView.setOnClickListener(onClickListener);
        ArrayList<ImageView> images = new ArrayList<>();
        for (int i=0; i<post.images.size(); i++){
            ScaleImageView image = new ScaleImageView(context);
            image.setPadding(0, 10, 0, 0);
            image.setImageBitmap(Bitmap.createBitmap(post.sizes.get(i)[0], post.sizes.get(i)[1], Bitmap.Config.RGB_565));
            //image.setImageResource(R.drawable.grill);
            image.setLayoutParams(params);
            ImageLoader loader = new ImageLoader(image, post, i, context);
            loader.execute(post.images.get(i));
            post.loaders.add(loader);
            imageContainer.addView(image);
        }


        if (post.images.size() == 0){
            ScaleImageView image = new ScaleImageView(context);

            image.setLayoutParams(params);

            image.setImageBitmap(MainActivity.bmpMissPicture);
            imageContainer.addView(image);
        }
        mainLayout.setTag(post);
        return mainLayout;

    }
}

notifyDataSetChanged()之后,您可以看到适配器重新加载视图的日志,即使我没有滚动它。

05-11 21:00:46.406 4391-4391/com.olleggerr.joyrector I/System.out: draw 3098998
05-11 21:00:46.414 4391-4391/com.olleggerr.joyrector I/System.out: draw 3099753
05-11 21:00:46.416 4391-4391/com.olleggerr.joyrector I/System.out: draw 3098998
05-11 21:00:46.417 4391-4391/com.olleggerr.joyrector I/System.out: draw 3099753
05-11 21:00:49.039 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100202
05-11 21:00:49.172 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100315
05-11 21:00:49.304 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100328
05-11 21:00:49.455 4391-4391/com.olleggerr.joyrector I/System.out: draw 3098651
05-11 21:00:49.755 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100191
05-11 21:00:50.038 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100287
05-11 21:00:51.754 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100348
05-11 21:00:51.838 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100386
05-11 21:00:51.938 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100348
05-11 21:00:52.411 4391-4691/com.olleggerr.joyrector I/System.out: 10 posts load started!
05-11 21:00:56.806 4391-4391/com.olleggerr.joyrector I/System.out: calling notifyDataSetChanged()
05-11 21:00:56.807 4391-4391/com.olleggerr.joyrector I/System.out: Size after load more posts 20
05-11 21:00:56.821 4391-4391/com.olleggerr.joyrector I/System.out: draw 3098998
05-11 21:00:56.821 4391-4391/com.olleggerr.joyrector I/System.out: draw 3099753
05-11 21:00:56.822 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100348
05-11 21:00:56.822 4391-4391/com.olleggerr.joyrector I/System.out: draw 3100386

同样notifyDataSetChanged()我在MainActivity线程中从处理程序调用:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    bmpMissPicture = Bitmap.createBitmap(500, 500, Bitmap.Config.RGB_565);
    Canvas c = new Canvas(bmpMissPicture);
    Paint p = new Paint();
    ListView listView = (ListView) findViewById(R.id.postList);
    View.OnClickListener onClickListener = new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(((TextView) v).getText().toString()));
            startActivity(browserIntent);
        }
    };
    adapter = new PostListAdapter(getApplicationContext(), posts, onClickListener);
    listView.setAdapter(adapter);
    p.setColor(getResources().getColor(R.color.missPicColor));
    c.drawRect(0, 0, 500, 500, p);
    handler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(Message msg) {
            System.out.println("calling notifyDataSetChanged()");
            if (msg.what == 0) {
                ((LinearLayout) findViewById(R.id.mainContainer)).removeViewAt(0);
                findViewById(R.id.mainContainer).invalidate();
                findViewById(R.id.postList).invalidate();
                adapter.notifyDataSetChanged();
                //System.out.println(posts.size());
                final ListView listView = (ListView) findViewById(R.id.postList);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while (!stopAskUpdate){
                            int pos = listView.getLastVisiblePosition();
                            //Log.d("Inf Scroll", "Pos: " + (pos+1) + " of " + posts.size());
                            if (pos >= posts.size()-1 && !loadNewPosts){
                                MainActivity.loadNewPosts = true;
                                new PageParser("http://joyreactor.cc/" + nextPage, posts, MainActivity.handler, false).start();
                            }
                            try{Thread.sleep(1500);}catch (InterruptedException e){}
                        }
                    }
                }).start();
            }else {
                adapter.notifyDataSetChanged();
                System.out.println("Size after load more posts " + posts.size());
            }
        }
    };
}

所以你能告诉我如何解决这个问题以及为什么它不起作用。

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

我猜您遇到的问题是因为您可能会一次又一次地在“活动”类中初始化“适配器”。每次在“数组”中添加新项时,都可能正在初始化适配器,然后在设置适配器后调用“notifyDataSetChanged()”方法。请让您初始化适配器一次。

另外一个建议是尝试使用“Picasso”库进行图像加载。

答案 1 :(得分:0)

我找到了办法。你应该做BasicAdapter应该做的工作,但由于某些原因它没有做到。在使用convertView中的新数据填充getView()之前,您应检查convertView是否已包含该数据。对于我的情况,解决方案看起来像:

@Override
public long getItemId(int position) {
    return (long)posts.get(position).id;
}

public View getView(int position, View convertView, ViewGroup parent) {
    boolean flag = false;

    LinearLayout mainLayout;
    if (convertView == null) {
        flag = true;
        mainLayout = (LinearLayout) inflater.inflate(R.layout.post, null, false);
    }else {
        mainLayout = (LinearLayout) convertView;
        if (((Post)convertView.getTag()).id != getItemId(position)){ //View tag contain link to the post.
            flag = true;
            LinearLayout cont = (LinearLayout) mainLayout.findViewById(R.id.image_container);
            while (cont.getChildCount() != 0){
                cont.removeViewAt(0);
            }
        }
    }

    if (flag) {
        //do some stuff with mainLayout....
        mainLayout.setTag(posts.get(position));
    }
    return mainLayout;

因此,如果convertView代表getView()个请求的帖子,我们只会返回它而不做任何更改,否则我们会进行更改以代表新帖子。

由于方法hasStableIds()我认为适配器是自己做的并且防止无用的getView()调用,但他没有。

希望它会对某人有所帮助,并感谢您的回答和评论。

答案 2 :(得分:0)

您可以在数组中添加和删除项目,并可以调用notifyItemInserted或notifyitemRemoved,这将使您获得更好的性能。此外,使用毕加索将是一个不错的选择。