Android notifyDataSetChanged()ListView项闪烁

Android notifyDataSetChanged()ListView项闪烁,android,listview,Android,Listview,我对ListView有问题。当应用程序启动时,它会从网络上加载10篇文章并显示出来。当您到达ListView的底部时,我开始加载下一个10个帖子,并将它们添加到列表的末尾。当我调用notifyDataSetChanged()ListView时,它将重新绘制不变的元素。这会导致奇怪的图像闪烁 我读到hasStableIds()可能会有帮助,并尝试在两个值中设置它,但都没有帮助 以下是我的适配器代码: public class PostListAdapter extends BaseAdap

我对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()
i调用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());
            }
        }
    };
}
那么,你能告诉我如何解决这个问题以及为什么它不起作用吗


提前感谢您的帮助。

我想您面临的问题可能是因为您在“活动”类中反复初始化“适配器”。每次在“数组”中添加新项时,都可能是在初始化适配器,然后在设置适配器后调用“notifyDataSetChanged()”方法。请确保只初始化一次适配器


还有一个建议,请尝试使用“毕加索”库加载图像。

我找到了方法。你应该做BasicAdapter应该做的工作,但由于某些原因,它做不到。在
getView()
中用新数据填充
convertView
之前,您应该检查
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()
请求的post,我们只返回它而不做任何更改,否则我们会进行更改以表示新的post

由于方法
hasStableIds()
的缘故,我认为适配器自己做这件事,并防止对
getView()
的无用调用,但他没有


希望它能帮助他人,并感谢您的回答和评论。

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

不。我100%确信我只在
onCreate()中初始化适配器一次。
。关于毕加索:一开始我想自己动手,不想使用任何外部库。但感谢您的推荐。如果您想制作自己的自定义模块,请尝试修改您的模块,并通过删除不必要的内容来优化其性能,这很好。当你完成了所有的努力,你仍然认为你的代码仍然需要一些修改,然后找到一些图像加载库代码,如“毕加索”或“通用图像加载程序”并将您的缓存过程代码与库代码进行比较。您是否考虑过使用RecyclerView,它可以更细粒度地控制数据集中哪些项发生了更改?是的,但RecyclerView仅在Android Lolipop中添加。我想用ListView来做。它在android支持库中提供,所以你也可以用旧版本的android。真的吗?!我会尝试,但这个问题现在对我来说是一个挑战。开箱即用,我认为您无法缓解您在ListView中看到的问题。notifyDataSetChanged相当于说“我不知道数据集中发生了什么变化,所以ListView(因为您也不知道)会重新绘制所有可见项。”很抱歉,
BaseAdapter
没有此消息。也许你说的是
RecyclerView
和他的适配器?哦,是的!我记得。这将是伟大的,如果你可以切换到回收的看法,然后我看到它。而且我已经找到了答案。现在我将用listview完成我的应用程序,之后我将它改为RecyclerView并比较它们。这对我帮助很大!请在充气前检查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;