編輯:關於Android編程
人性的弱點在於習慣於學習精確的東西而不善於總體的把握。
Android程序最重要的模塊就是網絡部分,如何從網絡上下載數據,如何將處理過的數據上傳至網絡,往往是android程序的關鍵環節。前幾天偶一朋友遇到這麼一個問題:如何使用volley實現文件上傳。最後問題解決了,小伙伴不禁有些飄飄然,大有一番天下之事皆逃不過我的魔掌的感覺。這時候coder君問了他幾個問題,大家可以一起思考下:
TCP/IP協議、SOCKET、HTTP協議、HTTPS協議都是做什麼的,他們之間有關系嗎 你是如何管理網絡使用情況的 常用的HTTP Client有哪些,該如何選擇 假如你需要修改的你網絡請求框架,你要動多少代碼 你是怎麼進行網絡優化的小伙伴支支吾吾,其實他熟悉的只是Android中網絡相關的那些點中的一小部分,不免有些盲人摸象的感覺,你呢?
網絡由下往上分為:物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。
IP協議對應於網絡層,TCP協議對應於傳輸層,而HTTP協議對應於應用層,三者從本質上來說沒有可比性,socket則是對TCP/IP協議的封裝和應用。也可以說,TPC/IP協議是傳輸層協議,主要解決數據如何在網絡中傳輸,而HTTP是應用層協議,主要解決如何包裝數據。
網絡編程的目的就是直接或間接地通過網絡協議與其他計算機進行通訊。
網絡編程中有兩個主要的問題,一個是如何准確的定位網絡上一台或多台主機;另一個就是找到主機後如何可靠高效的進行數據傳輸。目前使用最廣泛的因特網協議是TCP/IP協議。
在TCP/IP協議中IP層主要負責網絡主機的定位,數據傳輸的路由,由IP地址可以唯一地確定Internet上的一台主機。而TCP層則提供面向應用的可靠的或非可靠的數據傳輸機制,這是網絡編程的主要對象,一般不需要關心IP層是如何處理數據的。
我們知道兩個進程如果需要進行通訊最基本的一個前提能能夠唯一的標示一個進程,在本地進程通訊中我們可以使用PID來唯一標示一個進程,但PID只在本地唯一,網絡中的兩個進程PID沖突幾率很大,這時候我們需要另辟它徑了,我們知道IP層的ip地址可以唯一標示主機,而TCP層協議和端口號可以唯一標示主機的一個進程,這樣我們可以利用ip地址+協議+端口號唯一標示網絡中的一個進程。
能夠唯一標示網絡中的進程後,它們就可以利用socket進行通信了,什麼是socket呢?我們經常把socket翻譯為套接字,socket是在應用層和傳輸層之間的一個抽象層,它把TCP/IP層復雜的操作抽象為幾個簡單的接口供應用層調用已實現進程在網絡中通信。
Socket跟TCP/IP協議沒有必然的聯系。Socket編程接口在設計的時候,就希望也能適應其他的網絡協議。所以說,Socket的出現只是使得程序員更方便地使用TCP/IP協議棧而已,是對TCP/IP協議的抽象,
HTTP協議即超文本傳送協議(Hypertext Transfer Protocol ),是Web聯網的基礎,也是手機聯網常用的協議之一,HTTP協議是建立在TCP協議之上的一種應用。
HTTP連接最顯著的特點是客戶端發送的每次請求都需要服務器回送響應,在請求結束後,會主動釋放連接。從建立連接到關閉連接的過程稱為“一次連接”。
HTTP提供了封裝或者顯示數據的具體形式。Socket提供了網絡通信的能力。
HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。 它是一個URI scheme(抽象標識符體系),句法類同http:體系。用於安全的HTTP數據傳輸。https:URL表明它使用了HTTP,但HTTPS存在不同於HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。被廣泛用於萬維網上安全敏感的通訊,例如交易支付方面。
<-- 允許應用程序打開網絡套接字 -->
<-- 允許應用程序訪問網絡連接信息 -->
大多數連接網絡的 Android app 會使用 HTTP 來發送與接收數據。Android 提供了三種 HTTP client:HttpURLConnection、Apache HttpClient和okhttp。二者均支持 HTTPS、流媒體上傳和下載、可配置的超時、IPv6 與連接池(connection pooling)。
Java.net包中的HttpURLConnection類
HttpUrlConnection是JDK裡提供的聯網API,我們知道Android SDK是基於Java的,所以當然優先考慮HttpUrlConnection這種最原始最基本的API,其實大多數開源的聯網框架基本上也是基於JDK的HttpUrlConnection進行的封裝罷了
HttpClient
HttpClient是開源組織Apache提供的Java請求網絡框架,其最早是為了方便Java服務器開發而誕生的,是對JDK中的HttpUrlConnection各API進行了封裝和簡化,提高了性能並且降低了調用API的繁瑣,Android因此也引進了這個聯網框架,我們再不需要導入任何jar或者類庫就可以直接使用,值得注意的是Android官方已經宣布不建議使用HttpClient了,我們再開發的時候盡量少用吧,但是用了也無妨!
okhttp
http是現在主流應用使用的網絡請求方式, 用來交換數據和內容, 有效的使用HTTP可以使你的APP變的更快和減少流量的使用。
OkHttp是一個很棒HTTP客戶端:
支持SPDY,可以合並多個到同一個主機的請求
使用連接池技術減少請求的延遲(如果SPDY是可用的話)
使用GZIP壓縮減少傳輸的數據量
緩存響應避免重復的網絡請求
當你的網絡出現擁擠的時候,就是OKHttp大顯身手的時候,它可以避免常見的網絡問題,如果你的服務是部署在不同的IP上面的,如果第一個連接失敗,OkHTtp會嘗試其他的連接。這對現在IPv4+IPv6中常見的把服務冗余部署在不同的數據中心上也是很有必要的。OkHttp將使用現在TLS特性(SNI ALPN)來初始化新的連接,如果握手失敗,將切換到TLS 1.0。
使用OkHttp很容易,同時支持異步阻塞請求和回調.
如果你使用OkHttp ,你不用重寫你的代碼, okhttp-urlconnection模塊實現了 java.net.HttpURLConnection 中的API, okhttp-apache模塊實現了HttpClient中的API
如果我們的程序需要執行大量網絡操作,那麼應該提供用戶設置選項,來允許用戶控制程序的數據偏好。例如,同步數據的頻率,是否只在連接到 WiFi 才進行下載與上傳操作,是否在漫游時使用套餐數據流量等等。這樣用戶才不大可能在快到達流量上限時,禁止我們的程序獲取後台數據,因為他們可以精確控制我們的 app 使用多少數據流量。
在執行網絡操作之前,檢查設備當前連接的網絡連接信息是個好習慣。這樣可以防止我們的程序在無意間連接使用了非意向的網絡頻道。如果網絡連接不可用,那麼我們的應用應該優雅地做出響應。為了檢測網絡連接,我們需要使用到下面兩個類:
ConnectivityManager:它會回答關於網絡連接的查詢結果,並在網絡連接改變時通知應用程序。
NetworkInfo:描述一個給定類型(移動網絡或 Wi-Fi等)的網絡接口狀態。
下面這個方法可以找到的第一個已連接的網絡接口,如果返回null,則表示沒有已連接的網絡接口(意味著網絡連接不可用):
public boolean isOnline() {
ConnectivityManager connMgr = (ConnectivityManager)getSystemServic(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
我們可以實現一個偏好設置的選項,使用戶能直接設置程序對網絡資源的使用情況。例如:
可以允許用戶僅在連接到 Wi-Fi 時上傳視頻。
可以根據諸如網絡可用,時間間隔等條件來選擇是否做同步的操作。
要檢測網絡連接的變化需要用到BroadcastReceiver 的子類:NetworkReceiver。當設備網絡連接改變時,NetworkReceiver 會監聽到 CONNECTIVITY_ACTION,這時需要判斷當前網絡連接類型並相應的設置好 wifiConnected 與 mobileConnected。
這裡需要注意的是在使用BroadcastReceiver的時候,不必要的聲明注冊會浪費系統資源。最好在 onCreate()中注冊 BroadcastReceiver NetworkReceiver,在 onDestroy()中銷毀它。這樣做會比在 manifest 裡面聲明 更輕巧。
網絡操作會遇到不可預期的延遲。為了避免造成不好的用戶體驗,確保總是在 UI 線程之外單獨的線程中執行網絡操作。關於Android中的線程和進程可以參考這裡。
有了Http Client,我們需要考慮的是如何優雅的使用這些Http Client進行網絡請求。這時候我們可以對Http Clent進行封裝來滿足我們的需求。封裝的基本要點如下:
支持自定義請求的Header 支持Http的基本請求方法:GET、POST、PUT、DELETE等 支持文件上傳和下載 可以加載圖片 支持多任務網絡請求操作 支持緩存 支持請求回調 支持session的保持具體可以參考Volley源碼分析、Retrofit分析等,看看這些成名已久的框架是如何封裝的。
以下是曾經很火或者現在很多的網絡請求框架:
Android Async HTTP AndroidAsync Volley RetrofitAsyncHttp是一個較高層的封裝,底層使用的是HttpClient。
Volley是Google推出的Android異步網絡請求框架和圖片加載框架。底層網絡請求可以使用不同的網絡庫來處理,比如OkHttp,HttpClient。
Retrofit是一個封裝比較好的,相對更面向開發者的rest請求庫,它的底層網絡請求也可以使用不同的網絡庫來處理。
我在這些Tips讓你的App更容易維護 簡單提到過面向接口編程,這對於網絡框架再封裝很實用。
我們可以定義一套我們自己的網絡請求接口,接口規定我們需要有什麼能力的框架。調用的話我們可以直接調用接口方法就好了,這樣不管我們換什麼網絡框架,只要這個框架有網絡請求的能力就行。舉個例子,定義接口如下:
public interface ISender {
void send(METHOD method, String url, SenderCallback callback);
}
我們寫一個類實現這個接口:
public class BaseSender implements ISender {
@Override
public synchronized void sender(METHOD method, final String url, final SenderCallback callback) {
//volley,retrofit,balabala,用任意網絡請求框架實現。
}
}
然後是我們的SendCallback
public interface SendCallback {
//請求成功回調
void onSucceeed(String t);
//請求失敗回調
void onError(String errorMsg);
}
最後是我們的調用:
private ISender mHttp;
public void getWeahter(String tag) {
//調用接口裡定義好的方法
mHttp.sender();
}
這裡傳入我們需要的參數就好了。
以下是比較流行的網絡數據解析的庫:
Gson Jackson FastJson HtmlPaser Jsoup網絡數據解析比較基礎,這裡就不過多描述了。
對於手機程序,網絡操作相對來說是比較耗電的行為。優化網絡操作能夠顯著節約電量的消耗。一個網絡請求可以簡單分為連接服務器和獲取數據兩個部分。其中連接服務器前還包括 DNS 解析的過程;獲取數據後可能會對數據進行緩存。那麼我們如果要進行網絡優化需要從這兩個關鍵點入手。
以下是具體可以優化的點:
不用域名,用IP直連
省去 DNS 解析過程,DNS 全名 Domain Name System,解析意指根據域名得到其對應的IP地址。
服務器合理部署
服務器多運營商多地部署,一般至少含三大運營商、南中北三地部署。
根據當前的網絡環境選擇當下最佳的策略
主要的實施步驟有兩步:第1是檢測收集當前的網絡環境信息,第2是根據當前收集到的信息進行網絡請求行為的調整。
預取
我們需要預先判斷用戶在此次操作之後,後續零散的請求是否很有可能會馬上被觸發,可以把後面幾分鐘有可能會使用到的零散請求都一次集中執行完畢。
連接復用
節省連接建立時間,如開啟 keep-alive。
用捆綁批量訪問的方式來減少訪問的頻率
預先判定那些可能馬上就會使用到的網絡資源,捆綁一起集中進行網絡請求。這點我們可以考慮按照提前預期後續1-2分鐘的數據作為基准。
分優先級、延遲部分請求
首先我們需要區分哪些網絡請求是需要及時返回結果的,哪些是可以延遲執行的。我們可以有針對性的把請求行為捆綁起來,延遲到某個時刻統一發起請求。
對傳輸的數據進行壓縮
網絡傳輸數據量的大小主要由兩部分組成:圖片與序列化的數據,那麼我們需要做的就是減少這兩部分的數據傳輸大小。
多連接
對於較大文件,如大圖片、文件下載可考慮多連接。 需要控制請求的最大並發量,畢竟移動端網絡受限。
避免不必要的同步操作
應用程序的一個基礎功能是能夠保持確保界面上呈現的信息是即時最新的,例如呈現最新的新聞,天氣,信息流等等信息。但是,過於頻繁的促使手機客戶端應用去同步最新的服務器數據會對性能產生很大的負面影響,不僅僅使得CPU不停的在工作,內存,網絡流量,電量等等都會持續的被消耗,所以在進行網絡請求操作的時候一定要避免多度同步操作。
做好網絡數據的緩存
從手機的緩存中直接讀取數據肯定比從網絡上獲取數據要更加的便捷高效,特別是對於那些會被頻繁訪問到的數據,需要把這些數據緩存到設備上,以便更加快速的進行訪問。
本文實例講述了Android實現獲取SD卡總容量,可用大小,機身內存總容量及可用大小的方法。分享給大家供大家參考,具體如下:可能有的同學不知道系統已經提供了獲取獲取SD卡
Android中登錄界面的記住密碼功能實現,將用戶輸入的賬號和密碼以SharedPreferences方式存儲(注意的是,密碼要用MD5明文加密)。 界面xml
上幾節,我們學習如何用StartServer啟動一個服務,用bindServer去綁定一個服務,以及服務的生命周期,以及什麼是IntentService。或許有讀者會發現
當我們軟件中要使用大量數據,我們會選擇將這些數據存儲到一個數據庫中,然後通過數據庫的查詢修改操作來管理這些數據。大多數情況下我們都只在程序中建立使用數據庫,但也有我們在程