初识安卓之仿微博界面的实现
以下为主界面上负责显示的代码:
1: public class MainActivity extends Activity {
2: private ImageService imageService;
3: private List<Blog> blogs;
4: //activity一创建执行的代码
5: public void onCreate(Bundle savedInstanceState) {
6: super.onCreate(savedInstanceState);
7: setContentView(R.layout.main);
8: try {
9: //先拿到负责处理图像和封装微博对象的两个服务类对象
10: imageService = new ImageService(this);
11: BlogService blogService = new BlogService();
//通过blogService的get方法,从服务器中请求xml资源,并对xml进行解析,封装对象,得到一个微博对象集合
13: blogs = blogService.getBlogs();
14: //获取ListView控件对象
15: ListView blogLV = (ListView) findViewById(R.id.blogLV);
16: //设置ListView控件对象的适配器,用来向列表中添加包含了微博对象的各个item元素
17: blogLV.setAdapter(adapter);
18: } catch (Exception e) {
19: e.printStackTrace();
20: Toast.makeText(this, "服务器忙!", 0).show();
21: }
22: }
23: private BaseAdapter adapter = new BaseAdapter() {
24: //listview中用来获取一个行信息的函数:
25: //getview方法作用,listview中显示一条item就调用一次该方法,创建一个条目视图
26: //需要传三个参数:当前条目位置,当前条目载体(是否重用),当前条目父级
27: public View getView(int position, View convertView, ViewGroup parent) {
28: //把每个item填充到listview中的行里,销毁的拿来重新利用,提高浏览的速度
29: View view = convertView == null ?
30: View.inflate(getApplicationContext(), R.layout.item, null) : convertView;
31: //生成一个完整的item,设置它里面的所有内容:
32: //获取头像控件对象
33: final ImageView portraitIV =(ImageView) view.findViewById(R.id.portraitIV);
34: //获取微博里的图片控件对象
35: final ImageView picIV =(ImageView) view.findViewById(R.id.picIV);
36: //获取名字文本控件对象
37: TextView nameTV = (TextView) view.findViewById(R.id.nameTV);
38: //获取微博内容文本控件对象
39: TextView contentTV = (TextView) view.findViewById(R.id.contentTV);
40: //获取微博来源内容文本控件对象
41: TextView fromTV = (TextView) view.findViewById(R.id.fromTV);
42: //得到当前位置处的那个微博对象,position代表第几个条目,从0开始,正好和集合的下标一致
43: final Blog blog = blogs.get(position);
44: // 把blog中的数据添加到TextView, ImageView中
45: nameTV.setText(blog.getName());
46: contentTV.setText(blog.getContent());
47: fromTV.setText(blog.getFrom());
48: //获取解析到的图片的方法:
49: //原理:解析到的只是图片的地址,所以要得到图片,最好重新开一个线程,去访问服务器上的图片
50: try {
51: //把微博对象中的图片属性值(就是图片的地址),传给imageService的get方法,让它去访问,就可以得到一个图片
52: portraitIV.setImageBitmap(imageService.getImage(blog.getPortrait()));
53: } catch (Exception e) {
54: e.printStackTrace();
55: }
56: //设置微博对象中的微博图片同上
57: try {
58: picIV.setImageBitmap(imageService.getImage(blog.getPic()));
59: } catch (Exception e) {
60: e.printStackTrace();
61: }
62: return view;
63: }
64: public long getItemId(int position) {
65: return position;
66: }
67: //从微博对象集合blogs中,找到当前位置处的那个微博对象,并返回,position代表第几个条目,从0开始,正好和集合的下标一致
68: public Object getItem(int position) {
69: return blogs.get(position);
70: }
71: public int getCount() {
72: return blogs.size();
73: }
74: };
75: }
以下为负责处理请求图片逻辑的服务层代码
1: public class ImageService {
2: private Context context;
3:
4: public ImageService(Context context) {
5: this.context = context;
6: }
7: //bitmap位图类,安卓中用来表示图片的类,自定义一个从服务器获得图片的方法,接受一个图片地址
8: public Bitmap getImage(String address) throws Exception {
9: if (address == null)
10: return null;
11: //创建连接对象
12: URL url = new URL(address);
13: //打开连接
14: HttpURLConnection conn = (HttpURLConnection) url.openConnection();
15: //设置连接超时
16: conn.setConnectTimeout(3000);
17: //创建一个文件路径对象,目录是文件缓存地址,文件名是图片的网络地址
18: File cacheFile = new File(context.getCacheDir(), URLEncoder.encode(address));
19: if (cacheFile.exists()) {
//路径对象下的文件对象存在,说明之前访问过了,获取其最后修改时间, 设置请求头,再向服务器去请求这个图片
21: //以便能让服务器判断这个图片最近有没有修改过
22: conn.setIfModifiedSince(cacheFile.lastModified());
23: }
24: //获取服务器响应
25: int code = conn.getResponseCode();
26:
27: //资源被修改了或者第一次访问该资源都是200
28: if (code == 200) {
29: //利用自定义的工具类,读取服务器响应回的输入流并转为字节数组型数据
30: byte[] data = Util.read(conn.getInputStream());
31: //创建一个位图对象的方法:利用工厂类把字节数据解码为图片
32: Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
33: // 存储图片到本地, 用作缓存. 建议新线程中处理
34: bm.compress(CompressFormat.JPEG, 100, new FileOutputStream(cacheFile));
35: return bm;
36: //304表示资源没有被修改过,只要不是304,资源要么被修改了,要么是第一次访问
37: } else if (code == 304) {
38: Bitmap bm = BitmapFactory.decodeFile(cacheFile.getAbsolutePath()); // 读取cacheFile, 生成Bitmap
39: return bm;
40: }
41: throw new NetworkErrorException("连接出错: " + code);
42: }
43:
44: }
以下代码为负责从服务器请求微博数据的服务层代码:
1: public class BlogService {
2:
3: /**
4: * 请求服务端, 得到包含数据的XML, 解析XML, 得到List<Blog>
5: * @return 包含Blog对象的List集合
6: */
7: public List<Blog> getBlogs() throws Exception {
8: //如果服务器发过来的是blogs.js类型的数据,而不是blogs.xml,解析方式如下“
9:
10: //创建连接对象,如果服务器是以js的形式发回微博内容。则调用parseJSON方法
11: URL url = new URL("http://192.168.1.253:8080/15.Web/blogs.js");
12:
13: //创建连接对象,如果服务器是以xml的形式发回微博内容。则调用parseXML方法
14: //URL url = new URL("http://192.168.1.253:8080/15.Web/blogs.xml");
15:
16: //打开该连接
17: HttpURLConnection conn = (HttpURLConnection) url.openConnection();
18: conn.setConnectTimeout(3000);
19:
20: int code = conn.getResponseCode();
21: if (code == 200) {
22: //访问成功,执行解析方法
23: return parseJSON(conn.getInputStream());
24: }
25: throw new NetworkErrorException("网络异常: " + code);
26: }
27:
28: //服务器以js的形式发回微博内容。调用parseJSON方法
29: private List<Blog> parseJSON(InputStream inputStream) throws Exception {
30: List<Blog> blogs = new ArrayList<Blog>();
31: // 读取服务端写回的js数据,将服务器发来的输入流封装到一个字节数组中
32: byte[] data = Util.read(inputStream);
33: //将返回的字节数组转为字符串,该字符串包含了很多表中单元,一个单元代表一个微博信息
34: String json = new String(data);
35: //将包含所有微博数据的字符串封装成一个JSON数组对象,数组中每个成员是一条微博信息
36: JSONArray arr = new JSONArray(json);
37: //遍历数组,解析每条微博
38: for (int i = 0; i < arr.length(); i++) { // 循环遍历数组
39: // 得到每一个JSON对象
40: JSONObject obj = arr.getJSONObject(i);
41: //准备封装成对象
42: Blog blog = new Blog();
43: //封装对象的过程:
44: blog.setPortrait(obj.getString("portrait")); // 获取JSON对象中的属性, 设置给Blog对象
45: blog.setName(obj.getString("name"));
46: blog.setContent(obj.getString("content"));
47: //将图片的路径作为图片属性放到微博对象中
48: String pic = obj.getString("pic");
49: //如果微博中本来就没有图片,则设置null即可
50: blog.setPic(pic.equals("null") ? null : pic);
51: blog.setFrom(obj.getString("from"));
52: blogs.add(blog);
53: }
54:
55: return blogs;
56: }
57:
58: //服务器以xml的形式发回微博内容。调用parseXML方法
59: private List<Blog> parseXML(InputStream inputStream) throws Exception {
60: List<Blog> blogs = new ArrayList<Blog>();
61: Blog blog = null;
62:
63: XmlPullParser parser = Xml.newPullParser();
64: parser.setInput(inputStream, "UTF-8");
65: for (int type = parser.getEventType(); type != XmlPullParser.END_DOCUMENT; type = parser.next()) {
66: if (type == XmlPullParser.START_TAG) {
67: if ("blog".equals(parser.getName())) {
68: blog = new Blog();
69: blogs.add(blog);
70: } else if ("portrait".equals(parser.getName())) {
71: blog.setPortrait(parser.nextText());
72: } else if ("name".equals(parser.getName())) {
73: blog.setName(parser.nextText());
74: } else if ("content".equals(parser.getName())) {
75: blog.setContent(parser.nextText());
76: } else if ("pic".equals(parser.getName())) {
77: blog.setPic(parser.nextText());
78: } else if ("from".equals(parser.getName())) {
79: blog.setFrom(parser.nextText());
80: }
81: }
82: }
83: return blogs;
84: }
85: }
使用到的自定义工具类:读取服务器返回的输入流,转为字节数组
1: public class Util {
2:
3: /**
4: * 读取输入流中的数据, 返回
5: * @param in 要读取数据的输入流
6: * @return 输入流中的数据
7: */
8: public static byte[] read(InputStream in) throws IOException {
9: ByteArrayOutputStream baos = new ByteArrayOutputStream();
10: byte[] buffer = new byte[1024];
11: int len;
12: while ((len = in.read(buffer)) != -1)
13: //为了提高效率,砍掉数组中空白内容,写入字符数组的某一部分,而不是把字符数组整个写入
14: baos.write(buffer, 0, len);
15: in.close();
16: baos.close();
17: return baos.toByteArray();
18: }
19: }