編輯:關於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 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、表格內容可以根據數據源的定義合並列 3、要填寫的單元格可
安裝應用(APP) 不顯示圖標 本文地址:www.2cto.com 在啟動的activity的AndroidManifest注冊中,添加隱式啟
好不容易周末有空,作為一個零基礎非計算機專業剛培訓出來7個月的小白,對付博大精深的Android源碼真的是心有余而力不足,但是東西還是要學滴,這不!找到Hongyang大
ZXing是谷歌的一個開源庫,可以用來生成二維碼、掃描二維碼。本文所介紹的是第一部分。首先上效果圖:ZXing相關各種文件官方下載地址:https://github.co