【问题标题】:Download one item at a time from AsyncTask从 AsyncTask 一次下载一个项目
【发布时间】:2015-03-27 12:37:17
【问题描述】:

我有一个带有GridViewImageViews 作为项目的片段。细胞数量在 25 个左右。

对于每个图像,我都有一个按 ID 的服务器请求。所以它有 25 个服务器请求。需要2-3秒。

如何一次接收一张图片并将其动态设置为单元格的内容? 每个单元格,还没有图片应该包含ProgressBar

我现在有什么:我正在尝试加载 AsyncTask 中的项目并将 Bitmap 数组返回给 UI 线程。但我不知道如何为每个图像做到这一点。我的GridView 仅在所有图像下载后出现。它应该首先显示 25 个元素,其中包含 ProgressBars 并且没有图像。


代码

片段的onCreate():

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mItems = new Bitmap[dataChannelsList.size()];

    try {
    //starting AsyncTask
        mItems = new LoadImageAsyncTask(dataChannelsList).execute().get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

LoadImageAsyncTask:

private class LoadImageAsyncTask extends AsyncTask<Bitmap[], Void, Bitmap[]> {
    private ArrayList<DataChannels> dataChannelsList;
    private Bitmap[] bitmapList;

    public LoadImageAsyncTask(ArrayList<DataChannels> dataChannelsList) {
        this.dataChannelsList = dataChannelsList;

        bitmapList = new Bitmap[dataChannelsList.size()];
    }

    protected void onPreExecute() {
        super.onPreExecute();
    }

    protected Bitmap[] doInBackground(Bitmap[]... params) {
        for (int i = 0; i < dataChannelsList.size(); i++) {
            bitmapList[i] = getChannelImg(dataChannelsList.get(i).getId());
        }
        return bitmapList;
    }


    protected void onPostExecute(Bitmap[] param) {
        super.onPostExecute(param);
    }

    private Bitmap getChannelImg(String id) {
        ...returns Bitmap image by id
    }

}

GridView适配器:

    public class GridViewAdapter extends BaseAdapter {
    private Context mContext;
    private Bitmap[] mItems;

    public GridViewAdapter(Context context, Bitmap[] items) {
        mContext = context;
        mItems = items;
    }

    @Override
    public int getCount() {
        return mItems.length;
    }

    @Override
    public Object getItem(int position) {
        return mItems[position];
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;

        if (convertView == null) {
            // inflate the GridView item layout
            LayoutInflater inflater = LayoutInflater.from(mContext);
            convertView = inflater.inflate(R.layout.gridview_item, parent, false);

            // initialize the view holder
            viewHolder = new ViewHolder();
            viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.imageview_channelIcon);
            viewHolder.progressBar = (ProgressBar) convertView.findViewById(R.id.progress_bar_load_image);
            convertView.setTag(viewHolder);
        } else {
            // recycle the already inflated view
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // update the item view
        Bitmap item = mItems[position];

        //hide progress bar and bring image to top
        viewHolder.progressBar.setVisibility(View.GONE);
        viewHolder.ivIcon.setImageBitmap(item);
        return convertView;
    }

}

private static class ViewHolder {
    ImageView ivIcon;
    ProgressBar progressBar;
}

伙计们,我真的需要你们的帮助。 告诉是否需要更多代码或解释。

【问题讨论】:

  • 看看 Picasso stackoverflow.com/questions/22330772/…,或者至少回顾一下这样的开源解决方案来学习
  • 你应该调用适配器的 imageLoaderTask onGetView() 方法。此外,您的加载程序任务下载应该由适配器使用您的 image_id 进行参数化和调用。

标签: android gridview android-fragments android-asynctask


【解决方案1】:

您可以为此使用publishProgress() 调用onProgressUpdate()

所以在你的for loop 中类似

for (int i = 0; i < dataChannelsList.size(); i++) {
        // create a variable for the current bitmap
        Bitmap curBitmap = getChannelImg(dataChannelsList.get(i).getId()); 
        // add it to your list
        bitmapList[i] = curBitmap;
        // and pass it along
        publishProgress(curBitmap);
    }

那么你需要覆盖onProgressUpdate(),它被publishProgress()调用

@Override
public void onProgressUpdate(Bitmap...progress) {
    /* add the bitmap to your list you're using for your adapter here
     * and call notifyDataSetChanged() on your adapter
    */
}

然后您需要将您的 asynctask 更改为

private class LoadImageAsyncTask extends AsyncTask<Bitmap[], Bitmap, Bitmap[]> {

您也不想在您的AsyncTask 上调用.get(),因为it is a blocking call

与此类似的东西应该可以满足您的需求。

替代品

不过libraries that can do the work for you and give you benefits还是有很多的。

【讨论】:

    【解决方案2】:
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
    
        mItems = new Bitmap[dataChannelsList.size()];
        GridView grid=// declare your gridview;
    GridViewAdapter adapter=new GridViewAdapter(activityname.this,mItems);
    grid.setAdapter(adapter);
    
        try {
        //starting AsyncTask here
    
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    

    在异步任务中

    protected void onPostExecute(Bitmap[] param) {
            super.onPostExecute(param);
             adapter.notifydatasetchanged;
    
    // adapter should be declared as class variable,so that it can be used here.or else pass adapter variable as actual parameter to assynctask constructor
    
        }
    

    对于进度条,我认为您所做的是正确的 更改您的适配器类的

    @Override
        public int getCount() {
            return 25;// the size you want
        }
    

    getView 方法内部

      @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;
    
    int currentposition=position;
            if (convertView == null) {
                // inflate the GridView item layout
                LayoutInflater inflater = LayoutInflater.from(mContext);
                convertView = inflater.inflate(R.layout.gridview_item, parent, false);
    
                // initialize the view holder
                viewHolder = new ViewHolder();
                viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.imageview_channelIcon);
                viewHolder.progressBar = (ProgressBar) convertView.findViewById(R.id.progress_bar_load_image);
               viewHolder.ivIcon.setTag(currentposition);
                convertView.setTag(viewHolder);
            } else {
                // recycle the already inflated view
                viewHolder = (ViewHolder) convertView.getTag();
            }
    
            // update the item view
            Bitmap item = mItems[position];
    
            //hide progress bar and bring image to top
    
    if(Integer.parseInt(viewHolder.ivIcon.getTag().toString())>mItems.size()){
            viewHolder.progressBar.setVisibility(View.VISIBLE);
     viewHolder.ivIcon.setVisibility(View.VISIBLE);
    }
    else{
    viewHolder.progressBar.setVisibility(View.INVISIBLE);
     viewHolder.ivIcon.setVisibility(View.INVISIBLE);
    
    }
            viewHolder.ivIcon.setImageBitmap(item);
            return convertView;
        }
    
    }
    

    【讨论】:

    • 这永远行不通。不要在 AsyncTask 上使用 .get()。
    • @greenapps 请再次检查代码,好的……这不是我的代码行。
    • 为什么去掉调用asynctask的代码?此外,此代码对一次或一个一个地下载没有任何作用。那你要解决什么问题?
    • @greenapps 我现在有什么:我正在尝试在 AsyncTask 中加载项目并将位图数组返回给 UI 线程。但我不知道如何为每个图像做到这一点。我的 GridView 仅在所有图像下载后才会出现。它应该首先显示 25 个包含 ProgressBars 而没有图像的元素。这就是问题所在,需要在他现有的代码中添加上述代码行。他已经下载了代码,请阅读他的问题。我只是给了他建议,告诉他如何在每次图像下载后刷新他的 gridview 以及如何在其中显示进度条没有 iimage 的网格。仅此而已
    • But I don't know how to do that for every Image.。是的,这就是为什么我说它不起作用,codeMagic 的答案显示了它是如何完成的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    相关资源
    最近更新 更多