Android:更高效的解决方案,可在运行时从互联网上获取图像并在列表视图中显示

时间:2012-11-13 12:45:56

标签: android listview

情景:有点棘手但很有趣。 我发送了一个请求,它会给我一个JSON响应。此响应将进一步包含10个JSON请求URL。

然后,我会向这10个网址发送请求,然后每个网址将包含2个图片网址。这意味着共有20张图片。

我的目的是尽可能快地以ListView向用户显示这些图像。 这就是我到目前为止所做的事情:

第1步:一旦活动开始,请弹出显示加载圈的ProgressDialog,如同在youtube中一样。

第2步:在AN ASYNC TASK中,发送第一个请求,该请求提供这10个JSON请求的网址。发送此请求然后解析&存储这10个URL是响应。

第3步:从第一个(从10开始)开始,发送将提供JSON响应的请求。

第4步:解析此响应以获取2个图片网址并存储在LinkedList中。

第5步:由于我们现在拥有图像的实际链接,请关闭进度对话框并获取图像。

第6步:此图片将存储在drawable中。我制作了名为BaseAdapter的自定义ImageAdapter ArrayList<Drawable> mImages;

第7步:使用以下内容将收到的drawable存储在此ArrayList中:adapter.mImages.add(drawable);

第8步:然后调用adapter.notifyDataSetChanged();这将在图像准备好显示后立即更新列表视图。

第9步:返回第3步以处理更多网址。

下面是代码(条纹所有不必要的代码):

ActivityClass

public class ImageViewer extends Activity {
    GridView gvImage;
    private ProgressDialog progressDialog;
    private final static Integer IMAGE_LIMIT = 10;
    private ImageAdapter adapter;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            setContentView(R.layout.ImageViewer);
            gvImage = (GridView) findViewById(R.id.gvImage);
            adapter = new ImageAdapter(this);
            gvImage.setAdapter(adapter);

            progressDialog = ProgressDialog.show(ImageViewer.this, "In Progress",
                    "Loading...", true, true, new DialogInterface.OnCancelListener() {

                        public void onCancel(DialogInterface dialog) {
                            finish();
                        }
                    });
            new SendRequest().execute(null);
        } catch (Exception e) {
        }
    }

    class SendRequest extends AsyncTask {
        protected Object doInBackground(Object... params) {
            try {
                HttpClient client = new DefaultHttpClient(httpParameters);
                HttpContext localContext = new BasicHttpContext();
                HttpGet httpGet = new HttpGet(BaseRequest_URL);

                JSONObject jsonResponse = null;

                HttpResponse httpResponse = client.execute(httpGet, localContext);
                if (httpResponse.getStatusLine().getStatusCode() == 200) {
                    HttpEntity entity = httpResponse.getEntity();
                    jsonResponse = getJSONObjectFromEntity(entity); //getJSONObjectFromEntity() will return JSONObject
                    processJSON(jsonResponse);
                }
                progressDialog.dismiss();
            } catch (Exception e) {
            }
            return null;
        }

        private void processJSON(JSONObject jsonResponse) throws JSONException {
            for (int i = 0; i < IMAGE_LIMIT; i++) {
                // Some JSON parsing. Output will be 'imageURL' which will be image URL
                displayImage(imageURL);
            }
        }

        public void displayImage(String uri150) {
            try {
                InputStream is = (InputStream) new URL(uri150).getContent();
                if(progressDialog.isShowing()){
                    progressDialog.dismiss();
                }
                Drawable d = Drawable.createFromStream(is, "image 150");
                adapter.mImages.add(d);
                handler.sendEmptyMessage(0); // Handler Below
            } catch (Exception e) {
            }
        }

        protected void onPostExecute(Object result) {
            super.onPostExecute(result);
        }
    }

    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            adapter.notifyDataSetChanged();
        };
    };
}

ImageAdapter类:

public class ImageAdapter extends BaseAdapter {
    Context context;
    public ArrayList<Drawable> mImages = new ArrayList<Drawable>();

    public ImageAdapter(Context c) {
        this.context = c;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imageView = new ImageView(context);
        try {
            imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setImageDrawable(mImages.get(position));
            imageView.setTag("Image" + position);
        } catch (Exception e) {
        }
        return imageView;
    }
}

问题:

  1. 我看到ImageAdapter的方式被多次调用。还有其他方法可以减少它。

  2. 如何优化ImageAdapter的代码。

  3. 还有其他改进吗?

4 个答案:

答案 0 :(得分:1)

我可以告诉您,确保错误将图像存储在内存中,因为您可以获得 OutOfMemoryException

要了解如何处理图片和缓存,请访问Displaying Bitmaps Efficiently

答案 1 :(得分:1)

  1. (前两个问题)适配器不仅控制哪一行(列表中的视图)出现,它还会回收它。在您的适配器中,getView每次调用时都会创建一个新视图,如果旧视图不可用,它应该只创建一个新视图。查看Mark Murphy(commonsware)的适配器here

  2. 在您的代码中,所有图像都会在进度对话框中下载。你的用户可能不会将它们全部看到最后一个,这肯定会增加你的记忆力。我建议你延迟加载JSON和图像(请求你的JSON,解析它,异步加载图像,具体取决于你的用户看到/滚动的网格数量)。关于图像延迟加载已经有很多讨论,你一定要从Fedor的answer开始。

答案 2 :(得分:0)

试试this库。这对于layz加载非常有用。

答案 3 :(得分:0)

只搜索Android LazyImageLoading

祝你好运