在 ListView 上通过 URI 重新加载 ImageView

Posted

技术标签:

【中文标题】在 ListView 上通过 URI 重新加载 ImageView【英文标题】:Reload ImageView by URI on ListView 【发布时间】:2016-02-16 19:37:02 【问题描述】:

我有一个由ImageView 组成的元素的ListView。我使用AsyncTask 获得了一个新图像,在onPostExecute(Object result) 方法中我使用setImageUri(Uri uri) 设置了图像,但它没有得到更新。

如果我更改活动或在应用程序之间更改,图像会完美显示,但我想立即显示图像。

我尝试使用ImageView、扩展BaseAdapter、父ListView 的所有组合调用invalidate(),但没有任何效果。我尝试了许多其他技术,例如调用setImageResource(0)setImageUri(null),但没有结果...

已编辑:

这里,部分代码:

public class ThingItemAdapter extends BaseAdapter 

    protected List<Thing> things;
    LayoutInflater inflater;

    public ThingItemAdapter(Context context, List<Thing> things) 
        this.things = things;
        this.inflater = LayoutInflater.from(context);
    

    @Override
    public int getCount() 
        return things.size();
    

    @Override
    public Thing getItem(int position) 
        return things.get(position);
    

    @Override
    public long getItemId(int position) 
        return things.get(position).getId();
    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
        final int pos = position;

        final ViewHolder holder;
        if (convertView == null) 
            holder = new ViewHolder();
            convertView = this.inflater.inflate(R.layout.thing_list_item, parent, false);
            holder.thingImageView = (ImageView) convertView.findViewById(R.id.thing_preview);
            holder.button = (ImageButton) convertView.findViewById(R.id.apply_button);
            convertView.setTag(holder);
         else 
            holder = (ViewHolder) convertView.getTag();
        

        final Thing thing = things.get(position);
        final long thingId = thing.getId();

        final Uri thingUri = thing.getPicture();
        holder.thingImageView.setImageURI(thingUri);

        holder.button.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                // generate new file
                final TypedFile typedFile = new TypedFile("multipart/form-data", new File(thingUri.getPath()));

                new ReadAndStorePictureTask()
                        .execute(new Object[]  typedFile, holder.thingImageView, thing );
            
        );

        // item detailed view listener
        holder.thingImageView.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                Intent intent = new Intent((ThingApplication) ThingApplication.getContext(), ThingActivity.class);
                intent.putExtra(ThingActivity.EXTRA_THING_ID, thingId);
                context.startActivity(intent);
            
        );

        return convertView;
    

    private class ViewHolder 
        ImageView thingImageView;
        ImageButton button;
    

    private class ReadAndStorePictureTask extends AsyncTask<Object, Void, Void> 

        ImageView imageView;
        Thing thing;
        ViewGroup parent;

        protected Void doInBackground(Object... params) 

            final TypedFile typedFile = (TypedFile) params[0];
            imageView = (ImageView) params[1];
            thing = (Thing) params[2];

            ((ThingApplication) ThingApplication.getContext()).getClient().apply(typedFile,
                    new Callback<Response>() 

                        @Override
                        public void failure(RetrofitError error) 
                            ...
                        

                        @Override
                        public void success(Response nothing, Response response) 
                            try 
                                byte[] bytes = ThingApplication.getBytesFromStream(response.getBody().in());
                                Uri newImageURI = Uri.parse("uri://valid_uri"); // whatever, it exists in real code
                                thing.setPicture(newImageURI);
                                File file = ((ThingApplication) ThingApplication.getContext())
                                        .getFileFromURI(newImageURI); // this method works

                                ThingApplication.saveBytesToFile(bytes, file.getAbsolutePath());
                                thingService.storeThing(thing);
                             catch (Exception e) 
                                ...
                            
                        

                    );
            return null;
        

        @Override
        protected void onPostExecute(Void result) 
            imageView.setImageURI(thing.getPicture());

            // force redraw. FIXME not working          
            /*
            * ANSWER HERE, PLEASE
            */

        
    

如何在 onPostExecute(Object result) 方法中立即显示更新后的 URI?

【问题讨论】:

我想,你已经使用了 notifyDataSetChanged();,那么你应该展示一些你的代码,以便我可以帮助你 @androider 代码已添加。 【参考方案1】:

onPostExecute 更新链接到 ListView 适配器的图像列表,然后通过调用通知适配器您更改了列表中的项目:

adapter.notifyDataSetChanged();

【讨论】:

如果您粘贴适配器,我会尽力帮助您【参考方案2】:

你可以这样做:

-更改异步任务调用中的第三个参数。

new ReadAndStorePictureTask().execute(
    new Object[]  typedFile, holder.thingImageView, pos );

-然后,修改asynctask里面的列表项并刷新。

private class ReadAndStorePictureTask extends AsyncTask<Object, Void, Void> 

        ImageView imageView;
        int position;
        ViewGroup parent;

        protected Void doInBackground(Object... params) 

            final TypedFile typedFile = (TypedFile) params[0];
            imageView = (ImageView) params[1];
            position = (Integer) params[2];

            ((ThingApplication) ThingApplication.getContext()).getClient().apply(typedFile,
                    new Callback<Response>() 

                        @Override
                        public void failure(RetrofitError error) 
                            ...
                        

                        @Override
                        public void success(Response nothing, Response response) 
                            try 
                                byte[] bytes = ThingApplication.getBytesFromStream(response.getBody().in());
                                Uri newImageURI = Uri.parse("uri://valid_uri"); // whatever, it exists in real code
                                things.get(position).setPicture(newImageURI);
                                File file = ((ThingApplication) ThingApplication.getContext())
                                        .getFileFromURI(newImageURI); // this method works

                                ThingApplication.saveBytesToFile(bytes, file.getAbsolutePath());
                                thingService.storeThing(things.get(position));
                             catch (Exception e) 
                                ...
                            
                        

                    );
            return null;
        

        @Override
        protected void onPostExecute(Void result) 
            notifyDataSetChanged();
        
    

祝你好运!

【讨论】:

不工作。如果你看到,它是一样的,我正在传递一个从该位置提取的“东西”。在 AsyncTask 外部或内部获取它是一样的。 postExecute() 可能在 doInbackground() 完成之前运行,因为方法 new Callback 在其他线程中运行。 是的!!!这就是确切的原因。我更改了代码以进行同步调用。用这个确切的评论编辑你的答案,我会检查它是否正确;)

以上是关于在 ListView 上通过 URI 重新加载 ImageView的主要内容,如果未能解决你的问题,请参考以下文章

Flutter StreamBuilder ListView在流数据更改时不会重新加载

通过 uri / 通过它包含的数据获取 ListView 项目位置

setState 方法重新加载列表视图。我怎样才能阻止它?扑

在android中滚动listView时重新加载图像

如何通过滑翔(或其他)在listView项目中加载小部件中的图像

使用共享首选项保存和重新加载 ListView [保存 onDestroy()]