Code Bye

关于Android4.0之上的ListView显示从网络上获取图片和文字

最进在做一个demo,然后使用到ListView,发现了一些问题。是这样的,我的最低版本是Android4.0,我在ListView中,显示从网络获取来的Image和Text,然后问题来了,由于不能在主线程中访问网络,我首先需要从网络下载数据,下载完成之后,在把数据显示出来,可是下载图片的时候是一个图片的网络资源路径,需要在自定义的Adapter中再去获取。但是这时候ListView绑定适配器已经不再主线程当中而是在第一次下载数据的线程中,假如我这时候在适配器里面使用一条新的线程去完成图片的真正下载,然后使用Handler去更新界面,可是它更新的是ListView的ImageView,而这个ImageView不再UI线程中,这应该怎么办?

10分
多线程下载图片,同时做好内存缓存和硬盘缓存
当然,这个要求你掌握比较多的知识点和开发经验
最好是来我们公司实习一段时间,这样你就全都懂了
30分

1, 数据获取:
        在第一次加载网络数据时是异步线程,加载完毕后会将数据载入适配器。这时第一个步骤完毕。
 2,适配器加载:
        在适配器的getview方法中启动异步线程下载图片,将imageview作为参数传入,并已url作为该imageview的tag值作为标记;
        当该异步线程图片下载完毕后使用Handler机制来更新imageview显示图片,同事对tag值进行校验。这时第二个步骤完毕。
        此时页面已更新数据和图片了。

引用 2 楼 li352558693 的回复:

1, 数据获取:
        在第一次加载网络数据时是异步线程,加载完毕后会将数据载入适配器。这时第一个步骤完毕。
 2,适配器加载:
        在适配器的getview方法中启动异步线程下载图片,将imageview作为参数传入,并已url作为该imageview的tag值作为标记;
        当该异步线程图片下载完毕后使用Handler机制来更新imageview显示图片,同事对tag值进行校验。这时第二个步骤完毕。
        此时页面已更新数据和图片了。

问题:我应该怎么保证数据获取完成之前不去绑定适配器呢?假如把数据绑定适配器这一步放在子线程里面,那么宅这个子线程中使用UI线程的Handler发送消息,他又不能直接在这个子线程中使用handleMessage(),而是需要发送到UI线程去处理,可是我现在需要更新的是LIstView的ImageView,那么又不能在UI线程去获得这个ImageView,这怎么破。假如能保证第一步的数据加载在子线程完成,完成之后再返回UI线程,之后UI线程里再去绑定适配器就行,所以问题就在这里了。我还是不能搞清楚。谢谢

引用 3 楼 liweijie_chengxuyuan 的回复:
Quote: 引用 2 楼 li352558693 的回复:

1, 数据获取:
        在第一次加载网络数据时是异步线程,加载完毕后会将数据载入适配器。这时第一个步骤完毕。
 2,适配器加载:
        在适配器的getview方法中启动异步线程下载图片,将imageview作为参数传入,并已url作为该imageview的tag值作为标记;
        当该异步线程图片下载完毕后使用Handler机制来更新imageview显示图片,同事对tag值进行校验。这时第二个步骤完毕。
        此时页面已更新数据和图片了。

问题:我应该怎么保证数据获取完成之前不去绑定适配器呢?假如把数据绑定适配器这一步放在子线程里面,那么宅这个子线程中使用UI线程的Handler发送消息,他又不能直接在这个子线程中使用handleMessage(),而是需要发送到UI线程去处理,可是我现在需要更新的是LIstView的ImageView,那么又不能在UI线程去获得这个ImageView,这怎么破。假如能保证第一步的数据加载在子线程完成,完成之后再返回UI线程,之后UI线程里再去绑定适配器就行,所以问题就在这里了。我还是不能搞清楚。谢谢

是这样的:
1,首先Listview是先绑定适配器的,比如说你在activity中初始化的时候就可以绑定一个数据为空的适配器;
      
    

                mListView = (P2RefreshListView) findViewById(R.id.wine_select);
		// 数据源准备
		mList = new ArrayList<String>();
		// 适配器初始化
		mAdapter = new SelectAdapter(this, mList);
		// 适配器装置
		mListView.setAdapter(mAdapter);

2,获取网络数据

              当然网络数据肯定是异步线程获取的,获取OK之后使用Handler发送出来;
              或者使用谷歌推荐的第三方框架Volley来获取数据(这个框架的请求结果回调是在主线程的,可以直接更新UI),

3,更新UI

              数据获取之后,可以通过Handler的Message通知主线程,这个时候主线程就可以更新Listview的UI了;此时listview中的imageview并未有bitmap加载,而是bitmap对应的url;

4,处理imageview对应url加载图片的问题
            
             在listview的适配器当中可以开启一个新的线程(或者使用开源第三方框架imageloader,这个很成熟,一句话就能搞定)
             ,在新的线程里面去下载该url对应的bitmap图片,
            比如:
            

            new Thread() {
					@Override
					public void run() {
						try {
							//下载图片
							DefaultHttpClient client = new DefaultHttpClient();
							HttpGet get = new HttpGet(url);
							HttpResponse response = client.execute(get);
							Bitmap bm = null;
							if (response.getStatusLine().getStatusCode() == 200) {
								HttpEntity entity = response.getEntity();
								byte[] by = EntityUtils.toByteArray(entity);
								bm = getBitmap(by, width, height);//图片压缩
							}
							Message msg = mHandler.obtainMessage();
							if (null != bm) {
								// 下载成功
								// 保存下载的图片
								cache.put(url, bm);//将图片保存到缓存  该缓存以url为key,以bitmap为对应值
								msg.what = LOADING_IMAGE;
							} else {
								msg.what = LOADING_FAIL;
							}
							// 发送通知
							msg.obj = url;
							mHandler.sendMessage(msg);
						} catch (Exception e) {
							e.printStackTrace();
						}
					};
				}.start();
            

         这样将bitmap存入本地和缓存当中后就可以发message,并将对应的url带出。handler接收后处理该message,imageview跟url是由tag属性绑定。这时可以准确的更新到该imageview的视图。

引用 4 楼 li352558693 的回复:
Quote: 引用 3 楼 liweijie_chengxuyuan 的回复:
Quote: 引用 2 楼 li352558693 的回复:

1, 数据获取:
        在第一次加载网络数据时是异步线程,加载完毕后会将数据载入适配器。这时第一个步骤完毕。
 2,适配器加载:
        在适配器的getview方法中启动异步线程下载图片,将imageview作为参数传入,并已url作为该imageview的tag值作为标记;
        当该异步线程图片下载完毕后使用Handler机制来更新imageview显示图片,同事对tag值进行校验。这时第二个步骤完毕。
        此时页面已更新数据和图片了。

问题:我应该怎么保证数据获取完成之前不去绑定适配器呢?假如把数据绑定适配器这一步放在子线程里面,那么宅这个子线程中使用UI线程的Handler发送消息,他又不能直接在这个子线程中使用handleMessage(),而是需要发送到UI线程去处理,可是我现在需要更新的是LIstView的ImageView,那么又不能在UI线程去获得这个ImageView,这怎么破。假如能保证第一步的数据加载在子线程完成,完成之后再返回UI线程,之后UI线程里再去绑定适配器就行,所以问题就在这里了。我还是不能搞清楚。谢谢

是这样的:
1,首先Listview是先绑定适配器的,比如说你在activity中初始化的时候就可以绑定一个数据为空的适配器;
      
    

                mListView = (P2RefreshListView) findViewById(R.id.wine_select);
		// 数据源准备
		mList = new ArrayList<String>();
		// 适配器初始化
		mAdapter = new SelectAdapter(this, mList);
		// 适配器装置
		mListView.setAdapter(mAdapter);

2,获取网络数据

              当然网络数据肯定是异步线程获取的,获取OK之后使用Handler发送出来;
              或者使用谷歌推荐的第三方框架Volley来获取数据(这个框架的请求结果回调是在主线程的,可以直接更新UI),

3,更新UI

              数据获取之后,可以通过Handler的Message通知主线程,这个时候主线程就可以更新Listview的UI了;此时listview中的imageview并未有bitmap加载,而是bitmap对应的url;

4,处理imageview对应url加载图片的问题
            
             在listview的适配器当中可以开启一个新的线程(或者使用开源第三方框架imageloader,这个很成熟,一句话就能搞定)
             ,在新的线程里面去下载该url对应的bitmap图片,
            比如:
            

            new Thread() {
					@Override
					public void run() {
						try {
							//下载图片
							DefaultHttpClient client = new DefaultHttpClient();
							HttpGet get = new HttpGet(url);
							HttpResponse response = client.execute(get);
							Bitmap bm = null;
							if (response.getStatusLine().getStatusCode() == 200) {
								HttpEntity entity = response.getEntity();
								byte[] by = EntityUtils.toByteArray(entity);
								bm = getBitmap(by, width, height);//图片压缩
							}
							Message msg = mHandler.obtainMessage();
							if (null != bm) {
								// 下载成功
								// 保存下载的图片
								cache.put(url, bm);//将图片保存到缓存  该缓存以url为key,以bitmap为对应值
								msg.what = LOADING_IMAGE;
							} else {
								msg.what = LOADING_FAIL;
							}
							// 发送通知
							msg.obj = url;
							mHandler.sendMessage(msg);
						} catch (Exception e) {
							e.printStackTrace();
						}
					};
				}.start();
            

         这样将bitmap存入本地和缓存当中后就可以发message,并将对应的url带出。handler接收后处理该message,imageview跟url是由tag属性绑定。这时可以准确的更新到该imageview的视图。

谢谢,终于解决了


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明关于Android4.0之上的ListView显示从网络上获取图片和文字