本文主要是介绍Android_04_网络图片查看器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1>不带缓存的图片查看器
MainActivity.java
package com.ithiema.imageviewer;import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;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.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;public class MainActivity extends Activity {Handler handler = new Handler(){//此方法在主线程中调用,可以用来刷新uipublic void handleMessage(android.os.Message msg) {//处理刷新UI的操作需要在主线程中,通过子线程handler.sendMessage(msg);//即可触发主线程去调用主线程的handleMessage()方法;//所以关于子线程中刷新UI的操作都到handleMessage()方法中来做;//处理消息时,需要知道到底是成功的消息,还是失败的消息switch (msg.what) {case 1://把位图对象显示至imageviewImageView iv = (ImageView) findViewById(R.id.iv);iv.setImageBitmap((Bitmap)msg.obj);break;case 0:Toast.makeText(MainActivity.this, "请求失败", 0).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){Thread t = new Thread(){@Overridepublic void run() {//下载图片//1.确定网址String path = "http://192.168.1.103:8080/1.jpg";try {//2.把网址封装成一个url对象URL url = new URL(path);//3.获取客户端和服务器的连接对象,此时还没有建立连接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//4.对连接对象进行初始化//设置请求方法,注意大写conn.setRequestMethod("GET");//设置连接超时conn.setConnectTimeout(5000);//设置读取超时conn.setReadTimeout(5000);//5.发送请求,与服务器建立连接conn.connect();//如果响应码为200,说明请求成功if(conn.getResponseCode() == 200){//获取服务器响应头中的流,流里的数据就是客户端请求的数据InputStream is = conn.getInputStream();//读取出流里的数据,并构造成位图对象Bitmap bm = BitmapFactory.decodeStream(is);//除了new Message()一个Message之外,也可以通过Message.obtain()//获得Message对象,还可以通过handler.obtainMessage(),可自行查看源码;Message msg = new Message();//消息对象可以携带数据msg.obj = bm;//msg.what是为了区分多个message,以便在主线程的handleMessage()方法中去区分//哪个消息是哪个发送的msg.what = 1;//把消息发送至主线程的消息队列handler.sendMessage(msg);}else{//Toast.makeText(MainActivity.this, "请求失败", 0).show();Message msg = handler.obtainMessage();//msg.what是为了区分多个message,以便在主线程的handleMessage()方法中去区分//哪个消息是哪个发送的msg.what = 0;//把消息发送至主线程的消息队列,让主线程去处理;handler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();}}};t.start();}}
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" ><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下载图片"android:onClick="click"/><ImageViewandroid:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content"/></RelativeLayout>
注:对于网络下载这块,需要在清单文件中添加一条权限:
<uses-permission android:name="android.permission.INTERNET"/>
注:
I. 主线程不能被阻塞
* 在Android中,主线程被阻塞会导致应用不能刷新ui界面,不能响应用户操作,用户体验将非常差
* 主线程阻塞时间过长,系统会抛出ANR异常
* ANR:Application Not Response;应用无响应
* 任何耗时操作都不可以写在主线程
* 因为网络交互属于耗时操作,如果网速很慢,代码会阻塞,所以网络交互的代码不能运行在主线程
II. 只有主线程能刷新ui
* 刷新ui的代码只能运行在主线程,运行在子线程是没有任何效果的
* 如果需要在子线程中刷新ui,使用消息队列机制
III. 消息队列
* Looper一旦发现Message Queue中有消息,就会把消息取出,然后把消息扔给Handler对象,Handler会调用自己的handleMessage方法来处理这条消息
* handleMessage方法运行在主线程
* 主线程创建时,消息队列和轮询器对象就会被创建,但是消息处理器对象,需要使用时,自行创建
//消息队列
Handler handler = new Handler(){
//主线程中有一个消息轮询器looper,不断检测消息队列中是否有新消息,如果发现有新消息,自动调用此方法,注意此方法是在主线程中运行的
public void handleMessage(android.os.Message msg) {
}
};
* 在子线程中往消息队列里发消息
//创建消息对象
Message msg = new Message();
//消息的obj属性可以赋值任何对象,通过这个属性可以携带数据,若有多个数据,可以定义一个数组或集合类对象;
msg.obj = bm;
//what属性相当于一个标签,用于区分出不同的消息,从而运行不能的代码
msg.what = 1;
//发送消息
handler.sendMessage(msg);
2>进一步优化
也就是把Handler对象变成一个static对象,那么所有对象都只共用这一个静态变量,
那么这个应用的其他的类也可以直接调用,方便快捷;activity_main.xml文件无需修改;
MainActivity.java
package com.ithiema.imageviewer;import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;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.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;public class MainActivity extends Activity {static ImageView iv;static MainActivity ma;static Handler handler = new Handler(){//此方法在主线程中调用,可以用来刷新uipublic void handleMessage(android.os.Message msg) {//处理消息时,需要知道到底是成功的消息,还是失败的消息switch (msg.what) {case 1://把位图对象显示至imageviewiv.setImageBitmap((Bitmap)msg.obj);break;case 0:Toast.makeText(ma, "请求失败", 0).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);ma = this;}public void click(View v){Thread t = new Thread(){@Overridepublic void run() {//下载图片//1.确定网址String path = "http://192.168.13.13:8080/dd.jpg";try {//2.把网址封装成一个url对象URL url = new URL(path);//3.获取客户端和服务器的连接对象,此时还没有建立连接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//4.对连接对象进行初始化//设置请求方法,注意大写conn.setRequestMethod("GET");//设置连接超时conn.setConnectTimeout(5000);//设置读取超时conn.setReadTimeout(5000);//5.发送请求,与服务器建立连接conn.connect();//如果响应码为200,说明请求成功if(conn.getResponseCode() == 200){//获取服务器响应头中的流,流里的数据就是客户端请求的数据InputStream is = conn.getInputStream();//读取出流里的数据,并构造成位图对象Bitmap bm = BitmapFactory.decodeStream(is);// ImageView iv = (ImageView) findViewById(R.id.iv);
// //把位图对象显示至imageview
// iv.setImageBitmap(bm);Message msg = new Message();//消息对象可以携带数据msg.obj = bm;msg.what = 1;//把消息发送至主线程的消息队列handler.sendMessage(msg);}else{
// Toast.makeText(MainActivity.this, "请求失败", 0).show();Message msg = handler.obtainMessage();msg.what = 0;handler.sendMessage(msg);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}};t.start();}}
3>待缓存的图片查看器
MainActivity.java
package com.ithiema.imageviewer;import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;import com.ithiema.cacheimageviewer.R;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.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;public class MainActivity extends Activity {ImageView iv = (ImageView) findViewById(R.id.iv);Handler handler = new Handler(){//此方法在主线程中调用,可以用来刷新uipublic void handleMessage(android.os.Message msg) {//处理消息时,需要知道到底是成功的消息,还是失败的消息switch (msg.what) {case 1://把位图对象显示至imageviewiv.setImageBitmap((Bitmap)msg.obj);break;case 0:Toast.makeText(MainActivity.this, "请求失败", 0).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){//下载图片//1.确定网址final String path = "http://192.168.1.103:8080/1.jpg";final File file = new File(getCacheDir(), getFileName(path));//判断,缓存中是否存在该文件if(file.exists()){//如果缓存存在,从缓存读取图片System.out.println("从缓存读取的");Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());iv.setImageBitmap(bm);}else{//如果缓存不存在,从网络下载System.out.println("从网上下载的");Thread t = new Thread(){@Overridepublic void run() {try {//2.把网址封装成一个url对象URL url = new URL(path);//3.获取客户端和服务器的连接对象,此时还没有建立连接HttpURLConnection conn = (HttpURLConnection) url.openConnection();//4.对连接对象进行初始化//设置请求方法,注意大写conn.setRequestMethod("GET");//设置连接超时conn.setConnectTimeout(5000);//设置读取超时conn.setReadTimeout(5000);//5.发送请求,与服务器建立连接conn.connect();//如果响应码为200,说明请求成功if(conn.getResponseCode() == 200){//获取服务器响应头中的流,流里的数据就是客户端请求的数据InputStream is = conn.getInputStream();//读取服务器返回的流里的数据,把数据写到本地文件,缓存起来FileOutputStream fos = new FileOutputStream(file);byte[] b = new byte[1024];int len = 0;while((len = is.read(b)) != -1){fos.write(b, 0, len);}fos.close();//读取出流里的数据,并构造成位图对象//流里已经没有数据了,所以BitmapFactory.decodeStream(is)此时就失效了,//因为被is.read已经读取了;所以用BitmapFactory.decodeFile()方法生成Bitmap对象;
// Bitmap bm = BitmapFactory.decodeStream(is);Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());Message msg = new Message();//消息对象可以携带数据msg.obj = bm;msg.what = 1;//把消息发送至主线程的消息队列handler.sendMessage(msg);}else{ Message msg = handler.obtainMessage();msg.what = 0;handler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();}}};t.start();}}//这是自行定义的一个方法,用于获取path变量所存放的文件名,这种封装的思想要学会!public String getFileName(String path){int index = path.lastIndexOf("/");return path.substring(index + 1);}}
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" ><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下载图片"android:onClick="click"/><ImageViewandroid:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content"/></RelativeLayout>
注:关于网络图片查看器,上述部分只是其核心部分,很多细节都没有考虑到位,你也可参考网上的做法;
如你在做每个项目时,都可以去http://github.com或http://code.geogle.com去查看别人所写的类似的开源项目,
多学会学习学习别人思想的精髓
这篇关于Android_04_网络图片查看器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!