首先讓我們來看 SimpleGoogleSearch.java, 程式碼如下所示 : 1 public class SimpleGoogleSearch extends Activity { 2 3 EditText et_searchstr; 4 Button btn_search; 5

Similar documents
用手機直接傳值不透過網頁連接, 來當作搖控器控制家電 ( 電視遙控器 ) 按下按鍵發送同時會回傳值來確定是否有送出 問題 :1. 應該是使用了太多 thread 導致在傳值上有問題 2. 一次按很多次按鈕沒辦法即時反應

多媒體應用 13 新增專案並完成版面配置 <ExMusic01> <activity_main.xml> ImageView ID imgplay ImageView ID imgstop ImageView ID imgfront TextView ID txtsong TextView ID t

單步除錯 (1/10) 打開 Android Studio, 點選 Start a new Android Studio project 建立專案 Application name 輸入 BMI 點下 Next 2 P a g e

主程式 : public class Main3Activity extends AppCompatActivity { ListView listview; // 先整理資料來源,listitem.xml 需要傳入三種資料 : 圖片 狗狗名字 狗狗生日 // 狗狗圖片 int[] pic =new

建立Android新專案

建立Android新專案

雲端 Cloud Computing 技術指南 運算 應用 平台與架構 10/04/15 11:55:46 INFO 10/04/15 11:55:53 INFO 10/04/15 11:55:56 INFO 10/04/15 11:56:05 INFO 10/04/15 11:56:07 INFO

Android Service

ShareText

投影片 1

任務二 : 產生 20 個有炸彈的磚塊, 放在隨機的位置編輯 Block 類別的程式碼 import greenfoot.; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) Write a description of class

(TestFailure) JUnit Framework AssertionFailedError JUnit Composite TestSuite Test TestSuite run() run() JUnit

untitled

Dynamic Layout in Android

Database_001

Microsoft Word - 01.DOC

1: public class MyOutputStream implements AutoCloseable { 3: public void close() throws IOException { 4: throw new IOException(); 5: } 6:

輕鬆學 Dreamweaver CS5 網頁設計..\Example\Ch0\ \.html..\example\ch0\ \mouse.txt..\example\ch0\ \ _Ok.html 學習重點 JavaScript 複製程式碼 mouse.txt Ctrl+C Ctrl+C 0-4

res/layout 目录下的 main.xml 源码 : <?xml version="1.0" encoding="utf 8"?> <TabHost android:layout_height="fill_parent" xml


untitled

The golden pins of the PCI card can be oxidized after months or years

1.JasperReport ireport JasperReport ireport JDK JDK JDK JDK ant ant...6

詞 彙 表 編 號 詞 彙 描 述 1 預 約 人 資 料 中 文 姓 名 英 文 姓 名 身 份 證 字 號 預 約 人 電 話 性 別 2 付 款 資 料 信 用 卡 別 信 用 卡 號 信 用 卡 有 效 日 期 3 住 房 條 件 入 住 日 期 退 房 日 期 人 數 房 間 數 量 入

運算子多載 Operator Overloading

Spyder Anaconda Spyder Python Spyder Python Spyder Spyder Spyder 開始 \ 所有程式 \ Anaconda3 (64-bit) \ Spyder Spyder IPython Python IPython Sp

建模与图形思考

Outlook 2010 設定說明 Offic 企業郵件 / 虛擬主機郵件 / Office 365

Outlook 2007 設定說明 Offic 企業郵件 / 虛擬主機郵件 / Office 365

導讀 ASP.NET HTML ASP 第一篇 基礎篇第 1 章 認識 ASP.NET ASP.NET ASP.NET ASP.NET ASP.NET 第 2 章 認識 Visual Studio 20 開發環境 Visual Studio 20 Visual Studio 20 第二篇 C# 程式

Android Fragment

實作SQLiteOpenHelper類別

chapter 2 HTML5 目錄iii HTML HTML HTML HTML HTML canvas

7 TextView tv = (TextView)findViewById(R.id.tv_birthday); 8 9 Context otherapp = null; try { 12 otherapp = createpackagecontext("lincyu.horoscop

EJB-Programming-4-cn.doc

2016 勒索軟體白皮書

關於本書 l 3 PhoneGap Appcelerator Titanium Sencha Touch (wrapper framework) Native App PhoneGap Build Native App Hybrid App Java Objective-C Android SDK

關於本書 Part 3 CSS XHTML Ajax Part 4 HTML 5 API JavaScript HTML 5 API Canvas API ( ) Video/Audio API ( ) Drag and Drop API ( ) Geolocation API ( ) Part 5

! 2000 CSSsprites.com Web FTP app 20% 80% getelementbyid() UI Facebook F8 Web CSSsprites.com Web JavaScript CSS React xi React UI UI 反應 UI 宣告 d

使用手冊

Chapter V.S. PC

Microsoft Word - 第1章 Android基本概念.docx

untitled

( )... 5 ( ) ( )

Fun Time (1) What happens in memory? 1 i n t i ; 2 s h o r t j ; 3 double k ; 4 char c = a ; 5 i = 3; j = 2; 6 k = i j ; H.-T. Lin (NTU CSIE) Referenc

書面

Microsoft Word - PHP7Ch01.docx

CU0594.pdf

Android Android Android SDK iv

引 例 3 现 实 生 活 中 的 电 子 商 务 案 例 1 王 小 姐 是 一 家 网 络 公 司 职 员, 现 在 已 经 是 有 八 个 月 身 孕 的 准 妈 妈 由 于 出 行 不 是 很 方 便, 但 是 又 要 购 置 一 些 孕 妇 与 婴 儿 出 生 后 的 物 品 于 是 来

Java

封面-12

untitled

(CIP) Web /,. :, ISBN X.W T P393.4 CIP (2004) Web ( ) ( / ) : * 787

一、

2 WF 1 T I P WF WF WF WF WF WF WF WF 2.1 WF WF WF WF WF WF

The Embedded computing platform

課程簡介

TextView: 用來顯示 月 EditText: 讓使用者輸入日期 Button: 使用者按下 得知星座 的按鈕後, 可以查詢自己的星座, 程式會切換到另一個頁陎, 顯示星座的圖示及相關資訊 規畫好使用者介陎後, 我們就可以開始撰寫 XML 檔, 請讀者自行參考光碟內的檔案 \ 範例程式 \Ch

RecyclerView and CardVew

(Microsoft Word - \244\255\244U\260\352\273yok)

Python a p p l e b e a r c Fruit Animal a p p l e b e a r c 2-2

1 1 大概思路 创建 WebAPI 创建 CrossMainController 并编写 Nuget 安装 microsoft.aspnet.webapi.cors 跨域设置路由 编写 Jquery EasyUI 界面 运行效果 2 创建 WebAPI 创建 WebAPI, 新建 -> 项目 ->

02 2 成立 Facebook 粉絲專頁 Facebook Facebook Facebook 1, Facebook Facebook 1 Facebook 2-21

AutoCAD 用戶如何使用 ArchiCAD

Windows 10 在數位轉型下 所扮演的重要角色暨安全功能介紹

hw4

Java java.lang.math Java Java.util.Random : ArithmeticException int zero = 0; try { int i= 72 / zero ; }catch (ArithmeticException e ) { // } 0,


Chapter 9: Objects and Classes

WebSphere Studio Application Developer IBM Portal Toolkit... 2/21 1. WebSphere Portal Portal WebSphere Application Server stopserver.bat -configfile..

Android TSC Bluetooth/Ethernet 函式庫使用說明 1. openport(a) Bluetooth openport(a) 說明 : 指定電腦端的輸出埠參數 : a: 字串型別直接指定 Bluetooth MacAdress, 如 00:19:0E:A0:04:E1 Et

06 C H A P T E R 6-1 WWW 6-2 WWW WWW WWW

untitled

Microsoft PowerPoint - Class5.pptx

chp6.ppt

《大话设计模式》第一章

Microsoft PowerPoint - VB14.ppt

Maasa停車場管理系統

Chapter 3 Camera Raw Step negative clarity +25 ] P / Step 4 0 ( 下一頁 ) Camera Raw Chapter 3 089

CC213

Microsoft Word - 02.目錄.doc

The Embedded computing platform

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

JavaIO.PDF

<ADB6ADB1C25EA8FAA6DB2D4D56432E706466>

0511-Android程式之GPS應用_專題週記4

Transcription:

Chapter 13 網際網路 作者 : 林致孙 網路已成為現今大部份人使用電腦的最大目的, 我們也常利用網路來查詢一些生活資訊, 然而有時當我們想查詢某些資料, 例如火車時刻表, 這時人卻在戶外, 就會感到非常不便, 手機上網解決了這個問題, 因此上網可以說是一個智慧型手機應該具備的基本功能 在這一章中我們將學習一些跟網際網路相關的應用程式, 包含了網頁的瀏覽以及檔案的傳輸 13.1 網頁瀏覽 網頁瀏覽可以說是大部份人上網的最主要行為之一, 在本節中筆者將示範三種連 上網頁的方法 : 使用 HTTP[1] 相關類別 呼叫手機內建瀏覽器與使用 WebView[2] 13.1.1 HTTP 相關類別 HTTP (Hypertext Transfer Protocol) 是一個應用層網路協定, 此通訊協定主要是應用於網頁的瀏覽, 通訊協定是採用請求與回應模式的主從架構, 客戶端 (Client, 一般的網頁瀏覽器都屬於 HTTP 客戶端 ) 發送出請求 ( 利如需要某個網頁的資料 ) 後, 伺服器端 (Server) 會回應客戶端的相關請求, 這個回應包含了回應的標頭 (Header) 以及網頁內容本身 (Entity), 相關的細節請參考相關的 RFC 文件 [1] Android 提供了許多 HTTP 相關的類別, 然而開發者必須對 HTTP 有一定程度的瞭解才能看懂類別的說明文件, 筆者是認為除非是有特殊的需求, 例如需要對網頁的內容做分析 (Parse) 或對網頁的圖檔做處理, 才需要使用較低階的 HTTP 類別來存取網頁資料, 否則呼叫手機内建的瀏覽器或使用 WebView 應該就能滿足單純瀏覽網頁的需求 筆者還是使用了一個範例來說明幾個 HTTP 相關類別的使用, 請讀者引進光碟中 \ 範例程式 \Chapter13\SimpleGoogleSearch1 這個專案, 這個應用程式包含了兩個 Activity: SimpleGoogleSearch.java: 這個 Activity 有一個 EditText 讓使用者輸入搜尋關鍵字, 按下按鈕後會利用 HTTP 相關類別連上 Google[3], 搜尋的結果會儲存成字串並傳送給下一個 Activity:ShowResult ShowResult.java: 這個 Activity 繼承了 ListActivity, 會將搜尋結果字串做分析 (Parse), 將搜尋結果顯示於列表介面元件上

首先讓我們來看 SimpleGoogleSearch.java, 程式碼如下所示 : 1 public class SimpleGoogleSearch extends Activity { 2 3 EditText et_searchstr; 4 Button btn_search; 5 6 @Override 7 public void oncreate(bundle savedinstancestate) { 8 super.oncreate(savedinstancestate); 9 setcontentview(r.layout.main); 10 11 et_searchstr = (EditText)findViewById(R.id.et_searchstr); 12 btn_search = (Button)findViewById(R.id.btn_search); 13 btn_search.setonclicklistener(btn_listener); 14 } 15 16 OnClickListener btn_listener = new OnClickListener() { 17 public void onclick(view v) { 18 String str = et_searchstr.gettext().tostring(); 19 str = "http://www.google.com.tw/search?q=" + str; 20 HttpGet request = new HttpGet(str); 21 String result = ""; 22 try { 23 DefaultHttpClient client = new DefaultHttpClient(); 24 HttpResponse response = client.execute(request); 25 if (response.getstatusline().getstatuscode() == 200) { 26 result = EntityUtils.toString( 27 response.getentity()); 28 } 29 } catch (Exception e) { 30 return; 31 } 32 Intent intent = new Intent(); 33 intent.putextra("key_result", result); 34 intent.setclass(simplegooglesearch.this, 35 ShowResult.class); 36 startactivity(intent);

37 } 38 }; 39 } 先前已提過 HTTP 是一個採用請求與回應 (Request/Response) 模式的主從架構, 第 20 行我們先設定想要送出的請求,HTTP 的請求方法有三種, 會於請求的標頭 (Header) 中指明 : GET: 取得指定 URI 的資料, 得到的回應會包含標頭以及指定 URI 的資料內容 (Entity) HEAD: 跟 GET 方法完全一樣, 然而回應只會包含標頭 POST: 發出的請求除了會傳送標頭外, 也會攜帶些內容給伺服器, 通常是在上傳檔案或於部落格發表文章時使用 此範例中我們使用 HttpGet 類別產生一個請求 [4], 其中 URI 的字串表示是在第 19 行的地方設定的, 至於筆者是如何知道如此的 URI 設定就可請 Google 幫忙做查詢呢? 讀者只要於 Google 搜尋主頁中做幾次查詢並觀察 URI 的內容即可推導出 URI 的設定方式 接著第 23 行, 我們產生一個 DefaultHttpClient 物件 [5], 這個物件可視為是一個簡單的 HTTP 客戶端, 其繼承並實作了 AbstractHttpClient 抽象類別 [6],AbstractHttpClient 類別有一個 execute 方法能讓我們執行請求 (Request) 的發送, 並會回傳一個 HttpResponse 物件 [7] HttpResponse 就是從伺服器傳回來的回應 (Response), 回應的標頭中會有一行狀態行, 狀態行裡有一個狀態碼, 其中 404 可能是讀者較為熟悉的, 也就是找不到網頁的意思, 而 200 代表成功地取得指定 URI 的內容, 取得回應後, 程式利用 EntityUtils 類別 [8] 的 tostring 方法將回應的主體 ( 不含標頭 ) 轉成字串, 以本程式為例, 主體為 Google 所產生的一份 HTML 文件, 這個字串會傳送給下一個 Activity:ShowResult 接著我們來觀看 ShowResult.java 的內容 : 1 public class ShowResult extends ListActivity { 2 3 @Override 4 public void oncreate(bundle savedinstancestate) { 5 super.oncreate(savedinstancestate); 6 setcontentview(r.layout.results); 7 8 Intent intent = getintent(); 9 String result = intent.getstringextra("key_result"); 10 ArrayList<String> results = parsegoogleresult(result);

11 ListAdapter adapter = new ArrayAdapter<String>(this, 12 R.layout.list_item, results); 13 setlistadapter(adapter); 14 } 15 16 ArrayList<String> parsegoogleresult(string searchresult) { 17 ArrayList<String> results = new ArrayList<String>(); 18 19 StringBuilder t = new StringBuilder(""); 20 StringBuilder w = new StringBuilder(""); 21 22 boolean tagflag = false; 23 boolean wantedflag = false; 24 25 for (int i = 0; i < searchresult.length(); i++) { 26 char c = searchresult.charat(i); 27 if (c == '<') { 28 tagflag = true; 29 t = new StringBuilder(""); 30 continue; 31 } else if (c == '>') { 32 tagflag = false; 33 if (t.tostring().equals("h3 class=r")) { 34 wantedflag = true; 35 w = new StringBuilder(""); 36 } 37 if (t.tostring().equals("/h3")) { 38 if (wantedflag == true) { 39 wantedflag = false; 40 results.add(w.tostring()); 41 } 42 } 43 } 44 if (tagflag == true) 45 t.append(c); 46 if (tagflag == false && wantedflag == true && c!= '>') 47 w.append(c); 48 }

49 return results; 50 } 51 } 首先筆者利用電腦上的瀏覽器對 Google 做了搜尋, 並檢視搜尋結果的 HTML 原始檔, 發現搜尋結果的標題會被 <h3 class=r> 及其尾標籤 </h3> 包起來 ( 注意 : 如果 Google 更改了其搜尋結果的 HTML 文件格式, 本程式範例便失效了 ), 根據這特性, 筆者寫了一個簡單的分析器 (Parser), 請讀者自行閱讀 parsegoogleresult 方法的內容, 其會回傳一個字串動態陣列, 其可做為列表介面元件的 資料, 列表介面元件的細節我們就不再贅述 下面分別是筆者使用電腦上的瀏覽器做搜尋的結果畫面以及使用本應用程式做搜尋的結果畫面 ( 搜尋關鍵字為 Android):

最後要提醒讀者的是, 要讓此應用程式正常運作, 必須於應用程式描述檔 AndroidManifest.xml 內加上需要使用網際網路的聲明, 如下所示 : <uses-permission android:name="android.permission.internet"> </uses-permission> 使用 HTTP 相關類別做網頁的瀏覽實在並不是一個好方法, 不僅沒有一個好的使用者介面, 開發者也必須對 HTTP 本身有一定程度的瞭解, 例如瞭解請求的方法種類, 回應的回應狀態碼意義等 [1], 筆者是認為會使用 HTTP 相關類別的時機大部份是我們需要對回應主體 (Entity) 做分析或處理時才需要使用到 HTTP 相關類別, 否則呼叫內建的瀏覽器或使用 WebView 應該就能滿足單純瀏覽網頁的需求 13.1.2 呼叫手機內建的瀏覽器 在第六章時, 我們簡單介紹過 不明確的 Intent (Implicit Intent) 的概念, 一個不明確的 Intent 丟到系統後, 系統如何決定由哪一個應用程式來接收這個 Intent 呢? 主要是利用 Action 與 Data 的組合來判斷 [9], 其中若 Action 為 ACTION_VIEW 而 Data 為網頁形式的 URI 時, 系統便會將 Intent 交給內建的瀏覽器來處理, 請讀者引進光碟中 \ 範例程式 \Chapter13\SimpleGoogleSearch2 這個專案, 這個應用程式只有一個 Activity,SimpleGoogleSearch.java 的內容如下 : 1 public class SimpleGoogleSearch extends Activity { 2 3 EditText et_searchstr; 4 Button btn_search; 5 6 @Override 7 public void oncreate(bundle savedinstancestate) { 8 super.oncreate(savedinstancestate); 9 setcontentview(r.layout.main); 10 11 et_searchstr = (EditText)findViewById(R.id.et_searchstr); 12 btn_search = (Button)findViewById(R.id.btn_search); 13 btn_search.setonclicklistener(btn_listener); 14 } 15 16 OnClickListener btn_listener = new OnClickListener() { 17 public void onclick(view v) { 18 String str = et_searchstr.gettext().tostring();

19 str = "http://www.google.com.tw/search?q=" + str; 20 21 Uri uri = Uri.parse(str); 22 23 Intent intent = new Intent(Intent.ACTION_VIEW, uri); 24 startactivity(intent); 25 } 26 }; 27 } 首先在第 23 行, 程式呼叫了下面這個 Intent 建構子來產生一個不明確的 Intent: Intent(String action, Uri uri) 其中 Uri 物件的參數設定法請讀者自行參閱程式碼 19 與 21 行 呼叫 startactivity 後, 內建的瀏覽器就會被啟動, 執行結果如下圖所示 ( 搜尋關鍵字為 Android): 13.1.3 使用 WebView 使用内建的瀏覽器我們便能輕鬆地讓自己的程式瀏覽網頁, 然而有些讀者可能認 為這種內建的瀏覽器無法呈現自己的特色, 如果想建立一個具自我特色與風格的 簡易瀏覽器該如何做到呢?WebView 介面元件提供了一個解決方法 [10] 請讀者引進光碟中 \ 範例程式 \Chapter13\SimpleGoogleSearch3 這個專案, SimpleGoogleSearch 這個 Activity 會傳送搜尋關鍵字給 ShowResult, 我們把焦點放在 ShowResult 這個 Activity, 其內容如下所示 : 1 public class ShowResult extends Activity {

2 @Override 3 public void oncreate(bundle savedinstancestate) { 4 super.oncreate(savedinstancestate); 5 setcontentview(r.layout.mywebview); 6 7 Intent intent = getintent(); 8 9 String keyword = intent.getstringextra("key_keyword"); 10 11 TextView tv = (TextView)findViewById(R.id.tv_keyword); 12 tv.settext(" 查詢關鍵字為 :" + keyword); 13 14 String url = "http://www.google.com.tw/search?q=" + keyword; 15 16 WebView wv = (WebView)findViewById(R.id.webview); 17 wv.loadurl(url); 18 } 19 } 首先來到第 5 行, 要說明的是這個應用程式所採用的版面設計檔 mywebview.xml, 其包含了兩個 TextView, 其中一個 TextView 的 id 為 tv_keyword, 此外還包含了一個 WebView, 其 id 為 webview 程式於 11~12 行設定了 tv_keyword 這個 TextView 所要呈現的文字 於 16~17 行設定了 webview 這個 WebView 所要呈現的網頁, 只要簡單地呼叫 loadurl 方法即可, 執行結果如下圖所示 :

WebView 還提供了一個 loaddata 方法, 讓我們能夠像設計網頁般設計我們的版面, 請讀者引進光碟中 \ 範例程式 \Chapter13\InternetDemo 這個專案, 裡面只有一個 Activity,InternetDemo.java 的內容如下所示 : 1 public class InternetDemo extends Activity { 2 3 @Override 4 public void oncreate(bundle savedinstancestate) { 5 super.oncreate(savedinstancestate); 6 setcontentview(r.layout.main); 7 8 TextView tv = (TextView)findViewById(R.id.tv); 9 10 String tvcontent = "Chih-Yu Lin's Homepage: " + 11 "http://asia.edu.tw/~lincyu"; 12 13 tv.settext(tvcontent); 14 15 WebView wv = (WebView)findViewById(R.id.wv); 16 17 String simplepage = "<html><body><img src=" + 18 "http://asia.edu.tw/~lincyu/aboutme/chihyu.jpg" + 19 "></img></body><html>"; 20 21 wv.loaddata(simplepage, "text/html", "utf-8"); 22 } 23 } 從這個範例我們可以學到兩件事, 第一件事是如果 TextView 有設定屬性 android:autolink="web", 那麼當 TextView 所呈現的文字含有網頁 URL 時, 文字 會變成一個鏈結, 點下去後會使用內建的瀏覽器開啟網頁 第二件學到的事是 loaddata 的使用範例, 程式於 17~19 行設計了一個簡單的 HTML 格式的頁面, 接著於第 21 行放入 loaddata 當做參數即可顯示該頁面, 執 行結果如下圖所示 :

最後還是要再次提醒讀者, 使用 WebView 時必須記得於 AndroidManifest.xml 加 上需要使用網際網路的聲明 13.2 檔案傳輸 檔案的傳輸也是網際網路上一個很重要的主題, 本節首先將使用 HTTP 示範如何從網站下載檔案, 雖然 HTTP 也可以做檔案的上傳, 但是需要在伺服器端有一個對應的 CGI 程式, 為了讓上傳檔案較為單純, 本節也會說明如何使用 FTP 來做檔案的上傳與下載 13.2.1 使用 HTTP 下載檔案 首先來看使用 HTTP 下載檔案的範例, 事實上利用 13.1.1 節所學到的技巧, 將收到的回應 (Response) 的主體 (Entity) 儲存成檔案也是一種下載檔案的方法, 然而這節我們另外來學習 URLConnection 類別的使用 [11], 請讀者引進光碟中 \ 範例程式 \Chapter13\HTTPDownload 這個專案, 裡面只有一個 Activity:HTTPDownload, 其會從網站上抓取一個文字檔和一個影像檔, 然後分別將它們顯示於 TextView 及 ImageView 上, 筆者預先準備了一個文字檔及影像檔並將它們放在筆者的個人網頁上, 網址分別是 : 文字檔 :http://asia.edu.tw/~lincyu/android/txtfile.txt 影像檔 :http://asia.edu.tw/~lincyu/aboutme/chihyu.jpg 接下來我們可以開始討論程式的細節了,HTTPDownload.java 的內容如下 : 1 public class HTTPDownload extends Activity {

2 3 @Override 4 public void oncreate(bundle savedinstancestate) { 5 super.oncreate(savedinstancestate); 6 setcontentview(r.layout.main); 7 8 TextView tv = (TextView)findViewById(R.id.tv); 9 ImageView iv = (ImageView)findViewById(R.id.iv); 10 11 String tv_src = 12 "http://asia.edu.tw/~lincyu/android/txtfile.txt"; 13 String iv_src = 14 "http://asia.edu.tw/~lincyu/aboutme/chihyu.jpg"; 15 16 try { 17 StringBuilder tv_text = new StringBuilder(""); 18 19 URL url = new URL(tv_src); 20 URLConnection conn = url.openconnection(); 21 conn.connect(); 22 InputStream is = conn.getinputstream(); 23 int c = -1; 24 do { 25 c = is.read(); 26 if (c!= -1) tv_text.append((char)c); 27 } while (c!= -1); 28 tv.settext(tv_text.tostring()); 29 is.close(); 30 31 url = new URL(iv_src); 32 conn = url.openconnection(); 33 conn.connect(); 34 is = conn.getinputstream(); 35 Bitmap bitmap = BitmapFactory.decodeStream(is); 36 is.close(); 37 iv.setimagebitmap(bitmap); 38 } catch (Exception e) { 39 return;

40 } 41 } 42 } 首先在第 19 行中, 程式產生了一個 URL 物件 [12], 接著於在第 20 行, 程式產生一個 URLConnection 物件, 先呼叫 URLConnection 的 connect 方法再呼叫 getinputstream 方法便能取得文字檔的內容, 請讀者自行閱讀相關的程式碼以及相關的類別說明文件, 影像檔也是使用類似的做法, 程式碼是位於 31~37 行, 讀者要利用模仿的技巧來改寫這個程式應該不困難 最後還是要提醒讀者於 AndroidManifest.xml 加上需使用網際網路的聲明 下面是此應用程式執行的結果 : 13.2.2 使用 FTP 傳輸檔案 雖然我們能利用 HTTP 做檔案的下載, 可是要上傳檔案時會遇到一些麻煩, 伺服器端必須有一個 CGI 程式來接收上傳得檔案, 開發者還必須自己完成那個 CGI 程式, 事實上檔案的傳輸還是使用 FTP (File Transfer Protocol)[13] 較為容易, 因此本節將討論如何於 Android 上使用 FTP 來做檔案的傳輸 很不幸的 Android 本身並沒有提供 FTP 相關的類別讓開發者使用, 不過我們可利用 Jakarta Commons Net 的 API 來實作與 FTP 相關的應用程式 首先做一點簡單的背景介紹,Apache Commons 提供了許多 Java 的函式庫 [14],Jakarta Commons Net 是其中一個函式庫 [15], 其網頁上有對此函式庫的歷史背景做介紹, 讀者也可於該網頁上下載該函式庫, 筆者是下載 2.0 的版本, 下載後進行解壓縮, 可以看到數個 jar 檔, 其中 commons-net-ftp-2.0.jar 就是我們之後要使用的函式庫

然而若筆者只是給讀者一個範例, 讀者對於類別與方法的使用並無法全盤瞭解, 因此是否類似於 Android 開發者網站一樣有類別的說明文件呢? 答案是肯定的, 解壓縮後讀者可看到 apidocs 資料夾, 進入後點選 index.html 即可, 此外 Apache Commons 的網站上也有線上版本 [16] 那麼該如何使用此函式庫呢, 首先於 Java Perspective 的視窗選擇 Package Explorer, 於選定的專案上按下右鍵, 接著再選擇 Build Path Add External Archives, 就會出現下圖右側的畫面, 至解壓縮的目錄選擇 commons-net-ftp-2.0.jar 即完成載入函式庫的動作 現在我們可以開始討論範例程式了, 請讀者引進光碟中 \ 範例程式 \Chapter13\FTPDemo 這個專案, 裡面有兩個 Activity: FTPDemo: 此為登入畫面, 使用者可於此處輸入使用者帳號與密碼 並將使用者輸入的帳號密碼利用 Intent 傳送給 FTPMain 關於這個 Activity 要學的只有 : 如何讓使用者在輸入密碼時不被他人看到, 方法是在輸入密碼的那個 EditText 中加上 android:password="true" 屬性 ( 於 main.xml 中加入 ) FTPMain: 此為處理 FTP 相關操作的 Activity, 收到 FTPDemo 傳來的使用者帳號與密碼後會於 oncreate 方法內做登入的動作, 並設定兩個按扭 : Upload a file: 按下這個按鈕後, 程式會先產生一個名為 upload.txt 的檔案,upload.txt 只是一個文字檔, 內容為 Upload, 檔案會上傳至伺服器中 ~/public_html/android/ 這個資料夾, ~ 代表使用者的家目錄, 而檔名則改為 uploadfile.txt Download a file: 按下這個按鈕後, 會下載 ~/public_html/android/txtfile.txt 這個檔案( 上一小節中我們是用 HTTP 下載該檔案 ), 檔案會被儲存於 /data/data/lincyu.ftpdemo/files/ 這個資料夾, 而檔名則改為 download.txt 接著我們便開始細看 FTPMain.java, 其內容如下 :

1 public class FTPMain extends Activity { 2 3 FTPClient client; 4 boolean isconnected; 5 6 @Override 7 public void oncreate(bundle savedinstancestate) { 8 super.oncreate(savedinstancestate); 9 setcontentview(r.layout.ftpmain); 10 11 Intent intent = getintent(); 12 13 String username = intent.getstringextra("key_username"); 14 String password = intent.getstringextra("key_password"); 15 16 Button btn = (Button)findViewById(R.id.upload); 17 btn.setonclicklistener(upload_l); 18 btn = (Button)findViewById(R.id.download); 19 btn.setonclicklistener(download_l); 20 21 client = new FTPClient(); 22 23 isconnected = false; 24 try { 25 client.connect("asia.edu.tw"); 26 int replycode = client.getreplycode(); 27 if (!FTPReply.isPositiveCompletion(replycode)) { 28 client.disconnect(); 29 showtoast(this, "Connection fail"); 30 return; 31 } 32 if (!client.login(username, password)) { 33 showtoast(this, "Login fail"); 34 return; 35 } else { 36 client.enterlocalpassivemode(); 37 isconnected = true; 38 }

39 } catch (Exception e) { 40 showtoast(this, e.tostring()); 41 } 42 } 43 44 OnClickListener upload_l = new OnClickListener() { 45 public void onclick(view v) { 46 if (isconnected == false) 47 return; 48 49 try { 50 /* Generate the file that will be uploaded */ 51 FileOutputStream fos = FTPMain.this.openFileOutput( 52 "upload.txt", Context.MODE_PRIVATE); 53 final String content = "Upload"; 54 for (int i = 0; i < content.length(); i++) 55 fos.write((int)content.charat(i)); 56 fos.close(); 57 58 /* Upload */ 59 client.setfiletype(ftp.ascii_file_type); 60 FileInputStream fis = new FileInputStream(new File( 61 "/data/data/lincyu.ftpdemo/files/upload.txt")); 62 client.storefile( 63 "~/public_html/android/uploadfile.txt", fis); 64 showtoast(ftpmain.this, "Done!"); 65 } catch (Exception e) { 66 showtoast(ftpmain.this, e.tostring()); 67 } 68 } 69 }; 70 71 OnClickListener download_l = new OnClickListener() { 72 public void onclick(view v) { 73 if (isconnected == false) 74 return; 75 76 try {

77 /* Download */ 78 client.setfiletype(ftp.ascii_file_type); 79 InputStream is = client.retrievefilestream( 80 "~/public_html/android/txtfile.txt"); 81 82 /* Write to file */ 83 FileOutputStream fos = FTPMain.this.openFileOutput( 84 "download.txt", Context.MODE_PRIVATE); 85 86 int c = -1; 87 do { 88 c = is.read(); 89 if (c!= -1) fos.write(c); 90 } while (c!= -1); 91 is.close(); 92 fos.close(); 93 showtoast(ftpmain.this, "Done!"); 94 } catch (Exception e) { 95 showtoast(ftpmain.this, e.tostring()); 96 } 97 } 98 }; 99 100 private void showtoast(context mctx, String failmsg) { 101 Toast.makeText(mCtx, failmsg, Toast.LENGTH_SHORT).show(); 102 } 103 } FTP 連線與登入的動作是寫在 oncreate 方法內, 程式碼是位於 21~41 行, 其中第 25 行,connect 方法的參數可填入伺服器的 IP 或 Domain name, 剩餘的程式碼若不是很瞭解或對 FTP 的運作原理不是很清楚, 可先利用模仿的技巧完成登入的動作 檔案上傳的程式碼是寫在 58~64 行, 由於我們上傳的是一個純文字檔, 因此檔案類型選擇 ASCII_FILE_TYPE, 若是傳輸影像檔或其它非純文字檔, 請改成 BINARY_FILE_TYPE, 上傳主要是透過 storefile 方法 檔案的下載則是寫在 77~92 行, 下載主要是透過 retrievefilestream 方法

讀者可於擁有帳號密碼的 FTP 伺服器做程式的測試, 下面是筆者所做的上傳測 試, 上傳前若觀看上傳檔案會產生下圖的畫面 : 上傳後就可以看到該檔案了, 如下圖所示 : 下載的測試則可以透過 adb shell 或是 DDMS 裡的 File Explorer 來檢查檔案是否 下載成功, 下圖是利用 adb shell 所做的檢查 :

13.3 摘要 手機上網可說是智慧型手機的基本功能, 而上網的行為中, 網頁的瀏覽和檔案的傳輸佔了很大的比例, 本章我們學習了如何於 Android 平台上開發一個能夠瀏覽網頁的應用程式, 也學習了如何利用 Apache Commons 所提供的 Jakarta Commons Net 函式庫完成一個簡單的 FTP 客戶端程式, 然而若想要全盤地理解本章的內容, 除了閱讀相關 API 的使用方法外,RFC(Request for Comments) 文件的閱讀也是必要的 [1][13] 13.4 作業 1. 利用 WebView 設計一個有自我風格的瀏覽器 2. 利用 13.1.1 節學到的 HTTP 相關類別來做檔案的下載 3. 改寫 FTPDemo, 讓使用者可以輸入伺服器的 IP 或 Domain name 13.5 參考資料 [1] Hypertext Transfer Protocol HTTP/1.1, http://www.w3.org/protocols/rfc2616/rfc2616.html [2] WebView Android Developers, http://developer.android.com/reference/android/webkit/webview.html [3] Googe, http://www.google.com/ [4] HttpGet Android Developers, http://developer.android.com/reference/org/apache/http/client/methods/httpget.html [5] DefaultHttpClient Android Developers, http://developer.android.com/reference/org/apache/http/impl/client/defaulthttpclient. html [6] AbstractHttpClient Android Developers, http://developer.android.com/reference/org/apache/http/impl/client/abstracthttpclient.html

[7] HttpResponse Android Developers, http://developer.android.com/reference/org/apache/http/httpresponse.html [8] EntityUtils Android Developers, http://developer.android.com/reference/org/apache/http/util/entityutils.html [9] Intents and Intent Filters Android Developers, http://developer.android.com/guide/components/intents-filters.html [10] WebView Android Developers, http://developer.android.com/reference/android/webkit/webview.html [11] URLConnection Android Developers, http://developer.android.com/reference/java/net/urlconnection.html [12] URL Android Developers, http://developer.android.com/reference/java/net/url.html [13] File Transfer Protocol RFC959, http://www.faqs.org/rfcs/rfc959.html [14] Apache Commons, http://commons.apache.org/ [15] Commons Net Jakarta Commons Net, http://commons.apache.org/net/ [16] Overview (Commons Net 3.2 API), http://commons.apache.org/net/api-3.2/index.html