从网站解析JSON异步加载到ListView事例
2016-03-08 16:05
671 查看
从http://www.imooc.com/learn/406学习到「从网站解析JSON异步加载到ListView」这样一个例子。整理如下。
主要知识点包括:异步(子线程)下载图片、图片的缓存、JSON解析
最终列表效果如图
主布局就是一个ListView,没什么好说的。
然后是每个子View的布局
默认左边一张android机器人小图,右边标题和内容
MainActivity中的url是一个慕课网的API
可以看到整个的首先是一个Object,点击展开
我们需要的是这个名为“data”的JSONArray
遍历JSONArray中的每个JSONObject,我们需要的就是里面的数据。把他们存进一个NewsBean封装类里
完成后把List<NewsBean> newsBeans传入我们自定义的Adapter中,加载到ListView里显示出来。
那么我们具体的去看看这个自定义的Adapter
ListView中经典的利用convertView和ViewHolder避免多次加载的技巧我们当然用到了,我们还用到了一个自定义的类,用这个类中的方法去加载图片。那我们去看看这个类。
值得注意的是,我们之前在Adapter中已经对每个imageView设置了特定的Tag,在这里就用到了这个判断,保证不会因为imageView的复用出现图片多次加载的情况。至此整个demo就基本完成了。
主要知识点包括:异步(子线程)下载图片、图片的缓存、JSON解析
最终列表效果如图
主布局就是一个ListView,没什么好说的。
然后是每个子View的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <ImageView android:id="@+id/image_view" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/ic_launcher" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:orientation="vertical" android:paddingLeft="5dp"> <TextView android:id="@+id/title_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="1" android:text="Title" android:textSize="15sp" /> <TextView android:id="@+id/content_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="3" android:text="content" android:textSize="10sp" /> </LinearLayout> </LinearLayout>
默认左边一张android机器人小图,右边标题和内容
public class MainActivity extends AppCompatActivity { private ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.list_view); String URL = "http://www.imooc.com/api/teacher?type=4&num=30"; /*开启异步进程*/ new newsAsyncTask().execute(URL); } class newsAsyncTask extends AsyncTask<String, Void, List<NewsBean>> { @Override protected List<NewsBean> doInBackground(String... params) { String url = params[0]; List<NewsBean> newsBeanList = new ArrayList<>(); NewsBean newsBean; try { /*打开url对应的输入流,用readStream方法得到String格式的数据*/ String jsonString = readStream(new URL(url).openStream()); JSONObject jsonObject = new JSONObject(jsonString); JSONArray jsonArray = jsonObject.getJSONArray("data"); for (int i = 0; i < jsonArray.length(); i++) { /*每个JSONArray里的一项都是一个包含图片、标题、内容的JSONObject对象,依次把他们存入 * 一个封装的newsBean数组中*/ jsonObject = jsonArray.getJSONObject(i); newsBean = new NewsBean(); newsBean.newsImageUrl = jsonObject.getString("picSmall"); newsBean.newsTitle = jsonObject.getString("name"); newsBean.newsContent = jsonObject.getString("description"); newsBeanList.add(newsBean); } } catch (IOException | JSONException e) { e.printStackTrace(); } return newsBeanList; } @Override protected void onPostExecute(List<NewsBean> newsBeans) { super.onPostExecute(newsBeans); NewsArrayAdapter newsArrayAdapter = new NewsArrayAdapter(MainActivity.this, R.layout.item_layout, newsBeans); listView.setAdapter(newsArrayAdapter); } } private String readStream(InputStream inputStream) { String result = ""; try { String line; InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); while ((line = bufferedReader.readLine()) != null) { result += line; } } catch (IOException e) { e.printStackTrace(); } return result; } }
MainActivity中的url是一个慕课网的API
可以看到整个的首先是一个Object,点击展开
我们需要的是这个名为“data”的JSONArray
遍历JSONArray中的每个JSONObject,我们需要的就是里面的数据。把他们存进一个NewsBean封装类里
public class NewsBean { public String newsImageUrl; public String newsTitle; public String newsContent; }
完成后把List<NewsBean> newsBeans传入我们自定义的Adapter中,加载到ListView里显示出来。
那么我们具体的去看看这个自定义的Adapter
public class NewsArrayAdapter extends ArrayAdapter<NewsBean> { private int resource; private List<NewsBean> objects; private ImageLoader imageLoader; public NewsArrayAdapter(Context context, int resource, List<NewsBean> objects) { super(context, resource, objects); this.resource = resource; this.objects = objects; imageLoader = new ImageLoader(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; ViewHolder viewHolder; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resource, null); /*viewHolder用来对控件实例进行缓存,避免每次通过findViewById()获取控件*/ viewHolder = new ViewHolder(); viewHolder.titleView = (TextView) view.findViewById(R.id.title_text); viewHolder.contentView = (TextView) view.findViewById(R.id.content_text); viewHolder.imageView = (ImageView) view.findViewById(R.id.image_view); view.setTag(viewHolder); } else { view = convertView; viewHolder = (ViewHolder) view.getTag(); } viewHolder.titleView.setText(objects.get(position).newsTitle); viewHolder.contentView.setText(objects.get(position).newsContent); String imageUrl = objects.get(position).newsImageUrl; /*每个imageView设置独立对应的标签(对应的url),避免上下滑动listView时, 缓存中的图片加载显示到不对应的imageView中*/ viewHolder.imageView.setTag(imageUrl); /*通过自定义的imageLoader类设置图片*/ imageLoader.setImageByThread(viewHolder.imageView, imageUrl); return view; } class ViewHolder { TextView titleView; TextView contentView; ImageView imageView; } }
ListView中经典的利用convertView和ViewHolder避免多次加载的技巧我们当然用到了,我们还用到了一个自定义的类,用这个类中的方法去加载图片。那我们去看看这个类。
public class ImageLoader { private ImageView imageView; private String imageUrl; private LruCache<String, Bitmap> mCache; public ImageLoader() { int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 4; /*用来缓存图片的内存,设置大小为最大可用内存的1/4*/ mCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap value) { /*默认返回的是数量,我们重写让它返回每个bitmap的大小*/ return value.getByteCount(); } }; } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); /*当imageView与设置的Tag配对时才加载图片*/ if (imageView.getTag().equals(imageUrl)) { imageView.setImageBitmap((Bitmap) msg.obj); } } }; public void setImageByThread(ImageView imageView, final String newsImageUrl) { this.imageView = imageView; imageUrl = newsImageUrl; new Thread() { @Override public void run() { Bitmap bitmap = getBitmapFromURL(newsImageUrl); Message message = Message.obtain(); message.obj = bitmap; handler.sendMessage(message); } }.start(); } public Bitmap getBitmapFromURL(String newsImageUrl) { Bitmap bitmap = getBitmapFromCache(newsImageUrl); /*如果内存中已有缓存的此图,直接返回此图*/ if (bitmap != null) { return bitmap; } InputStream inputStream = null; try { URL url = new URL(newsImageUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); inputStream = new BufferedInputStream(connection.getInputStream()); bitmap = BitmapFactory.decodeStream(inputStream); connection.disconnect(); if (bitmap != null) { addBitmapToCache(newsImageUrl, bitmap); return bitmap; } } catch (IOException e) { e.printStackTrace(); } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } public void addBitmapToCache(String imageUrl, Bitmap bitmap) { if (getBitmapFromCache(imageUrl) == null) { mCache.put(imageUrl, bitmap); } } public Bitmap getBitmapFromCache(String imageUrl) { return mCache.get(imageUrl); } }
值得注意的是,我们之前在Adapter中已经对每个imageView设置了特定的Tag,在这里就用到了这个判断,保证不会因为imageView的复用出现图片多次加载的情况。至此整个demo就基本完成了。
相关文章推荐
- 完美实现Android ListView中的TextView的跑马灯效果
- android上改变listView的选中颜色
- XML 与 JSON 优劣对比
- VBA将excel数据表生成JSON文件
- ruby实现的一个异步文件下载HttpServer实例
- C#异步绑定数据实现方法
- newtonsoft.json解析天气数据出错解决方法
- Delphi7中Listview的常用功能汇总
- Delphi控件ListView的属性及使用方法详解
- 科学知识:同步、异步、阻塞和非阻塞区别
- 探讨Ajax中同步与异步之间的区别
- vbs 解析json jsonp的方法
- C#中异步回调函数用法实例
- Extjs4如何处理后台json数据中日期和时间
- C#实现将类的内容写成JSON格式字符串的方法
- JQuery ajax返回JSON时的处理方式 (三种方式)
- jquery JSON的解析方式示例介绍
- c#版json数据解析示例分享
- ASP JSON类文件的使用方法
- android中ListView数据刷新时的同步方法