Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 網絡學習之獲取服務器的圖片

Android 網絡學習之獲取服務器的圖片

編輯:關於Android編程

首先需要搭建一個Tomcat服務器,然後測試服務器上的圖片使用PC上的浏覽器是否可以正常下載下來

\

可以看到服務器上的圖片數據是可以正常訪問的。圖片的地址:http://localhost:8080/meinv.jpg

那如何在我們Android上從網絡下載圖片呢?

直接上獲取網絡圖片的代碼:

 

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    public void click(View v)
    {
    	//1: 確定網址
    	String path = http://localhost:8080/meinv.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位圖
    			Bitmap bm = BitmapFactory.decodeStream(is);
    			
    			//顯示在界面上
    			ImageView imageView = (ImageView) findViewById(R.id.lv);
    			imageView.setImageBitmap(bm);
    		}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
}

運行看效果:

 

\

從控制台的打印可以是警告: 網絡工作在主線程中異常。

上面的警告就是從4.0以後引入的,如果網絡任務在主線程中,就會報警告。所以我們需要開啟一個線程來執行網絡任務。

 

修改後的代碼為:

 

public void click(View v)
    {
    	//開啟一個線程
    	Thread thread = new Thread()
    	{
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    	    	//1: 確定網址
    	    	String path = http://localhost:8080/meinv.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位圖
    	    			Bitmap bm = BitmapFactory.decodeStream(is);
    	    			
    	    			//顯示在界面上
    	    			ImageView imageView = (ImageView) findViewById(R.id.lv);
    	    			imageView.setImageBitmap(bm);
    	    		}
    			} catch (Exception e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	};
    	
    	//啟動線程任務
    	thread.start();
    }

再次運行看效果:

 

\

又報出一個警告: 調用錯誤線程異常,也就是說只有創建它的view,才能調用該view。 直白點就是只有主線程(UI線程)才能更新UI,別的線程是不能隨便更新UI的。

如果需要更新UI,那只能主線程來更新UI,那別的線程如何告訴主線程需要更新UI呢? 這就需要引入另一個知識點:消息

 

如果別的線程需要更新UI,就發生消息給主線程,主線程收到後會自動的更新UI

 

代碼修改為:

 

if(conn.getResponseCode() == 200)
    	    		{
    	    			//獲取服務器響應頭中的流
    	    			InputStream is = conn.getInputStream();
    	    			
    	    			//讀取流裡的數據,構建成bitmap位圖
    	    			Bitmap bm = BitmapFactory.decodeStream(is);
    	    			
    	    			//發生更新UI的消息
    	    			Message msg = handler.obtainMessage();
    	    			msg.obj = bm;
    	    			handler.sendMessage(msg);
    	    			//顯示在界面上
    	    			//ImageView imageView = (ImageView) findViewById(R.id.lv);
    	    			//imageView.setImageBitmap(bm);
    	    		}

加入Handler,也就是處理消息的handle

 

 

	Handler handler = new Handler()
	{
		public void handleMessage(android.os.Message msg) 
		{
			//更新UI
			ImageView imageView = (ImageView) findViewById(R.id.lv);
			imageView.setImageBitmap((Bitmap) msg.obj);
		};
	};

再次運行看效果:

 

\

可以看到圖片正常顯示出來了。

我們再次修改代碼增加獲取失敗的處理邏輯

 

if(conn.getResponseCode() == 200)
    	    		{
    	    			//獲取服務器響應頭中的流
    	    			InputStream is = conn.getInputStream();
    	    			
    	    			//讀取流裡的數據,構建成bitmap位圖
    	    			Bitmap bm = BitmapFactory.decodeStream(is);
    	    			
    	    			//發生更新UI的消息
    	    			Message msg = handler.obtainMessage();
    	    			msg.obj = bm;
    	    			msg.what = GET_OK;
    	    			handler.sendMessage(msg);
    	    			//顯示在界面上
    	    			//ImageView imageView = (ImageView) findViewById(R.id.lv);
    	    			//imageView.setImageBitmap(bm);
    	    		}
    	    		else {
    	    			//發送獲取失敗的消息
						Message msg = handler.obtainMessage();
						msg.what = GET_ERROR;
						handler.sendMessage(msg);
					}

消息處理過程:

 

 

static final int GET_ERROR = 0;
	static final int GET_OK  = 1;
	Handler handler = new Handler()
	{
		public void handleMessage(android.os.Message msg) 
		{
			//更新UI
			switch (msg.what) {
			case GET_OK:
				ImageView imageView = (ImageView) findViewById(R.id.lv);
				imageView.setImageBitmap((Bitmap) msg.obj);
				break;
			case GET_ERROR:
				Toast.makeText(MainActivity.this, 訪問失敗!, Toast.LENGTH_SHORT).show();
				break;
			default:
				break;
			}
			
		};
	};

我們可以將地址改錯,顯示效果

 

\

關於消息機制簡單說明一下:

1:發生消息系統會使用消息隊列(MessageQueue)和消息輪詢對象(Looper)

2:消息輪詢對象的作用就是不停的檢測消息隊列中是否有小心,如果一旦有消息,消息輪詢器就會將消息對象交給消息處理器(Handler),處理器會調用handleMessage方法來處理這條消息。handleMessage方法運行在主線程中,所以可以刷新ui

 

但是平常應用中,比如微信朋友圈的大量圖片,第一次浏覽時都是先緩沖到本地,第二次浏覽時直接從本地讀取即可,那我們來實現一下:

 

    public void click(View v)
    {
    	//指定文件的路徑
		final File file = new File(getCacheDir(), info.jpg);
    	//如果文件存在,直接從本地打開
		if(file.exists())
    	{
			System.out.println(從緩存讀取的);
			Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
			ImageView imageView = (ImageView) findViewById(R.id.lv);
			imageView.setImageBitmap(bm);
    	}
		else {
			
			System.out.println(從網上下載的);
    	//開啟一個線程
    	Thread thread = new Thread()
    	{
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    	    	//1: 確定網址
    	    	String path = http://192.168.1.109:8080/meinv.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();
    	    			
    	    			//讀取服務器返回流裡的數據,把數據寫入到本地,緩沖起來
    	    			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();
    	    			is.close();
    	    			
    	    			//從本地加載圖片
    	    			Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());
    	    			
    	    			//讀取流裡的數據,構建成bitmap位圖
    	    			//Bitmap bm = BitmapFactory.decodeStream(is);
    	    			
    	    			//發生更新UI的消息
    	    			Message msg = handler.obtainMessage();
    	    			msg.obj = bm;
    	    			msg.what = GET_OK;
    	    			handler.sendMessage(msg);
    	    			//顯示在界面上
    	    			//ImageView imageView = (ImageView) findViewById(R.id.lv);
    	    			//imageView.setImageBitmap(bm);
    	    		}
    	    		else {
    	    			//發送獲取失敗的消息
						Message msg = handler.obtainMessage();
						msg.what = GET_ERROR;
						handler.sendMessage(msg);
					}
    			} catch (Exception e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	};
    	
    	//啟動線程任務
    	thread.start();
    }
    }

上面是增加從本地緩沖中獲取圖片文件。

 

第一次運行時:包文件名下的cache下就會存在info.jpg文件

\

緩沖文件

\

當退出再次進來,就會直接從緩沖去獲取

 

\

 

關於從網絡上獲取文件,就簡單的說到這裡

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved