Android應用開發-網絡編程(一)

 

網絡圖片查看器

 

  1. 肯定圖片的網址html

  2. 發送http請求java

URL url = new URL(address);
// 獲取客戶端和服務器的鏈接對象,此時尚未創建鏈接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 設置請求方式,注意必須大寫
conn.setRequestMethod("GET");
// 設置鏈接和讀取超時
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
// 發送請求,與服務器創建鏈接
conn.connect();
// 若是響應碼爲200,說明請求成功
if(conn.getResponseCode() == 200){

}

 

  3. 服務器的圖片是以流的形式返回給瀏覽器的android

InputStream is = conn.getInputStream();   // 拿到服務器返回的輸入流
Bitmap bm = BitmapFactory.decodeStream(is);// 把流裏的數據讀取出來,並構形成位圖對象

 

  4. 把位圖對象顯示至ImageView數組

ImageView iv = (ImageView) findViewById(R.id.iv);
iv.setImageBitmap(bm);

 

  須要添加權限瀏覽器

<uses-permission android:name="android.permission.INTERNET"/>

 

 

網絡請求

 

主線程阻塞

  在Android中,主線程被阻塞會致使UI中止刷新,用戶體驗將很是差,若主線程阻塞時間過長,就會拋出ANR(Application Not Responding,即應用無響應)異常。所以任何耗時操做都不該該在主線程進行,不然可能使主線程阻塞。由於網絡請求屬於耗時操做,若是網速很慢,線程會被阻塞,因此網絡請求的代碼不能寫在主線程中。緩存

 

 

消息傳遞機制

  • 主線程又稱UI線程,由於只有在主線程中才能刷新UI。若是須要在子線程中刷新UI,須要藉助Handler的消息傳遞機制服務器

  • 主線程建立時,系統會爲主線程建立一個Looper(ActivityThread中的main方法中依次調用Looper.prepareMainLooper(),Looper.loop()),而Looper對象在初始化時會建立一個與之關聯的MessageQueue網絡

  • 若是是子線程的話,須要咱們本身在子線程調用Looper.prepare()來爲子線程建立一個Looper(Looper對象在初始化時仍會建立一個與之關聯的MessageQueue),而後再調用Looper.loop()來啓動這個Looperapp

  • Looper.loop()使用一個死循環不斷的取出MessageQueue中的Message,而後將Message分發給曾經發送它的Handler進行處理(若是MessageQueue中沒有Message,loop()方法會暫時阻塞,實際上Android系統的UI線程始終處於loop死循環中,一旦退出這個消息循環,App也就退出了)ide

  • Handler收到Message後會回調它的handleMessage()來處理這條Message。若是這個handleMessage()方法運行在主線程中,就能夠刷新UI

    /**
     * 調用默認的構造器new一個Handler會將它與所在的線程關聯起來
     * 若是Handler關聯的線程沒有Looper,就會拋出以下異常
     * java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
     * 這裏是在主線程中直接new一個Handler,不會拋異常,且handleMessage()能夠刷新UI
     */
    android.os.Handler handler = new android.os.Handler(){
    
        public void handleMessage(Message msg) {
    
        }
    };

     

  • 在子線程中向Handler所在線程的MessageQueue裏發送Message

    Message msg = handler.obtainMessage();// 這樣建立Message對象比直接new更節省空間
    msg.obj = bm;  // obj字段能夠賦值任何對象,用來攜帶數據
    msg.what = 1;   // what字段至關於一個標籤,用來區分出不一樣的Message,從而進行不一樣的處理
    handler.sendMessage(msg);

     

  • 經過switch語句區分不一樣的Message

    public void handleMessage(android.os.Message msg) {
        switch (msg.what) {
        // 若是是1,說明是請求成功的Message
        case 1:
            ImageView iv = (ImageView) findViewById(R.id.iv);
            Bitmap bm = (Bitmap) msg.obj;
            iv.setImageBitmap(bm);
            break;
        case 2:
            Toast.makeText(MainActivity.this, "請求失敗", 0).show();
            break;
        }       
    }

 

 

加入緩存圖片的功能

  讀取服務器返回的流裏的數據,把數據寫到本地文件緩存起來

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();

 

  讀取緩存的數據,並構形成位圖對象

Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath());

 

  每次發送請求前檢測一下在緩存中是否存在同名圖片,若是存在,則讀取緩存

 

 

Html源文件查看器

 

  發送GET請求

URL url = new URL(path);
//獲取鏈接對象,此時還未創建鏈接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//設置鏈接屬性
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
// 能夠不寫conn.connect();
// 若是不寫conn.connect();,getResponseCode()會先創建鏈接,而後得到響應碼
if(conn.getResponseCode() == 200){

}

 

  獲取服務器返回的流,從流中把html源碼讀取出來

InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while((len = is.read(b)) != -1){
    //把讀到的字節先寫入字節數組輸出流中存起來
    bos.write(b, 0, len);
}
//把字節數組輸出流中的內容轉換成字符串
//Android系統默認使用utf-8編碼
text = new String(bos.toByteArray());

 

 

亂碼的處理

  亂碼的出現是由於服務器端和客戶端碼錶不一致所致

text = new String(bos.toByteArray(), "gb2312");// 手動指定碼錶

 

 

提交數據

 

GET方式提交數據

  GET方式提交的數據是直接拼接在url的末尾

final String path = "http://192.168.1.104/Web/servlet/CheckLogin?name=" + name + "&pass=" + pass;

 

  發送GET請求,代碼和以前同樣

URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
if(conn.getResponseCode() == 200){

}

 

  瀏覽器在發送請求攜帶數據時會對數據進行URL編碼,咱們寫代碼時也須要爲中文進行URL編碼(這裏用戶名name使用了中文)

final String path = "http://192.168.1.104/Web/servlet/CheckLogin?name=" + URLEncoder.encode(name) + "&pass=" + pass;

 

 

POST方式提交數據

  POST提交數據是用流寫給服務器的。協議頭中多了兩個屬性:

    Content-Type: application/x-www-form-urlencoded,描述提交的數據的mimetype

    Content-Length: 32,描述提交的數據的長度

// 給請求頭添加post多出來的兩個屬性
String data = "name=" + URLEncoder.encode(name) + "&pass=" + pass;
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", data.length() + "");

 

  設置容許打開POST請求的流

conn.setDoOutput(true);

 

  獲取鏈接對象的輸出流,往流裏寫要提交給服務器的數據

OutputStream os = conn.getOutputStream();
os.write(data.getBytes());
相關文章
相關標籤/搜索