实验项目:输入图片URL地址,查看网络图片
实验步骤:
1.UI设计,创建一个页面包括输入路径的文本框,点击查看的按钮和一个显示图片的ImageView;
activity代码:
<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"
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" >
<ImageView
android:id="@+id/ivImage"
android:layout_width="230dp"
android:layout_height="226dp"
android:layout_gravity="center"
android:src="@drawable/ic_launcher" />
<EditText
android:id="@+id/etImageUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:text="http://pic46.nipic.com/20140813/10153265_103918805357_2.jpg" />
<Button
android:id="@+id/btnView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="showImage"
android:text="浏览" />
</LinearLayout>
显示效果:
2.访问网络,从网络中获取图片;
(需要在AndroidManifest.xml中添加一个网络连接的权限 );
代码:
/**
* 根据路径获取图片内容的方法
* @param view
*/
public void showImage(View view) {
final String path = etImageUrl.getText().toString();// 获取url
if (TextUtils.isEmpty(path)) {// 当用户输入的url为空的时候
Toast.makeText(MainActivity.this, "url为空", Toast.LENGTH_SHORT)
.show();
} else {// 当用户输入的url不为空的时候
public void run() {
// 连接服务器获取图片信息
try {
// 传入url
URL url = new URL(path);
// 发出http请求
HttpURLConnection huc = (HttpURLConnection) url
.openConnection();
// 发送请求类型
huc.setRequestMethod("GET");
// 设置连接超时时间(五秒)
huc.setConnectTimeout(5000);
// 接收返回信息类型
int responsecode = huc.getResponseCode();
if (responsecode == 200) {// 当返回正确到达
InputStream is = huc.getInputStream();// 获取文件输入流
Bitmap bm = BitmapFactory.decodeStream(is);// 使用位图工厂将流变换为图片
InputStream is=httpURLConnection.getInputStream();
Bitmap bitmap=BitmapFactor.decodeStream(is);
ivImage.setImageBitmap(bitmap) } else {
Toast.makeText(MainActivity.this, "显示图片失败",
Toast.LENGTH_SHORT).show();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3.打开模拟器进行试验;
#3.1:在Android2.2模拟器上可以运行
#3.2:在Android4.2模拟器上运行失败
4.分析失败原因;
4.1:ANR(Application Not Responding):应用程序无响应,如果应用程序不能响应用户输入
的话,系统会显示ANR。主线程也是UI线程本身就干了很多事情,绘制界面响应事件等。如果里面再直接放入一些耗时的操作,如连接网络进行IO操作,就会阻塞主线程,带来较差的用户体验。
5.修改代码,为代码添加一个新的线程;
修改后代码:
/**
* 根据路径获取图片内容的方法
* @param view
*/
public void showImage(View view) {
final String path = etImageUrl.getText().toString();// 获取url
if (TextUtils.isEmpty(path)) {// 当用户输入的url为空的时候
Toast.makeText(MainActivity.this, "url为空", Toast.LENGTH_SHORT)
.show();
} else {// 当用户输入的url不为空的时候
new Thread() {
public void run() {
// 连接服务器获取图片信息
try {
// 传入url
URL url = new URL(path);
// 发出http请求
HttpURLConnection huc = (HttpURLConnection) url
.openConnection();
// 发送请求类型
huc.setRequestMethod("GET");
// 设置连接超时时间(五秒)
huc.setConnectTimeout(5000);
// 接收返回信息类型
int responsecode = huc.getResponseCode();
if (responsecode == 200) {// 当返回正确到达
InputStream is = huc.getInputStream();// 获取文件输入流
Bitmap bm = BitmapFactory.decodeStream(is);// 使用位图工厂将流变换为图片
InputStream is=httpURLConnection.getInputStream();
Bitmap bitmap=BitmapFactor.decodeStream(is);
ivImage.setImageBitmap(bitmap)
} else {
Toast.makeText(MainActivity.this, "显示图片失败",
Toast.LENGTH_SHORT).show();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
6.再一次对程序进行试验,会发现还会有错误;
6.1:错误分析,在android里面不是所以线程都是安全的,所以android有阻止子线程更新组件的机制。如果强制运行,就会报android.view.ViewRootImpl$CalledFromWrongThreadException
6.2:解决方法,android给我们提供了一种消息处理机制,即handler,用来处理不同线程之间的消息。每个线程都有属于自己的一个handler,可以直接通过new方法得到,而在子线程中,我们可以把接收到的信息封装在一个Message对象里面,并调用主线程中的handler对象的sendMessage(Message msg)方法,将该Message对象传递过去,然后主线程的handler收到Message后就会自动调用handleMessage(Message msg)方法,我们就可以通过重写该方法(在主线程中完成)来实现我们想要的操作了。
7.程序最后获取图片的代码;
代码MainActivity中所有代码:
package cn.edu.bzu.web_image;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
protected static final int SHOW_IMAGE = 0;
private ImageView ivImage;
private EditText etImageUrl;
private Handler handler=new Handler(){
public void handleMessage(android.os.Message msg){
//对接收到的新消息进行处理
switch(msg.what){
case SHOW_IMAGE:
Bitmap bitmap=(Bitmap) msg.obj;
ivImage.setImageBitmap(bitmap);
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findView();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* 实例化控件
*/
public void findView(){
ivImage=(ImageView) findViewById(R.id.ivImage);
etImageUrl=(EditText) findViewById(R.id.etImageUrl);
}
/**
* 根据路径获取图片内容的方法
* @param view
*/
public void showImage(View view) {
final String path = etImageUrl.getText().toString();// 获取url
if (TextUtils.isEmpty(path)) {// 当用户输入的url为空的时候
Toast.makeText(MainActivity.this, "url为空", Toast.LENGTH_SHORT)
.show();
} else {// 当用户输入的url不为空的时候
new Thread() {
public void run() {
// 连接服务器获取图片信息
try {
// 传入url
URL url = new URL(path);
// 发出http请求
HttpURLConnection huc = (HttpURLConnection) url
.openConnection();
// 发送请求类型
huc.setRequestMethod("GET");
// 设置连接超时时间(五秒)
huc.setConnectTimeout(5000);
// 接收返回信息类型
int responsecode = huc.getResponseCode();
if (responsecode == 200) {// 当返回正确到达
InputStream is = huc.getInputStream();// 获取文件输入流
Bitmap bm = BitmapFactory.decodeStream(is);// 使用位图工厂将流变换为图片
// 告诉主线程帮我更新页面,内容是bm
Message msg = new Message();
msg.what = SHOW_IMAGE;
msg.obj = bm;
handler.sendMessage(msg);
//iv_imeages.setImageBitmap(bm);//不能再子线程中更新view视图(因为视图不是线程安全的)
} else {
Toast.makeText(MainActivity.this, "显示图片失败",
Toast.LENGTH_SHORT).show();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
}
}