try { // 2.把網址字符串封裝成一個URL URL url = new URL(path); // 3.獲取鏈接對象 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 4.作參數設置,注意大寫 conn.setRequestMethod("GET"); // 5.設置鏈接超時時間 conn.setConnectTimeout(8000); // 設置讀取超時時間 conn.setReadTimeout(8000); // 發送請求,創建鏈接 conn.connect(); // 6. 獲取返回碼,判斷請求返回狀態 if (conn.getResponseCode() == 200) { // 請求成功 // 7.拿到服務器返回的流,裏面的數據就是客戶端請求的內容 InputStream is = conn.getInputStream(); // 在肯定流中數據是圖片的狀況下可使用Google提供的API直接生成圖片,就不須要本身讀取流了 //==================================================================================================================== //從流裏讀取數據就是在下載數據,若是網速過慢就會形成主線程阻塞(主線程阻塞在2.3能夠,可是4.0+版本的Android會拋出異常) Bitmap bm = BitmapFactory.decodeStream(is); //==================================================================================================================== ImageView iv = (ImageView) findViewById(R.id.imageView1); iv.setImageBitmap(bm); } else { Toast.makeText(this, "請求失敗", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
(應用)主線程阻塞html
規範android
問題:怎麼用子線程中處理過的數據去刷新UI
MessageQueue 消息隊列git
Looper 輪詢器(會一直不停的檢測消息隊列裏面是否有消息) * 消息隊列沒有數據,就什麼都不幹 * 消息隊列有消息,就扔給Handler去處理程序員
Handler * handleMessage()方法用來處理消息 - 重寫該方法來處理咱們的消息github
在主線程建立時會同時建立MessageQueue和Looper對象,可是Handler對象在程序員須要使用是,(程序員)自行建立。 只要消息隊列有消息,handleMessage()方法就會在主線程調用編程
子線程須要刷新UI,只須要往主線程的消息隊列中發送一條數據便可數組
栗子:瀏覽器
public class MainActivity extends Activity { // 建立消息處理器 Handler handler = new Handler() { // 重寫handleMessage方法 public void handleMessage(android.os.Message msg) { switch (msg.what) { case 0: ImageView iv = (ImageView) findViewById(R.id.imageView1); iv.setImageBitmap((Bitmap) msg.obj); break; case 1: Toast.makeText(MainActivity.this, "請求失敗", Toast.LENGTH_SHORT) .show(); break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View V) { Thread t = new Thread() { @Override public void run() { // 網址 String path = "http://192.168.15.27:8080/dd.jpg"; try { // 2.把網址字符串封裝成一個URL URL url = new URL(path); // 3.獲取鏈接對象 HttpURLConnection conn = (HttpURLConnection) url .openConnection(); // 4.作參數設置,注意大寫 conn.setRequestMethod("GET"); // 5.設置鏈接超時時間 conn.setConnectTimeout(8000); // 設置讀取超時時間 conn.setReadTimeout(8000); // 發送請求,創建鏈接 conn.connect(); // 6. 獲取返回碼,判斷請求返回狀態 if (conn.getResponseCode() == 200) { // 請求成功 // 7.拿到服務器返回的流,裏面的數據就是客戶端請求的內容 InputStream is = conn.getInputStream(); // 在肯定流中數據是圖片的狀況下可使用Google提供的API直接生成圖片,就不須要本身讀取流了 Bitmap bm = BitmapFactory.decodeStream(is); // ImageView iv = (ImageView) // findViewById(R.id.imageView1); // iv.setImageBitmap(bm); // 發送消息至主線程消息隊列 Message msg = new Message(); // 利用消息對象攜帶數據 msg.obj = bm; // 設置狀態標識(這裏設置的是成功獲取返回0) msg.what = 0; handler.sendMessage(msg); } else { // Message msg = new Message(); // msg.what = 0; // handler.sendMessage(msg); // 不須要攜帶數據時也能夠發送空消息,參數what handler.sendEmptyMessage(1); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; t.start(); } }
看代碼緩存
public class MainActivity extends Activity { // 建立消息處理器 Handler handler = new Handler() { // 重寫handleMessage方法 public void handleMessage(android.os.Message msg) { switch (msg.what) { case 0: ImageView iv = (ImageView) findViewById(R.id.imageView1); iv.setImageBitmap((Bitmap) msg.obj); break; case 1: Toast.makeText(MainActivity.this, "請求失敗", Toast.LENGTH_SHORT) .show(); break; } }; }; ………… public void click(View V) { // 網址 final String path = "http://192.168.15.27:8080/dd.jpg"; final File file = new File(getCacheDir(), getFileName(path)); // 判斷文件是否已將緩存到本地 if (!file.exists()) { // 是 直接讀取顯示 Bitmap bm = BitmapFactory.decodeFile(file.getAbsolutePath()); ImageView iv = (ImageView) findViewById(R.id.imageView1); iv.setImageBitmap(bm); } else { Thread t = new Thread() { @Override public void run() { try { // 2.把網址字符串封裝成一個URL // 3.獲取鏈接對象 // 4.作參數設置,注意大寫 // 5.設置鏈接超時時間 // 設置讀取超時時間 // 發送請求,創建鏈接 // 6. 獲取返回碼,判斷請求返回狀態 if (conn.getResponseCode() == 200) { // 請求成功 // 7.拿到服務器返回的流,裏面的數據就是客戶端請求的內容 InputStream is = conn.getInputStream(); FileOutputStream fos = new FileOutputStream(file); byte[] b = new byte[1024]; int len; while ((len = is.read(b)) != -1) { fos.write(b, 0, len); } fos.close(); //生成圖片 Bitmap bm = BitmapFactory.decodeFile(file .getAbsolutePath()); // 在肯定流中數據是圖片的狀況下可使用Google提供的API直接生成圖片,就不須要本身讀取流了 // Bitmap bm = BitmapFactory.decodeStream(is); // ImageView iv = (ImageView) // 發送消息至主線程消息隊列 // 利用消息對象攜帶數據 // 設置狀態標識(這裏設置的是成功獲取返回0) ……………… } else { handler.sendEmptyMessage(1); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; t.start(); } } /** * 獲取文件名 * * @param path * @return */ public String getFileName(String path) { int index = path.lastIndexOf("/"); return path.substring(index + 1); }
使用自定義組件時,標籤名字要寫包名安全
<com.loopj.android.image.SmartImageView/>
SmartImageView的使用
SmartImageView siv = (SmartImageView) findViewById(R.id.siv); siv.setImageUrl("http://192.168.1.102:8080/dd.jpg");
測試用第三方資源:android-smart-image-view-master.zip
發送GET請求
URL url = new URL(path); //獲取鏈接對象 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //設置鏈接屬性 conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); //創建鏈接,獲取響應嗎 if(conn.getResponseCode() == 200){ }
獲取服務器返回的流,從流中把html源碼讀取出來
byte[] b = new byte[1024]; int len = 0; ByteArrayOutputStream bos = new ByteArrayOutputStream(); while((len = is.read(b)) != -1){ //把讀到的字節先寫入字節數組輸出流中存起來 bos.write(b, 0, len); } //把字節數組輸出流中的內容轉換成字符串 //默認使用utf-8 text = new String(bos.toByteArray());
由於主線程不能執行網絡下載等其餘耗時的操做,而必須使用子線程去實現網絡下載等操做,可是要注意這裏面的線程異步問題。 如:主線程在刷新UI是調用了子線程沒有處理完畢內容致使的空指針等異常
ViewHolder * 避免了重複生成大量的view對象 * 先把佈局文件中的全部的組件封裝到ViewHolder對象中 * ViewHolder的對象會與View一塊兒被緩存起來 * 須要的時候直接xxx
解決亂碼問題很是簡單: 統一兩遍的編碼集。 android下默認編碼 utf-8
客戶端: 中文和特殊字符 URLEncoder.encode(); 服務器端: 默認的編碼 iso-8859-1 和 本地編碼(gbk)
發現 數據
�� gbk->utf-8 ??? utf-8 -> iso-8859-1 編碼不存在 錕腳達拷錕斤拷 無藥可救 刪除了重寫。
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編碼
String path = "http://192.168.1.104/Web/servlet/CheckLogin?name=" + URLEncoder.encode(name) + "&pass=" + pass;
GET方式提交數據的缺點: * 組拼http的URL的方式不安全。 * GET方式提交數據,對數據的長度是有要求的。http規範最大長度4K。
協議頭中多了兩個屬性
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());
POST方式提交數據的優缺點: * 代碼寫起來麻煩 注意4個細節。
優勢: * 安全。 * 提交數據的長度沒有限制。