1.我們在Android下,實現使用http協議進行網絡通信,請求網絡數據。這里是獲取網絡上的圖片信息,讓它可以顯示在手機上;
但是我們這個手機連接網絡是很費時間,如果我們在主線程(UI線程)中寫這個網絡連接的邏輯,這是很容易報一個錯誤:android.os.NetworkOnMainThreadException(Android4.0之后引入的異常)
主線程很重要,它負責監聽系統的各種事件,如果主線程在一段時間內沒有響應,系統就會這個應用程序無響應,就會產生ANR的異常。下面有必要說明一下這個ANR異常:
2.ANRs ("Application Not Responding"),意思是"應用沒有響應".
在如下情況下,Android會報出ANR錯誤:
?主線程 ("事件處理線程"/ "UI線程") 在5秒內沒有響應輸入事件.
??BroadcastReceiver 沒有在10秒內完成返回.
通常情況下,下面這些做法會導致ANR:
(1).在主線程內進行網絡操作
(2).在主線程內進行一些緩慢的磁盤操作(例如執行沒有優化過的SQL查詢)
應用應該在5秒或者10秒內響應,否則用戶會覺得“這個應用很垃圾”“爛”“慢”…等等
邏輯應該是:
(1). new出一個新的線程,進行數據請求.
(2). 獲取數據后,調用handler.sendMessage方法.
(3). 在handler的handle()方法中更新UI.
案例:
activity_main.xml:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 tools:context=".MainActivity" > 6 7 <Button 8 android:onClick="click" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:layout_centerHorizontal="true" 12 android:layout_centerVertical="true" 13 android:text="點我" /> 14 15 </RelativeLayout>
MainActivity.java:
package com.itheima.anr;import android.app.Activity; import android.os.Bundle; import android.view.View;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View view){try {System.out.println(Thread.currentThread().getName());Thread.sleep(6000);//當前線程。 } catch (InterruptedException e) {e.printStackTrace();}}}
這里的Thread.sleep(6000),這里的表示Thread線程是Main線程,也就是UI主線程,我們之前說過了UI主線程在5s不能響應,系統就會認為這個應用程序是不響應的。這里6s>5s,所以會報錯ANRs ("Application Not Responding")
?
3.前面說了這么多,也就是說了關于在Android下進行網絡連接注意事項,網絡連接是耗時程序代碼:下面開始實現網絡圖片瀏覽器程序:
MainActivity.java:
package com.itheima.netimageviewer;import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL;import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.text.TextUtils; import android.util.Base64; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast;public class MainActivity extends Activity {private EditText et_path;private ImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);iv = (ImageView) findViewById(R.id.iv);}/*** 點擊查看網絡上的圖片* * @param view*/public void click(View view) {String path = et_path.getText().toString().trim();// http://www.baidu.com/aa.pngif (TextUtils.isEmpty(path)) {Toast.makeText(this, "圖片路徑不能為空", 0).show();return;}//把文件名編碼之后+緩沖的路徑變成file文件File file = new File(getCacheDir(), Base64.encodeToString(path.getBytes(), Base64.DEFAULT));if (file.exists() && file.length() > 0) {System.out.println("圖片存在,拿緩存");Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());iv.setImageBitmap(bitmap);} else {System.out.println("圖片不存在,獲取數據生成緩存");// 通過http請求把圖片獲取下來。try {// 1.聲明訪問的路徑, url 網絡資源 http ftp rtspURL url = new URL(path);// 2.通過路徑得到一個連接 http的連接HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 3.判斷服務器給我們返回的狀態信息。// 200 成功 302 重定向 404資源沒找到 5xx 服務器內部錯誤int code = conn.getResponseCode();if (code == 200) {//這個流是用來接收圖片的InputStream is = conn.getInputStream();// png的圖片//這個輸出流是吧圖片寫入安卓系統的儲存區的FileOutputStream fos = new FileOutputStream(file);//讀寫操作byte[] buffer = new byte[1024];int len = -1;while ((len = is.read(buffer)) != -1) {fos.write(buffer, 0, len);}is.close();fos.close();//通過圖片工廠來獲取文件路徑, 然后變成圖片傳遞給控件Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());iv.setImageBitmap(bitmap);} else {// 請求失敗Toast.makeText(this, "請求失敗", 0).show();}} catch (Exception e) {e.printStackTrace();Toast.makeText(this, "發生異常,請求失敗", 0).show();}}} }
activity_main.xml:
<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"tools:context=".MainActivity" ><EditTextandroid:text="http://www.baidu.com/img/bd_logo1.png"android:id="@+id/et_path"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="請輸入網絡圖片的路徑" /><Buttonandroid:onClick="click"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="查看" /><ImageViewandroid:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.himi.webpicturewatch"android:versionCode="1"android:versionName="1.0" ><uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/><uses-sdkandroid:minSdkVersion="15"android:targetSdkVersion="17" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
?