注意: 访问网络必须在工程的AndroidManifest.xml中声明对应的权限:<uses-permission android:name="android.permission.INTERNET"/>
访问网络的步骤:
1. 创建URL对象
URL url = new URL(path);//path为网络请求的路径
(URL的作用:统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。)
2. 通过URL打开网络连接对象
HttpURLConnectionconn = (HttpURLConnection)url.openConnection();
3. 设置网络请求的参数
conn.setRequestMethod("GET");//设置请求参数为get, 默认的请求方式就是get
conn.setConnectTimeout(5000);//设置请求服务器的超时时间.
4. 得到服务器的返回信息
String type =conn.getContentType();//服务器返回的数据类型
int length =conn.getContentLength();//服务器返回的数据类型
int code =conn.getResponseCode(); // 200 OK 404 资源没找到 503服务器内部错误
5. 得到服务器返回的数据
InputStream is = conn.getInputStream()
如果是一张图片资源的话,android提供了一个方便的API:BitmapFactory可以方便将流转为Bitmap位图图片:
Bitmap bitmap =BitmapFactory.decodeStream(IO输入流);
Useragent:
作用:让服务器判断客户端是来自电脑还是手机设备!方式: conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0;Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR3.5.30729; .NET CLR 3.0.30729; .NET4.0C; InfoPath.2");
通过该设置可以服务器端认为该请求是来自电脑windows系统
Application NotResponse,应用程序无响应,简称ANR 异常。在主线程中做一些耗时的操作,比如网络访问、文件拷贝等阻塞了主线程,导致主线程无法响应,这时就会报ANR 异常。因此对于耗时操作,必须在子线程中完成。
Google 工程师考虑到网络访问是一个比较耗时的操作,从Android 4.0 开始,Google 更加在意UI 界面运行的流畅性,强制要求访问网络的操作不允许在主线程中执行,只能在子线程中进行,在主线程请求网络时,会报如下错误:android.os.NetworkOnMainThreadException
因此,访问网络的操作必须在子线程中进行。
主线程也叫UI 线程,Activity 中的onCreate 方法和点击事件的方法都是运行在主线程中的。主线程创建的界面,因此只有主线程才能修改界面,别的线程不允许修改,否则会报如下错误:
CalledFromWrongThreadException:Only the original thread that created a view hierarchy
can touch itsviews.
注意:既然子线程不能修改主线程的UI,那么我们的子线程如果需要修改UI 该怎么办呢?这个时候就应该使用Handler 实现子线程与主线程之间的通信了。
Android 的Handler 机制(也有人叫消息机制)目的是为了跨线程通信,也就是多线程通信。之所以需要跨线程通信是因为在Android 中主线程通常只负责UI 的创建和修改,子线程负责网络访问和耗时操作,因此,主线程和子线程需要经常配合使用才能完成整个Android 功能。
Handler 机制可以用下图来展示。MainThread代表主线程,newThread 代表子线程。
MainThread 是Android 系统创建并维护的,创建的时候系统执行了Looper.prepare();方法,该方法内部创建了MessageQueue 消息队列(也叫消息池),该消息队列是Message 消息的容器,用于存储通过handler发送过来的Message。MessageQueue 是Looper 对象的成员变量,Looper 对象通过ThreadLocal 绑定在MainThread 中。因此我们可以简单的这么认为:MainThread 拥有唯一的一个Looper 对象,该Looper 对象有唯一的MessageQueue 对象,MessageQueue 对象可以存储多个Message。
MainThread 中需要程序员手动创建Handler对象,并覆写Handler 中的handleMessage(Message msg)方法,该方法将来会在主线程中被调用,在该方法里一般会写与UI 修改相关的代码。MainThread 创建好之后,系统自动执行了Looper.loop();方法,该方法内部开启了一个“死循环”不断的去之前创建好的MessageQueue 中取Message。如果一有消息进入MessageQueue,那么马上会被Looper.loop();取出来,取出来之后就会调用之前创建好的handler 对象的handleMessage(Message)方法。
newThread 线程是我们程序员自定new出来的子线程。在该子线程中处理完我们的“耗时”或者网络访问任务后,调用主线程中的handler 对象的sendMessage(msg)方法,该方法一被执行,内部将msg添加到了主线程中的MessageQueue 队列中,这样就成为了Looper.loop()的盘中餐了,等待着被消费。
我们使用时只需要在主线程中创建Handler,并覆写handler 中的handleMessage 方法,然后在子线程中调用handler 的sendMessage(msg)方法即可。
在Hanlder 机制中都需要用到Message 对象,该对象的创建或者获取有多种方式。
1. Message msg = new Message(); 直接创建一个新的Message对象。
2. Message msg =handler.obtainMessage(); 通过handler 对象获取一个Message 对象,该对象从消息缓存池中获取的,可以提高Message 的使用率,减少垃圾回收次数。
3. Message msg =Message.obtain();该方法最常用.
除了正常的利用handler发送一个messgae对象去更新UI外,Android下还有以下三种方式可以在子线程中直接更新UI:
1. Handler的post(Runnable runnable)方法
2. View的post(Runnable runnable)方法
3. Activity的runOnUiThread(Runnablerunnable)方法
以上三种方法都是需要传递一个Runnable对象,该对象会被主线程执行。该方法表面上看跟Message 没任何关系,但是其内部帮我们封装了Message。
通过该案例可以将网络请求和handler消息机制结合一起练习使用。
需求分析:
通过在输入框输入正确的网络连接,点击查看按钮获取网络图片,显示在下方的ImageView控件上。
开发步骤:
1. 界面布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/et_path"
android:text="http://www.itheima.com/images_new/logo.jpg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入网络图片的路径" />
<Button
android:onClick="viewImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查看" />
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
2. 初始化控件
@Override
protectedvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_path = (EditText) findViewById(R.id.et_path);
iv = (ImageView) findViewById(R.id.iv);
}
3. 实现点击按钮事件,开启子线程请求网络图片
/**
* 点击查看图片
*
* @param view
*/
publicvoid viewImage(View view) {
final String path = et_path.getText().toString().trim();
if (TextUtils.isEmpty(path)) {
Toast.makeText(this, "对不起,图片路径不能为空", 0).show();
return;
}
new Thread(){
publicvoid run() {
//开启新的子线程去请求网络获取数据
// 显示这个互联网上的图片
try {
// 1.得到图片的url路径
URL url = new URL(path);
// 2.通过路径打开一个http的连接
HttpURLConnectionconn = (HttpURLConnection) url.openConnection();// http
conn.setRequestMethod("GET");//设置请求参数为get, 默认的请求方式就是get
conn.setConnectTimeout(5000);//设置请求服务器的超时时间.
// 3.得到服务器的返回信息
String type =conn.getContentType();
int length = conn.getContentLength();
System.out.println("服务器资源的长度:"+length);
System.out.println("服务器返回的数据类型:" + type);
int code = conn.getResponseCode(); // 200 OK 404 资源没找到 503服务器内部错误
if (code == 200) {
//请求成功
InputStream is =conn.getInputStream();
Bitmap bitmap =BitmapFactory.decodeStream(is);
//iv.setImageBitmap(bitmap);
//不能直接更新ui,通过发消息让handler去更新ui
Message msg =Message.obtain();//节约了内存
msg.what = SUCCESS;//what标识一个消息的类型
msg.obj = bitmap;
handler.sendMessage(msg);
is.close();
}
} catch (Exception e) {
e.printStackTrace();
Message msg =Message.obtain();
msg.what = ERROR;
handler.sendMessage(msg);
}
};
}.start();
}
4. 子线程发送消息更新UI,在handler中处理消息
private Handler handler = new Handler(){
publicvoid handleMessage(android.os.Messagemsg) {
switch (msg.what) {
caseSUCCESS:
Bitmap bitmap =(Bitmap) msg.obj;
iv.setImageBitmap(bitmap);
break;
caseERROR:
Toast.makeText(MainActivity.this, "获取图片失败", 0).show();
break;
}
};
};
5. 因为案例涉及到网络请求,所以一定要记得添加网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
常见的黑色菱形里面带问号乱码造成的原因:gbk的数据 以utf-8方式显示.
无论是哪种乱码解决的方案:
只要保证服务器端和客户端的编码同一就可以解决乱码问题.
客户端可以根据服务器端返回的数据中包含哪种编码来对应解码:
publicclass StreamTools {
/**
* 工具方法
* @param is 输入流
* @return文本字符串
* @throws Exception
*/
publicstatic String readStream(InputStream is) throws Exception{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = newbyte[1024];
int len = -1;
while((len = is.read(buffer))!=-1){
baos.write(buffer, 0,len);
}
is.close();
String temp = baos.toString();
if(temp.contains("charset=utf-8")){
return temp;
}elseif(temp.contains("gb2312")){
return baos.toString("gb2312");
}returnnull;
}
}
一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案(有点类似于正则表达式,获得了当今大部分语言的支持),从而可以在不同平台间进行数据交换。JSON采用兼容性很高的文本格式,同时也具备类似于C语言体系的行为。
l JSON和XML的数据可读性基本相同
l JSON和XML同样拥有丰富的解析手段
l JSON相对于XML来讲,数据的体积小
l JSON与JavaScript的交互更加方便
l JSON对数据的描述性比XML较差
l JSON的速度要远远快于XML
可以看作是一个json对象,这是系统中有关JSON定义的基本单元,其包含一对儿(Key/Value)数值。Json字符串中凡是一对{}的数据都可以封装成一个JSONObject对象来进行解析,JSONObject可以方便的根据key值来取出vaule值。
可以获取以下类型的数据:
可以看做是一个json数组对象,里面装的是一个一个的JSONOject对象,通过角标JSONArray. getJSONObject (index)取出对应的JSONOject对象。Json字符串中凡是一对[]的数据都可以封装成JSONArray数组。
天气预报的案例获取返回的JSON数据如下:
{
"desc": "OK",
"status": 1000,
"data": {
"wendu": "28",
"ganmao": "相对今天出现了较大幅度降温,较易发生感冒,体质较弱的朋友请注意适当防护。",
"forecast": [
{
"fengxiang": "无持续风向",
"fengli": "微风级",
"high": "高温 29℃",
"type": "雷阵雨",
"low": "低温 25℃",
"date": "30日星期六"
},
{
"fengxiang": "无持续风向",
"fengli": "微风级",
"high": "高温 32℃",
"type": "阴",
"low": "低温 24℃",
"date": "31日星期天"
},
{
"fengxiang": "无持续风向",
"fengli": "微风级",
"high": "高温 31℃",
"type": "阴",
"low": "低温 26℃",
"date": "1日星期一"
},
{
"fengxiang": "无持续风向",
"fengli": "微风级",
"high": "高温 32℃",
"type": "晴",
"low": "低温 25℃",
"date": "2日星期二"
},
{
"fengxiang": "无持续风向",
"fengli": "微风级",
"high": "高温 33℃",
"type": "晴",
"low": "低温 25℃",
"date": "3日星期三"
}
],
"yesterday": {
"fl": "微风",
"fx": "无持续风向",
"high": "高温 32℃",
"type": "多云",
"low": "低温 25℃",
"date": "29日星期五"
},
"aqi": "264",
"city": "北京"
}
}
整个json字符串可以用一个JSONObject对象封装,data字段对应的也是一个JSON对象所以代码可以这样操作:
//开始解析json数据
JSONObject jsonObj = new JSONObject(json);
String result =jsonObj.getString("desc");
System.out.println(result);
if("OK".equals(result)){
//请求成功
//data对应的value值就是一个JSON对象 JSONObject
JSONObject dataJSON =jsonObj.getJSONObject("data");
JSONArray array = dataJSON.getJSONArray("forecast");
//array数组里面都是jsonObject对象可以遍历取出在进行获取对应的数据
...这里就不进行深层次的解析了
该案例属于一个综合案例,不仅用到了网络访问、图片加载、xml 的解析、handler 机制、线程池的使用还用到了ListView 及其优化策略。
效果图如下:
由于该案例需要用到网络数据,因此需要先搭建服务器。服务器的搭建也很简单,直接将如下图片和news.xml 放到文件夹中(我起名叫news),然后将该文件夹放到tomcat 的webapps 目录下,最后启动tomcat即可。
News.xml文件的内容如下:
<?xml version="1.0"encoding="UTF-8" ?>
<channel>
<item>
<title>军报评徐才厚</title>
<description>人死账不消 反腐步不停,支持,威武,顶,有希望了。
</description>
<image>http://192.168.1.103:8080/img/a.jpg</image>
<type>1</type>
<comment>163</comment>
</item>
<item>
<title>女司机翻车后直奔麻将室</title>
<description>女司机翻车后直奔麻将室,称大难不死手气必红
</description>
<image>http://192.168.1.103:8080/img/b.jpg</image>
<type>2</type>
</item>
<item>
<title>小伙当“男公关”以为陪美女</title>
<description>来源:中国青年网,小伙当“男公关”以为陪美女,上工后被大妈吓怕 </description>
<image>http://192.168.1.103:8080/img/c.jpg</image>
<type>3</type>
</item>
<item>
<title>男子看上女孩背影欲强奸</title>
<description> 来源:新京报,看到正脸后放弃仍被捕
</description>
<image>http://192.168.1.103:8080/img/d.jpg</image>
<type>1</type>
<comment>763</comment>
</item>
</channel>
注意:
上面xml 代码中<image>标签中的url 是对应图片的地址。加载图片的实质就是先从xml 中获取到图片url 地址,然后从网络中再获取其对应的图片。
如上效果图所示: 主界面是一个ListView,ListView 的每一个条目都是一个复杂条目,ListView 中的所有数据全部来自网络。
步骤如下:
主界面布局和listview条目item的布局,并且在界面activity中初始化控件
1. 访问网络获取news.xml
2. 解析news.xml,并将里面的每一个item 封装成一个JavaBean
3. 解析好数据后通过Handler 发送消息给主线程,让主线程给ListView 设置Adapter因为网络访问必须在子线程中,而给ListView 设置Adapter 属于修改UI 操作,因此当解析好网络数据后需要通过Handler 发送消息。
1. 自定义一个MyAdapter 继承BaseAdapter
2. 覆写getCount()和getView()方法
3. getCount()方法返回新闻的条目个数
4. getView()中显然要将一个单独的布局填充为View 对象
5. 通过View.findViewById()将list_item.xml 中的各个控件初始化,然后设置相应的值。其中ImageView 需要处理。
6. 因为getView()方法也是在主线程中被调用的,而此时需要在该方法中从网络上加载图片,因此需要在该方法中再开启一个子线程负责下载图片,然后通过Handler 发送消息将图片显示在界面。
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/ll_loading"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在拼命加载中..."
/>
</LinearLayout>
</RelativeLayout>
Item.xml:
这里面会用到自定义的SmartImageView来替代ImageView,可以先将SmartImageView类创建出来先不实现。
<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 设置为自定义的imageview -->
<com.loopj.android.image.SmartImageView
android:id="@+id/iv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"/>
<TextView
android:layout_marginLeft="2dip"
android:singleLine="true"
android:layout_marginTop="5dip"
android:id="@+id/tv_item_title"
android:layout_toRightOf="@id/iv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新闻的标题"
android:textColor="#BB000000"
android:textSize="18sp"/>
<TextView
android:layout_marginLeft="2dip"
android:lines="2"
android:layout_marginTop="2dip"
android:id="@+id/tv_item_desc"
android:layout_below="@id/tv_item_title"
android:layout_toRightOf="@id/iv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新闻的描述信息.描述信息比较长....."
android:textColor="#88000000"
android:textSize="14sp"/>
<TextView
android:id="@+id/tv_item_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_item_desc"
android:textSize="8sp"
android:layout_alignParentRight="true"
android:text="评论:33个"
/>
</RelativeLayout>
由于该步骤涉及到大量的XML解析和对象的封装,可以将该代码抽取成一个单独的业务逻辑类NewsInfoService来进行实现,每一条新闻用一个javabean对象来表示:
/**
* 业务bean 用来表示每一条新闻信息
*/
publicclass NewsItem {
private String title;
private String description;
private String image;
private String type;
privateintcomment;
@Override
public String toString() {
return"NewsItem [title=" + title + ", description=" + description
+ ", image=" + image + ", type=" + type + ", comment="
+ comment + "]";
}
public String getTitle() {
returntitle;
}
publicvoid setTitle(String title) {
this.title = title;
}
public String getDescription() {
returndescription;
}
publicvoid setDescription(String description){
this.description = description;
}
public String getImage() {
returnimage;
}
publicvoid setImage(String image) {
this.image = image;
}
public String getType() {
returntype;
}
publicvoid setType(String type) {
this.type = type;
}
publicint getComment() {
returncomment;
}
publicvoid setComment(int comment) {
this.comment = comment;
}
}
业务逻辑类:
/**
* 新闻信息的业务代码
*/
publicclass NewsInfoService {
/**
* 获取服务器最新的所有的新闻信息
*
* @param path
* 服务器的路径
* @return null请求失败
*/
publicstatic List<NewsItem>getAllNews(String path) throws Exception {
List<NewsItem> newsItems= new ArrayList<NewsItem>();//所有新闻的集合
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
Thread.sleep(3000);
int code = conn.getResponseCode();
if (code == 200) {
InputStream is =conn.getInputStream();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(is, "utf-8");
int eventType = parser.getEventType();
NewsItem newsItem = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
if("item".equals(parser.getName())){
newsItem = new NewsItem();//新闻数据要开始了创建出来对象
}elseif("title".equals(parser.getName())){
newsItem.setTitle(parser.nextText());
}elseif("description".equals(parser.getName())){
newsItem.setDescription(parser.nextText());
}elseif("image".equals(parser.getName())){
newsItem.setImage(parser.nextText());
}elseif("type".equals(parser.getName())){
newsItem.setType(parser.nextText());
}elseif("comment".equals(parser.getName())){
newsItem.setComment(Integer.parseInt(parser.nextText()));
}
break;
case XmlPullParser.END_TAG:
if("item".equals(parser.getName())){
newsItems.add(newsItem);
}
break;
}
eventType =parser.next();
}
return newsItems;
} else {
returnnull;
}
}
}
在MainActivity中请求网络获取到数据进行显示,由于请求网络需要在子线程而且子线程不能更新UI需要进行handler消息机制来进行更新UI
private Handler handler = new Handler(){
publicvoid handleMessage(android.os.Messagemsg) {
ll_loading.setVisibility(View.INVISIBLE);
switch (msg.what) {
caseSUCCESS:
//设置数据适配器
lv.setAdapter(new NewsAdapter());
break;
caseERROR:
Toast.makeText(MainActivity.this, "获取新闻资讯失败,请检查网络", 0).show();
break;
}
};
};
@Override
protectedvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);
ll_loading = (LinearLayout) findViewById(R.id.ll_loading);
// 显示数据加载进度条
ll_loading.setVisibility(View.VISIBLE);
new Thread() {
publicvoid run() {
try {
items = NewsInfoService.getAllNews(getResources()
.getString(R.string.serverpath));
//更新界面的listview设置listivew的数据适配器
Message msg =Message.obtain();
msg.what = SUCCESS;
handler.sendMessage(msg);
} catch (Exception e) {
e.printStackTrace();
Message msg =Message.obtain();
msg.what = ERROR;
handler.sendMessage(msg);
}
};
}.start();
}
数据适配器适配数据:
privateclass NewsAdapter extends BaseAdapter{
@Override
publicint getCount() {
returnitems.size();
}
@Override
public View getView(int position, View convertView,ViewGroup parent) {
View view = View.inflate(MainActivity.this, R.layout.item, null);
TextViewtv_title = (TextView) view.findViewById(R.id.tv_item_title);
TextView tv_desc =(TextView) view.findViewById(R.id.tv_item_desc);
TextView tv_comment =(TextView) view.findViewById(R.id.tv_item_comment);
SmartImageView siv =(SmartImageView) view.findViewById(R.id.iv_item);
NewsItem item = items.get(position);
tv_title.setText(item.getTitle());
tv_desc.setText(item.getDescription());
String type =item.getType();//1 2 3
if("1".equals(type)){
tv_comment.setText("评论:"+item.getComment());
}elseif("2".equals(type)){
tv_comment.setText("视频");
tv_comment.setBackgroundColor(0x66ff0000);
}elseif("3".equals(type)){
tv_comment.setText("LIVE");
tv_comment.setBackgroundColor(0x660000ff);
}
System.out.println(item.getImage());
//自定义的smartImageView中提供的设置图片的方法
siv.setImageUrl(item.getImage());
return view;
}
@Override
public Object getItem(int position) {
returnnull;
}
@Override
publiclong getItemId(int position) {
return 0;
}
}
publicclass SmartImageView extends ImageView {
private Handler handler = new Handler(){
publicvoid handleMessage(android.os.Messagemsg) {
Bitmap bitmap = (Bitmap)msg.obj;
setImageBitmap(bitmap);
};
};
public SmartImageView(Context context,AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SmartImageView(Context context,AttributeSet attrs) {
super(context, attrs);
}
public SmartImageView(Context context) {
super(context);
}
/**
* 设置一个网络的图片路径,直接把网络上的图片给显示出来
* @param url
*/
publicvoid setImageUrl(final String path){
new Thread(){
publicvoid run() {
try {
URL url = new URL(path);
HttpURLConnectionconn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
int code = conn.getResponseCode();
if(code == 200){
InputStream is =conn.getInputStream();
Bitmap bitmap =BitmapFactory.decodeStream(is);
Message msg = Message.obtain();
msg.obj = bitmap;
handler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
}
该SmartImageView是我们自己写的代码,里面就是通过异步请求网络然后将数据加载成一个图片。网络上有现成封装好的SmartImageView,如何使用见下:
SmartImageView 是开源免费的图片加载框架,代码托管在Github 上,用它可以替代Android 自带的ImgageView 控件。使用SmartImageView 可以直接通过url 加载图片,该过程是异步的,且支持图片的缓存,以便下次快速快速加载显示。
下载地址:https://github.com/loopj/android-smart-image-view
使用步骤:
1. 将下载好的SmartImageView的src下的整个源代码直接拷贝到自己本工程下的src目录下。
在list_item.xml布局文件中将ImageView 替换为com.loopj.android.image.SmartImageView ,如下图所示。
2. 在代码中的ImageView 也给替换为SmartImageView
SmartImageView iv = (SmartImageView)view.findViewById(R.id.iv);给SmartImageView 对象直接设置url 即可iv.setImageUrl(imageURL);
