Android 網路學習之擷取伺服器的圖片

來源:互聯網
上載者:User

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 blocke.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) {//更新UIImageView 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) {//更新UIswitch (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檔案

緩衝檔案

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

 

 

關於從網路上擷取檔案,就簡單的說到這裡

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.