Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> 如何成為Android高手

如何成為Android高手

編輯:Android開發實例

 若立志成為Android高手,如有耐心,“一瓶一缽足矣”。 

  “天下事有難易乎?為之,則難者亦易矣;不為,則易者亦難矣。人之為學有難易乎?學之,則難者亦易矣;不學,則易者亦難矣。”想成為Android高手?這可不是想象中寫幾行代碼那麼容易的事情,但也不是不可實現。

  如何做?

  1,學會懶惰!奇怪吧?但是,你一定也聽說過和感受過這個世界某種程度上是由懶人推動的,生命在於懶惰,懶人創造世界。當然,懶惰也是真的傻傻的呆在那裡什麼都不做,而是說要善於想出做事情的更好的方式,這樣就可以節約大量的時間,也就有更多的機會懶惰了,同事也懶出了境界。在Android中如何懶惰?《如何成為Android高手》一文就如何在Android中學會懶惰和朋友們進行了分享。

  2,精通Android體系架構、MVC、常見的設計模式、控制反轉(IoC):這一點難嗎?“學之,則難者亦易矣;不學,則易者亦難矣。”

  3,編寫可重用、可擴展、可維護、靈活性高的代碼:Android應用程序開發的使用純粹面向對象的Java作為開發語言,自然也就繼承了關於Java關於面向對象的優秀想思想,如何做?《如何成為Android高手》一文就如何在Android中編寫可重用、可擴展、可維護、靈活性高的代碼和朋友們進行了分享。

  4,高效的編寫高效的代碼:高效的編寫代碼和編寫高效的代碼好像天生就是死敵。似乎開發速度上去了,程序的執行效率就下去了;程序的執行效率上去,開發速度就下去了。如何解決二者的忙著,請聽《如何成為Android高手》一文想大家娓娓道來。

  5,學會至少一門服務器端開發技術:沒搞錯吧,成為Android高手還需要學習服務端開發技術?對,需要!《如何成為Android高手》一文就該問題和大家進行了分享。 

  “蜀之鄙,有二僧:其一貧,其一富。貧者語於富者曰:"吾欲之南海,何如?"富者曰:"子何恃而往?"曰:"吾一瓶一缽足矣。"富者曰:"吾數年來欲買舟而下,猶未能也。子何恃而往!"越明年,貧者自南海還,以告富者,富者有慚色。西蜀之去南海,不知幾千裡也,僧富者不能至,而貧者至之,人之立志,顧不如蜀鄙之僧哉 ”

  若立志成為Android高手,如有耐心,“一瓶一缽足矣”。

  ·2007年底Google宣布舉辦總獎金高達1000萬美元的開發者大獎賽,鼓勵程序開發者在Android上寫出實用而又具有創意的應用程序;

  ·2009年5月27日,在Google的I/O開發者聚會上,Google發布了總獎金接近2000萬美元的第二次大獎賽的消息,開發者們開始了新一輪的較量;

Android是Google於2007年11月5日宣布的基於Linux平台的開源手機操作系統的名稱,該平台由操作系統、中間件、用戶界面和應用軟件組成,號稱是首個為移動終端打造的真正開放和完整的移動軟件。

  Android一出生就被打上了富二代的胎記,不僅僅是因為誕生於當今的網絡霸主Google,更主要還有一個空前強大和壯觀的開放手機聯盟OHA(Open Handset Alliance)提供全力的支持。OHA是什麼?OHA涵蓋了中國移動、T-Mobile、 Sprint等移動運營商,包括HTC、Motolora、三星等手機制造商,有Google為代表的手機軟件商,還有Inter、Nvidia為標志的底層硬件廠商和Astonishing Tribe等商業運作公司,該組織聲稱組織的所有成員都會基於Android來開發新的手機業務。

  但是,要成為Android高手並不是一件容易的事情。並不是很多人想象的能夠飛快的寫出幾行漂亮的代碼去解決一些困難的問題就是Android高手了。真正的Android高手需要考慮的問題遠遠不是寫些漂亮的代碼就足夠的。下面是成為一名真正的Android高手必須掌握和遵循的一些准則:

1,學會懶惰

2,精通Android體系架構、MVC、常見的設計模式、控制反轉(IoC)

3,編寫可重用、可擴展、可維護、靈活性高的代碼

4,高效的編寫高效的代碼

5,學會至少一門服務器端開發技術

 

一:學會懶惰

  沒搞錯吧?竟然讓程序開發人員學會懶惰?程序開發人員可能是世界上最為忙碌的一類人啦!對,沒錯,學會懶惰!正因為程序開發人員忙碌,正因為程序開發人員可能會在客戶無限變化的需求之下沒日沒夜的加班,所以要學會懶惰,這樣,你就可以把更多的時間浪費在美好的事物身上!

如何懶惰:

1,Don't Reinvent the Wheel(不要重復發明輪子)。

2,Inventing the Wheel(發明輪子)。

 

1,Don't Reinvent the Wheel(不要重復發明輪子)。

  “輪子理論”,也即“不要重復發明輪子”,這是西方國家的一句諺語,原話是:Don't Reinvent the Wheel。“不要重復發明輪子 ”意思是企業中任何一項工作實際上都有人做過,我們所需要做的就是找到做過這件事情的人。拿到軟件領域中就是指有的項目或功能,別人已經做過,我們需要用的時候,直接拿來用即可,而不要重新制造。  

   Android號稱是首個為移動終端打造的真正開放和完整的移動軟件。Android發布後不久Google公司就發布了操作系統核心(Kernel)與部分驅動程序的源代碼,到目前位置除了Google Map等Google公司的核心組件沒有開放源代碼外,Android基本完成了完全的開源,這就極大的促進了Android的普及和移植。受到Android開放行為和開源精神的影響,在世界各地,有成千上萬的程序員喜歡和別人分享自己的聰明才智和自己編寫的代碼。你可以在Google的Android討論組或者Google搜索引擎上搜索到很多優秀的程序代碼。這樣做並不是鼓勵大家整天等著讓別人為你編寫代碼,而是你可以“站在偉人的肩膀上”,充分發揚“拿來主義”,聰明地應用別人的程序代碼可以節省你大量的時間。
  下面筆者為大家介紹幾個通用的類,這些類來自筆者平日的收集,如果你能把它們加入到你自己的類庫中,遲早你會發現自己在進行Android開發的時候受益無窮:

1) 從輸入流中獲取數據並以字節數組返回,這種輸入流可以來自Android本地也可以來自網絡。

 

 1 import java.io.ByteArrayOutputStream;
2
3  import java.io.InputStream;
4
5
6
7 public class StreamTool {
8
9 /**
10
11 * 從輸入流獲取數據
12
13 * @param inputStream
14
15 * @return
16
17 * @throws Exception
18
19 */
20
21 public static byte[] readInputStream(InputStream inputStream) throws Exception {
22
23 byte[] buffer = new byte[1024]; //你可以根據實際需要調整緩存大小
24
25 int len = -1;
26
27 ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
28
29 while( (len = inputStream.read(buffer)) != -1 ){
30
31 outSteam.write(buffer, 0, len);
32
33 }
34
35 outSteam.close();
36
37 inputStream.close();
38
39 return outSteam.toByteArray();
40
41 }
42
43 }
44
45

 

 

2) 通過Android客戶端上傳數據到服務器:可以上傳簡單的表單,也可以方便的上傳帶有附件的文件,此類遠遠比Android自身的HttpClient更高效、更易於使用:

 

import java.io.DataOutputStream;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import java.net.URLEncoder;

import java.util.ArrayList;

import java.util.List;

import java.util.Map;



import org.apache.http.HttpResponse;

import org.apache.http.NameValuePair;

import org.apache.http.client.HttpClient;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.impl.client.DefaultHttpClient;

import org.apache.http.message.BasicNameValuePair;



public class HttpRequester {



/**

* 直接通過HTTP協議提交數據到服務器,實現如下面表單提交功能:

* <FORM METHOD=POST ACTION="http://192.168.0.200:8080/ssi/fileload/test.do" enctype="multipart/form-data">

<INPUT TYPE="text" NAME="name">

<INPUT TYPE="text" NAME="id">

<input type="file" name="imagefile"/>

<input type="file" name="zip"/>

</FORM>

* @param actionUrl 上傳路徑(注:避免使用localhost或127.0.0.1這樣的路徑測試,因為它會指向手機模擬器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080這樣的路徑測試)

* @param params 請求參數 key為參數名,value為參數值

* @param file 上傳文件

*/

public static String post(String actionUrl, Map<String, String> params, FormFile[] files) {

try {

String BOUNDARY = "---------7d4a6d158c9"; //數據分隔線

String MULTIPART_FORM_DATA = "multipart/form-data";



URL url = new URL(actionUrl);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setConnectTimeout(5* 1000);

conn.setDoInput(true);//允許輸入

conn.setDoOutput(true);//允許輸出

conn.setUseCaches(false);//不使用Cache

conn.setRequestMethod("POST");

conn.setRequestProperty("Connection", "Keep-Alive");

conn.setRequestProperty("Charset", "UTF-8");

conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA "; boundary=" BOUNDARY);



StringBuilder sb = new StringBuilder();

for (Map.Entry<String, String> entry : params.entrySet()) {//構建表單字段內容

sb.append("--");

sb.append(BOUNDARY);

sb.append("\r\n");

sb.append("Content-Disposition: form-data; name=\"" entry.getKey() "\"\r\n\r\n");

sb.append(entry.getValue());

sb.append("\r\n");

}

DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());

outStream.write(sb.toString().getBytes());//發送表單字段數據

for(FormFile file : files){//發送文件數據

StringBuilder split = new StringBuilder();

split.append("--");

split.append(BOUNDARY);

split.append("\r\n");

split.append("Content-Disposition: form-data;name=\"" file.getFormname() "\";filename=\"" file.getFilname() "\"\r\n");

split.append("Content-Type: " file.getContentType() "\r\n\r\n");

outStream.write(split.toString().getBytes());

if(file.getInStream()!=null){

byte[] buffer = new byte[1024];

int len = 0;

while((len = file.getInStream().read(buffer))!=-1){

outStream.write(buffer, 0, len);

}

file.getInStream().close();

}else{

outStream.write(file.getData(), 0, file.getData().length);

}

outStream.write("\r\n".getBytes());

}

byte[] end_data = ("--" BOUNDARY "--\r\n").getBytes();//數據結束標志

outStream.write(end_data);

outStream.flush();

int cah = conn.getResponseCode();

if (cah != 200) throw new RuntimeException("請求url失敗");

InputStream is = conn.getInputStream();

int ch;

StringBuilder b = new StringBuilder();

while( (ch = is.read()) != -1 ){

b.append((char)ch);

}

outStream.close();

conn.disconnect();

return b.toString();

} catch (Exception e) {

throw new RuntimeException(e);

}

}



/**

* 提交數據到服務器

* @param actionUrl 上傳路徑(注:避免使用localhost或127.0.0.1這樣的路徑測試,因為它會指向手機模擬器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080這樣的路徑測試)

* @param params 請求參數 key為參數名,value為參數值

* @param file 上傳文件

*/

public static String post(String actionUrl, Map<String, String> params, FormFile file) {

return post(actionUrl, params, new FormFile[]{file});

}



public static byte[] postFromHttpClient(String path, Map<String, String> params, String encode) throws Exception{

List<NameValuePair> formparams = new ArrayList<NameValuePair>();//用於存放請求參數

for(Map.Entry<String, String> entry : params.entrySet()){

formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));

}

UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");

HttpPost httppost = new HttpPost(path);

httppost.setEntity(entity);

HttpClient httpclient = new DefaultHttpClient();//看作是浏覽器

HttpResponse response = httpclient.execute(httppost);//發送post請求

return StreamTool.readInputStream(response.getEntity().getContent());

}



/**

* 發送請求

* @param path 請求路徑

* @param params 請求參數 key為參數名稱 value為參數值

* @param encode 請求參數的編碼

*/

public static byte[] post(String path, Map<String, String> params, String encode) throws Exception{

//String params = "method=save&name=" URLEncoder.encode("老畢", "UTF-8") "&age=28&";//需要發送的參數

StringBuilder parambuilder = new StringBuilder("");

if(params!=null && !params.isEmpty()){

for(Map.Entry<String, String> entry : params.entrySet()){

parambuilder.append(entry.getKey()).append("=")

.append(URLEncoder.encode(entry.getValue(), encode)).append("&");

}

parambuilder.deleteCharAt(parambuilder.length()-1);

}

byte[] data = parambuilder.toString().getBytes();

URL url = new URL(path);

HttpURLConnection conn = (HttpURLConnection)url.openConnection();

conn.setDoOutput(true);//允許對外發送請求參數

conn.setUseCaches(false);//不進行緩存

conn.setConnectTimeout(5 * 1000);

conn.setRequestMethod("POST");

//下面設置http請求頭

conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");

conn.setRequestProperty("Accept-Language", "zh-CN");

conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");

conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

conn.setRequestProperty("Content-Length", String.valueOf(data.length));

conn.setRequestProperty("Connection", "Keep-Alive");



//發送參數

DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());

outStream.write(data);//把參數發送出去

outStream.flush();

outStream.close();

if(conn.getResponseCode()==200){

return StreamTool.readInputStream(conn.getInputStream());

}

return null;

}

}



 

 

2,Inventing the Wheel(發明輪子)。

  發明輪子?不錯,發明輪子!我們不僅要發明輪子,更要成為努力成為世界上發明輪子的主導力量,唯有這樣,才能談的上中華名族軟件大業的真正強大。在Android,要發明輪子,就是我們要主動的是解決一些世界上他人未解決的難題或者創造新的編程框架或者對Android進行深度的改造以適合自己的業務發展需要。Google發布了Android後不久,中國移動便投入了大量的人力和物力,在Android的基礎上創建融入自己業務並開發、封裝了新的功能的和框架的OMS,這是Android中發明輪子的一個非常重要的例子。可能你會說,這發明輪子也太難了吧,別急,我們慢慢來,開發一個框架特定領域的框架吧!你可能會一臉無辜的說,開發一個框架是說的那麼容易嗎?當然不是啦。但是也並非不可能,首先,我們分析一下框架的魅力的源泉,看看Spring、Struts等Java EE框架,在看看.NET框架,當然也可以看看發展的如火如荼、層出不窮的PHP框架,她們的強大和魅力的源泉都在於:IoC(Inversion of Control)。

Don't call us, we'll call you(別找我,我會來找你的)。我們下面就自己發明一個輪子的模型,實際展示一個框架最初核心的類,讓你一飽眼福:

1) 下面的類是文件下載類,支持文件的多線程斷點續傳,使用該類的即可安全、高效的下載任何類型的二進制文件:

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.LinkedHashMap;

import java.util.Map;

import java.util.Properties;

import java.util.UUID;

import java.util.concurrent.ConcurrentHashMap;

import java.util.regex.Matcher;

import java.util.regex.Pattern;



import cn.itcast.service.FileService;



import android.content.Context;

import android.util.Log;

/**

* 文件下載器

*/

public class FileDownloader {

private Context context;

private FileService fileService;



private static final String TAG = "FileDownloader";

/* 已下載文件大小 */

private int downloadSize = 0;

/* 原始文件大小 */

private int fileSize = 0;

/* 線程數 */

private DownloadThread[] threads;

/* 下載路徑 */

private URL url;

/* 本地保存文件 */

private File saveFile;

/* 下載記錄文件 */

private File logFile;

/* 緩存各線程最後下載的位置*/

private Map<Integer, Integer> data = new ConcurrentHashMap<Integer, Integer>();

/* 每條線程下載的大小 */

private int block;

private String downloadUrl;//下載路徑

/**

* 獲取線程數

*/

public int getThreadSize() {

return threads.length;

}

/**

* 獲取文件大小

* @return

*/

public int getFileSize() {

return fileSize;

}

/**

* 累計已下載大小

* @param size

*/

protected synchronized void append(int size) {

downloadSize = size;

}

/**

* 更新指定線程最後下載的位置

* @param threadId 線程id

* @param pos 最後下載的位置

*/

protected void update(int threadId, int pos) {

this.data.put(threadId, pos);

}

/**

* 保存記錄文件

*/

protected synchronized void saveLogFile() {

this.fileService.update(this.downloadUrl, this.data);

}

/**

* 構建文件下載器

* @param downloadUrl 下載路徑

* @param fileSaveDir 文件保存目錄

* @param threadNum 下載線程數

*/

public FileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum) {

try {

this.context = context;

this.downloadUrl = downloadUrl;

fileService = new FileService(context);

this.url = new URL(downloadUrl);

if(!fileSaveDir.exists()) fileSaveDir.mkdirs();

this.threads = new DownloadThread[threadNum];

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setConnectTimeout(6*1000);

conn.setRequestMethod("GET");

conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");

conn.setRequestProperty("Accept-Language", "zh-CN");

conn.setRequestProperty("Referer", downloadUrl);

conn.setRequestProperty("Charset", "UTF-8");

conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");

conn.setRequestProperty("Connection", "Keep-Alive");

conn.connect();

printResponseHeader(conn);

if (conn.getResponseCode()==200) {

this.fileSize = conn.getContentLength();//根據響應獲取文件大小

if (this.fileSize <= 0) throw new RuntimeException("1無法獲知文件大小 ");



String filename = getFileName(conn);

this.saveFile = new File(fileSaveDir, filename);/* 保存文件 */

Map<Integer, Integer> logdata = fileService.getData(downloadUrl);

if(logdata.size()>0){

for(Map.Entry<Integer, Integer> entry : logdata.entrySet())

data.put(entry.getKey(), entry.getValue() 1);

}

this.block = this.fileSize / this.threads.length 1;

if(this.data.size()==this.threads.length){

for (int i = 0; i < this.threads.length; i ) {

this.downloadSize = this.data.get(i 1)-(this.block * i);

}

print("已經下載的長度" this.downloadSize);

}

}else{

throw new RuntimeException("2服務器響應錯誤 ");

}

} catch (Exception e) {

print(e.toString());

throw new RuntimeException("3連接不到下載路徑 ");

}

}

/**

* 獲取文件名

*/

private String getFileName(HttpURLConnection conn) {

String filename = this.url.toString().substring(this.url.toString().lastIndexOf('/') 1);

if(filename==null || "".equals(filename.trim())){//如果獲取不到文件名稱

for (int i = 0;; i ) {

String mine = conn.getHeaderField(i);

if (mine == null) break;

if("content-disposition".equals(conn.getHeaderFieldKey(i).toLowerCase())){

Matcher m = Pattern.compile(".*filename=(.*)").matcher(mine.toLowerCase());

if(m.find()) return m.group(1);

}

}

filename = UUID.randomUUID() ".tmp";//默認取一個文件名

}

return filename;

}



/**

* 開始下載文件

* @param listener 監聽下載數量的變化,如果不需要了解實時下載的數量,可以設置為null

* @return 已下載文件大小

* @throws Exception

*/

public int download(DownloadProgressListener listener) throws Exception{

try {

if(this.data.size() != this.threads.length){

this.data.clear();

for (int i = 0; i < this.threads.length; i ) {

this.data.put(i 1, this.block * i);

}

}

for (int i = 0; i < this.threads.length; i ) {

int downLength = this.data.get(i 1) - (this.block * i);

if(downLength < this.block && this.data.get(i 1)<this.fileSize){ //該線程未完成下載時,繼續下載

RandomAccessFile randOut = new RandomAccessFile(this.saveFile, "rw");

if(this.fileSize>0) randOut.setLength(this.fileSize);

randOut.seek(this.data.get(i 1));

this.threads[i] = new DownloadThread(this, this.url, randOut, this.block, this.data.get(i 1), i 1);

this.threads[i].setPriority(7);

this.threads[i].start();

}else{

this.threads[i] = null;

}

}

this.fileService.save(this.downloadUrl, this.data);

boolean notFinish = true;//下載未完成

while (notFinish) {// 循環判斷是否下載完畢

Thread.sleep(900);

notFinish = false;//假定下載完成

for (int i = 0; i < this.threads.length; i ){

if (this.threads[i] != null && !this.threads[i].isFinish()) {

notFinish = true;//下載沒有完成

if(this.threads[i].getDownLength() == -1){//如果下載失敗,再重新下載

RandomAccessFile randOut = new RandomAccessFile(this.saveFile, "rw");

randOut.seek(this.data.get(i 1));

this.threads[i] = new DownloadThread(this, this.url, randOut, this.block, this.data.get(i 1), i 1);

this.threads[i].setPriority(7);

this.threads[i].start();

}

}

}

if(listener!=null) listener.onDownloadSize(this.downloadSize);

}

fileService.delete(this.downloadUrl);

} catch (Exception e) {

print(e.toString());

throw new Exception("下載失敗");

}

return this.downloadSize;

}

/**

* 獲取Http響應頭字段

* @param http

* @return

*/

public static Map<String, String> getHttpResponseHeader(HttpURLConnection http) {

Map<String, String> header = new LinkedHashMap<String, String>();

for (int i = 0;; i ) {

String mine = http.getHeaderField(i);

if (mine == null) break;

header.put(http.getHeaderFieldKey(i), mine);

}

return header;

}

/**

* 打印Http頭字段

* @param http

*/

public static void printResponseHeader(HttpURLConnection http){

Map<String, String> header = getHttpResponseHeader(http);

for(Map.Entry<String, String> entry : header.entrySet()){

String key = entry.getKey()!=null ? entry.getKey() ":" : "";

print(key entry.getValue());

}

}



private static void print(String msg){

Log.i(TAG, msg);

}



public static void main(String[] args) {

/* FileDownloader loader = new FileDownloader(context, "http://browse.babasport.com/ejb3/ActivePort.exe",

new File("D:\\androidsoft\\test"), 2);

loader.getFileSize();//得到文件總大小

try {

loader.download(new DownloadProgressListener(){

public void onDownloadSize(int size) {

print("已經下載:" size);

}

});

} catch (Exception e) {

e.printStackTrace();

}*/

}



}

 

 

 

2) 下面的類是真正支持下載的線程類:

 

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;



import android.util.Log;



public class DownloadThread extends Thread {

private static final String TAG = "DownloadThread";

private RandomAccessFile saveFile;

private URL downUrl;

private int block;

/* 下載開始位置 */

private int threadId = -1;

private int startPos;

private int downLength;

private boolean finish = false;

private FileDownloader downloader;



public DownloadThread(FileDownloader downloader, URL downUrl, RandomAccessFile saveFile, int block, int startPos, int threadId) {

this.downUrl = downUrl;

this.saveFile = saveFile;

this.block = block;

this.startPos = startPos;

this.downloader = downloader;

this.threadId = threadId;

this.downLength = startPos - (block * (threadId - 1));

}



@Override

public void run() {

if(downLength < block){//未下載完成

try {

HttpURLConnection http = (HttpURLConnection) downUrl.openConnection();

http.setRequestMethod("GET");

http.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");

http.setRequestProperty("Accept-Language", "zh-CN");

http.setRequestProperty("Referer", downUrl.toString());

http.setRequestProperty("Charset", "UTF-8");

http.setRequestProperty("Range", "bytes=" this.startPos "-");

http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");

http.setRequestProperty("Connection", "Keep-Alive");



InputStream inStream = http.getInputStream();

int max = 1024 * 1024;

byte[] buffer = new byte[max];

int offset = 0;

print("線程 " this.threadId "從位置" this.startPos "開始下載 ");

while (downLength < block && (offset = inStream.read(buffer, 0, max)) != -1) {

saveFile.write(buffer, 0, offset);

downLength = offset;

downloader.update(this.threadId, block * (threadId - 1) downLength);

downloader.saveLogFile();

downloader.append(offset);

int spare = block-downLength;//求剩下的字節數

if(spare < max) max = (int) spare;

}

saveFile.close();

inStream.close();

print("線程 " this.threadId "完成下載 ");

this.finish = true;

this.interrupt();

} catch (Exception e) {

this.downLength = -1;

print("線程" this.threadId ":" e);

}

}

}

private static void print(String msg){

Log.i(TAG, msg);

}

/**

* 下載是否完成

* @return

*/

public boolean isFinish() {

return finish;

}

/**

* 已經下載的內容大小

* @return 如果返回值為-1,代表下載失敗

*/

public long getDownLength() {

return downLength;

}

}

 

 

3) 下面為監聽器接口,會實時顯示下載的大小,在實際使用的時候建議采用匿名類的方式構建此接口:

 

public interface DownloadProgressListener {

public void onDownloadSize(int size);

}

 

 

 

  上面的三個文件在一起就構建起了一個迷你型的Android下載框架,這個下載框架可以用於下載任何類型的二進制文件,以後需要下載的時候直接使用即可。其中IoC非常直接的體現就是DownloadProgressListener ,在使用的時候只需要只需要傳入該接口一個實現實例即可自動的獲取實時的下載長度。

 

二:精通Android體系架構、MVC、常見的設計模式、控制反轉(IoC)

1,請看某個著名的IT公司一則招聘信息的其中一條要求:“熟悉Android系統架構及相關技術,1年以上實際 Android平台開發經驗;”,裡面非常明確的說道要求熟練Android系統架構,這從某種程度上說明了對Android體系架構的理解的重要性,下面我們看看Android體系結構圖,該圖源自Android的文檔:

 

很明顯,上圖包含四個主要的層次:

Linux Kernel:負責硬件的驅動程序、網絡、電源、系統安全以及內存管理等功能。

Libraries和Android Runtime:Libraries:即C/C 函數庫部分,大多數都是開放源代碼的函數庫,例如WebKit,該函數庫負責Android網頁浏覽器的運行,例如標准的C函數庫Libc、OpenSSL、SQLite等,當然也包括支持游戲開發2D SGL和3D OpenGL | ES,在多媒體方面有MediaFramework框架來支持各種影音和圖形文件的播放與顯示,例如 MPEG4、H.264、MP3、AAC、AMR、JPG和PNG等眾多的多媒體文件格式。Android的Runtime負責解釋和執行生成的 Dalvik格式的字節碼。

  Application Framework(應用軟件架構),Java應用程序開發人員主要是使用該層封裝好的API進行快速開發。

Applications:該層是Java的應用程序層,Android內置的Google Maps、E-mail、即時通信工具、浏覽器、MP3播放器等處於該層,Java開發人員開發的程序也處於該層,而且和內置的應用程序具有平等的位置,可以調用內置的應用程序,也可以替換內置的應用程序。

上面的四個層次,下層為上層服務,上層需要下層的支持,調用下層的服務,這種嚴格分層的方式帶來的極大的穩定性、靈活性和可擴展性,使得不同層的開發人員可以按照規范專心特定層的開發。

Android應用程序使用框架的API並在框架下運行,這就帶來了程序開發的高度一致性,另一方面也告訴我們,要想寫出優質高效的程序就必須對整個Application Framework進行非常深入的理解。精通Application Framework,你就可以真正的理解Android的設計和運行機制,也就更能夠駕馭整個應用層的開發。

2,Android的官方建議應用程序的開發采用MVC模式。何謂MVC?先看看下圖

 

MVC是Model,View,Controller的縮寫,從上圖可以看出MVC包含三個部分:

l 模型(Model)對象:是應用程序的主體部分,所有的業務邏輯都應該寫在該層。

l 視圖(View)對象:是應用程序中負責生成用戶界面的部分。也是在整個MVC架構中用戶唯一可以看到的一層,接收用戶的輸入,顯示處理結果。

l 控制器(Control)對象:是根據用戶的輸入,控制用戶界面數據顯示及更新Model對象狀態的部分,控制器更重要的一種導航功能,想用用戶出發的相關事件,交給M哦得了處理。

Android鼓勵弱耦合和組件的重用,在Android中MVC的具體體現如下:

1) 視圖層(View):一般采用XML文件進行界面的描述,使用的時候可以非常方便的引入,當然,如何你對 Android了解的比較的多了話,就一定可以想到在Android中也可以使用JavaScript HTML等的方式作為View層,當然這裡需要進行Java和JavaScript之間的通信,幸運的是,Android提供了它們之間非常方便的通信實現。

2) 控制層(Controller):Android的控制層的重任通常落在了眾多的Acitvity的肩上,這句話也就暗含了不要在Acitivity中寫代碼,要通過Activity交割Model業務邏輯層處理,這樣做的另外一個原因是Android中的 Acitivity的響應時間是5s,如果耗時的操作放在這裡,程序就很容易被回收掉。

3) 模型層(Model):對數據庫的操作、對網絡等的操作都應該在Model裡面處理,當然對業務計算等操作也是必須放在的該層的。

3,設計模式和IoC(控制反轉)

毫無疑問,Android的之所以能夠成為一個開放的氣象萬千的系統,與設計模式的精妙應用是分不開的,只要你稍微用心觀察,就會發現在Android中到處都是A設計模式或者設計模式的聯合運用,一下的設計模式是您想游刃有余的駕馭Android必須掌握的:

l Template Method模式

l Factory Method模式

l Observer模式

l Abstract Factory模式

l Adapter模式

l Composite模式

l Strategy模式

l State模式

l Proxy模式

l Bridge模式

l Iterator模式

l Mediator模式

l Façade模式

 

Android框架魅力的源泉在於IoC,在開發Android的過程中你會時刻感受到IoC帶來的巨大方便,就拿Activity來說,下面的函數是框架調用自動調用的:

protected void onCreate(Bundle savedInstanceState) ;

不是程序編寫者主動去調用,反而是用戶寫的代碼被框架調用,這也就反轉了!當然IoC本身的內涵遠遠不止這些,但是從這個例子中也可以窺視出IoC帶來的巨大好處。此類的例子在Android隨處可見,例如說數據庫的管理類,例如說Android中SAX的Handler的調用等。有時候,您甚至需要自己編寫簡單的IoC實現,上面展示的多線程現在就是一個說明。

 

三:編寫可重用、可擴展、可維護、靈活性高的代碼

Android應用程序的開發是使用Java編寫,在架構上使用MVC,鼓勵組件之間的若耦合。開發出編寫可重用、可擴展、可維護、靈活性高的代碼需要經歷遵循以下原則:

l "開-閉"原則(OCP):一個軟件實體應當對擴展開放,對修改關閉。這個原則說的是,在設計一個模塊的時候,應當使這個模塊可以在不被修改的前提下被擴展。換言之,應當可以在不必修改源代碼的情況下改變這個模塊的行為。

l 裡氏代換原則(LSP):一個軟件實體如果使用的是一個基類的話,那麼一定使用於其子類,而且它根本不能察覺出基類對象和子類對象的區別。

l 依賴倒轉原則(DIP):要依賴於抽象,不要依賴於具體。

l 接口隔離原則(ISP):使用多個專門的接口比使用單一的總接口要好。一個類對另外一個類的依賴性應當是建立在最小的接口上的。 

l 合成/聚合復用原則(CARP):又稱合成復用原則(CRP),就是在一個新的對象裡面使用一些已有的對象,使之成為新對象的一部分;新的對象通過向這些對象的委派達到復用已有功能的目的。簡而言之就是:要盡量使用合成/聚合,盡量不要使用繼承。

l 迪米特法則(LoD):又稱最少知識原則(LKP),就是說一個對象應當對其他對象盡可能少的了解。狹義的迪米特法則是指如果兩個類不必彼此直接通信,那麼這兩個類就不應當發生直接的相互作用.如果其中一個類需要調用另一個類的方法的話,可以通過第三者轉發這個調用.。廣義的迪米特法則是指一個模塊設計得好壞的一個重要的標志就是該模塊在多大的程度上將自己的內部數據與實現有關的細節隱藏起來。信息的隱藏非常重要的原因在於,它可以使各個子系統之間脫耦,從而允許它們獨立地被開發,優化,使用閱讀以及修改.。

靈活的使用設計模式可以在面對千變萬化的業務需求是編寫出可重用、可擴展、可維護、靈活性高的代碼。

 

當然,由於Android是運行在移動設備上的,而移動設備的處理能力是有限的,所以有時間必須在編寫可重用、可擴展、可維護、靈活性高的代碼與高效的代碼之間做出適當的平衡。

 

四:高效的編寫高效的代碼

高效快速的編寫代碼和編寫高效率執行的代碼很多時候都是對立的死敵,很多時候,你想快速的開發,代碼的執行效率往往就會慢下來;你想編寫高效的代碼,開發速度就會慢下來。

不重復發明輪子和發明新的輪子是高效的編寫高效的代碼的正確是道路。

關於高效的代碼,下面網絡的一篇文章,直接轉載(不知道是哪位哥們寫的)如下:

“現代的手持設備,與其說是電話,更像一台拿在手中的電腦。但是,即使是“最快”的手持設備,其性能也趕不上一台普通的台式電腦。

這就是為什麼我們在書寫Android應用程序的時候要格外關注效率。這些設備並沒有那麼快,並且受電池電量的制約。這意味著,設備沒有更多的能力,我們必須把程序寫的盡量有效。

本文討論了很多能讓開發者使他們的程序運行更有效的方法,遵照這些方法,你可以使你的程序發揮最大的效力。
對於占用資源的系統,有兩條基本原則:
1. 不要做不必要的事
2. 不要分配不必要的內存

所有下面的內容都遵照這兩個原則。

有些人可能馬上會跳出來,把本節的大部分內容歸於“草率的優化”(xing:參見[The Root of All Evil]),不可否認微優化(micro-optimization。xing:代碼優化,相對於結構優化)的確會帶來很多問題,諸如無法使用更有效的數據結構和算法。但是在手持設備上,你別無選擇。假如你認為Android虛擬機的性能與台式機相當,你的程序很有可能一開始就占用了系統的全部內存(xing:內存很小),這會讓你的程序慢得像蝸牛一樣,更遑論做其他的操作了。

Android的成功依賴於你的程序提供的用戶體驗。而這種用戶體驗,部分依賴於你的程序是響應快速而靈活的,還是響應緩慢而僵化的。因為所有的程序都運行在同一個設備之上,都在一起,這就如果在同一條路上行駛的汽車。而這篇文檔就相當於你在取得駕照之前必須要學習的交通規則。如果大家都按照這些規則去做,駕駛就會很順暢,但是如果你不這樣做,你可能會車毀人亡。這就是為什麼這些原則十分重要。

當我們開門見山、直擊主題之前,還必須要提醒大家一點:不管VM是否支持實時(JIT)編譯器(xing:它允許實時地將Java解釋型程序自動編譯成本機機器語言,以使程序執行的速度更快。有些JVM包含JIT編譯器。),下面提到的這些原則都是成立的。假如我們有目標完全相同的兩個方法,在解釋執行時foo()比bar()快,那麼編譯之後,foo()依然會比bar()快。所以不要寄希望於編譯器可以拯救你的程序。

避免建立對象

世界上沒有免費的對象。雖然GC為每個線程都建立了臨時對象池,可以使創建對象的代價變得小一些,但是分配內存永遠都比不分配內存的代價大。

如果你在用戶界面循環中分配對象內存,就會引發周期性的垃圾回收,用戶就會覺得界面像打嗝一樣一頓一頓的。

所以,除非必要,應盡量避免盡力對象的實例。下面的例子將幫助你理解這條原則:

當你從用戶輸入的數據中截取一段字符串時,盡量使用substring函數取得原始數據的一個子串,而不是為子串另外建立一份拷貝。這樣你就有一個新的String對象,它與原始數據共享一個char數組。
如果你有一個函數返回一個String對象,而你確切的知道這個字符串會被附加到一個StringBuffer,那麼,請改變這個函數的參數和實現方式,直接把結果附加到StringBuffer中,而不要再建立一個短命的臨時對象。
一個更極端的例子是,把多維數組分成多個一維數組。

int數組比Integer數組好,這也概括了一個基本事實,兩個平行的int數組比(int,int)對象數組性能要好很多。同理,這試用於所有基本類型的組合。
如果你想用一種容器存儲(Foo,Bar)元組,嘗試使用兩個單獨的Foo[]數組和Bar[]數組,一定比(Foo,Bar)數組效率更高。(也有例外的情況,就是當你建立一個API,讓別人調用它的時候。這時候你要注重對API借口的設計而犧牲一點兒速度。當然在API的內部,你仍要盡可能的提高代碼的效率)

總體來說,就是避免創建短命的臨時對象。減少對象的創建就能減少垃圾收集,進而減少對用戶體驗的影響。

使用本地方法

當你在處理字串的時候,不要吝惜使用String.indexOf(), String.lastIndexOf()等特殊實現的方法(specialty methods)。這些方法都是使用C/C 實現的,比起Java循環快10到100倍。

使用實類比接口好

假設你有一個HashMap對象,你可以將它聲明為HashMap或者Map:

Map myMap1 = new HashMap();
HashMap myMap2 = new HashMap();
哪個更好呢?

按照傳統的觀點Map會更好些,因為這樣你可以改變他的具體實現類,只要這個類繼承自Map接口。傳統的觀點對於傳統的程序是正確的,但是它並不適合嵌入式系統。調用一個接口的引用會比調用實體類的引用多花費一倍的時間。

如果HashMap完全適合你的程序,那麼使用Map就沒有什麼價值。如果有些地方你不能確定,先避免使用Map,剩下的交給IDE提供的重構功能好了。(當然公共API是一個例外:一個好的API常常會犧牲一些性能)

用靜態方法比虛方法好

如果你不需要訪問一個對象的成員變量,那麼請把方法聲明成static。虛方法執行的更快,因為它可以被直接調用而不需要一個虛函數表。另外你也可以通過聲明體現出這個函數的調用不會改變對象的狀態。

不用getter和setter

在很多本地語言如C 中,都會使用getter(比如:i = getCount())來避免直接訪問成員變量(i = mCount)。在C 中這是一個非常好的習慣,因為編譯器能夠內聯訪問,如果你需要約束或調試變量,你可以在任何時候添加代碼。

在Android上,這就不是個好主意了。虛方法的開銷比直接訪問成員變量大得多。在通用的接口定義中,可以依照OO的方式定義getters和setters,但是在一般的類中,你應該直接訪問變量。

將成員變量緩存到本地

訪問成員變量比訪問本地變量慢得多,下面一段代碼:

Java代碼 

1 for (int i = 0; i < this.mCount; i )   

2     dumpItem(this.mItems[i]);  


最好改成這樣:

Java代碼 

3 int count = this.mCount;   

4 Item[] items = this.mItems;   

5 for (int i = 0; i < count; i )   

6     dumpItems(items[i]);  


(使用"this"是為了表明這些是成員變量)

另一個相似的原則是:永遠不要在for的第二個條件中調用任何方法。如下面方法所示,在每次循環的時候都會調用getCount()方法,這樣做比你在一個int先把結果保存起來開銷大很多。

Java代碼 

7 for (int i = 0; i < this.getCount(); i )   

8     dumpItems(this.getItem(i));  


同樣如果你要多次訪問一個變量,也最好先為它建立一個本地變量,例如:

Java代碼 

9 protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) {   

10     if (isHorizontalScrollBarEnabled()) {   

11         int size = mScrollBar.getSize(false);   

12         if (size <= 0) {   

13             size = mScrollBarSize;   

14         }   

15         mScrollBar.setBounds(0, height - size, width, height);   

16         mScrollBar.setParams(computeHorizontalScrollRange(),computeHorizontalScrollOffset(),computeHorizontalScrollExtent(), false);   

17         mScrollBar.draw(canvas);   

18     }   

19 }  



這裡有4次訪問成員變量mScrollBar,如果將它緩存到本地,4次成員變量訪問就會變成4次效率更高的棧變量訪問。

另外就是方法的參數與本地變量的效率相同。

使用常量

讓我們來看看這兩段在類前面的聲明:

Java代碼 

20 static int intVal = 42;   

21 static String strVal = "Hello, world!";  


必以其會生成一個叫做<clinit>的初始化類的方法,當類第一次被使用的時候這個方法會被執行。方法會將42賦給intVal,然後把一個指向類中常量表的引用賦給strVal。當以後要用到這些值的時候,會在成員變量表中查找到他們。

下面我們做些改進,使用“final"關鍵字:

Java代碼 

22 static final int intVal = 42;   

23 static final String strVal = "Hello, world!";  


現在,類不再需要<clinit>方法,因為在成員變量初始化的時候,會將常量直接保存到類文件中。用到intVal的代碼被直接替換成42,而使用strVal的會指向一個字符串常量,而不是使用成員變量。

將一個方法或類聲明為"final"不會帶來性能的提升,但是會幫助編譯器優化代碼。舉例說,如果編譯器知道一個"getter"方法不會被重載,那麼編譯器會對其采用內聯調用。

你也可以將本地變量聲明為"final",同樣,這也不會帶來性能的提升。使用"final"只能使本地變量看起來更清晰些(但是也有些時候這是必須的,比如在使用匿名內部類的時候)(xing:原文是 or you have to, e.g. for use in an anonymous inner class)

謹慎使用foreach

foreach 可以用在實現了Iterable接口的集合類型上。foreach會給這些對象分配一個iterator,然後調用 hasNext()和next()方法。你最好使用foreach處理ArrayList對象,但是對其他集合對象,foreach相當於使用 iterator。

下面展示了foreach一種可接受的用法:

Java代碼 

24 public class Foo {   

25     int mSplat;   

26     static Foo mArray[] = new Foo[27];    

27   

28     public static void zero() {   

29         int sum = 0;   

30         for (int i = 0; i < mArray.length; i ) {   

31             sum  = mArray[i].mSplat;   

32         }   

33     }   

34   

35     public static void one() {   

36         int sum = 0;   

37         Foo[] localArray = mArray;   

38         int len = localArray.length;   

39         for (int i = 0; i < len; i ) {   

40         sum  = localArray[i].mSplat;   

41         }   

42     }    

43   

44     public static void two() {   

45         int sum = 0;   

46         for (Foo a: mArray) {   

47             sum  = a.mSplat;   

48         }   

49     }   

50 }  



在zero()中,每次循環都會訪問兩次靜態成員變量,取得一次數組的長度。
retrieves the static field twice and gets the array length once for every iteration through the loop.

在one()中,將所有成員變量存儲到本地變量。
pulls everything out into local variables, avoiding the lookups.

two() 使用了在java1.5中引入的foreach語法。編譯器會將對數組的引用和數組的長度保存到本地變量中,這對訪問數組元素非常好。但是編譯器還會在每次循環中產生一個額外的對本地變量的存儲操作(對變量a的存取)這樣會比one()多出4個字節,速度要稍微慢一些。

綜上所述:foreach語法在運用於array時性能很好,但是運用於其他集合對象時要小心,因為它會產生額外的對象。

避免使用枚舉

枚舉變量非常方便,但不幸的是它會犧牲執行的速度和並大幅增加文件體積。例如:

public class Foo {public enum Shrubbery { GROUND, CRAWLING, HANGING }}

會產生一個900字節的.class文件(Foo$Shubbery.class)。在它被首次調用時,這個類會調用初始化方法來准備每個枚舉變量。每個枚舉項都會被聲明成一個靜態變量,並被賦值。然後將這些靜態變量放在一個名為"$VALUES"的靜態數組變量中。而這麼一大堆代碼,僅僅是為了使用三個整數。

這樣:

Shrubbery shrub = Shrubbery.GROUND;會引起一個對靜態變量的引用,如果這個靜態變量是final int,那麼編譯器會直接內聯這個常數。

一方面說,使用枚舉變量可以讓你的API更出色,並能提供編譯時的檢查。所以在通常的時候你毫無疑問應該為公共API選擇枚舉變量。但是當性能方面有所限制的時候,你就應該避免這種做法了。

有些情況下,使用ordinal()方法獲取枚舉變量的整數值會更好一些,舉例來說,將:

Java代碼 

51 for (int n = 0; n < list.size(); n ) {   

52     if (list.items[n].e == MyEnum.VAL_X)// do stuff 1  

53     else if (list.items[n].e == MyEnum.VAL_Y)// do stuff 2  

54 }  



替換為:

Java代碼 

55 int valX = MyEnum.VAL_X.ordinal();   

56 int valY = MyEnum.VAL_Y.ordinal();   

57 int count = list.size();   

58 MyItem items = list.items();   

59 for (int n = 0; n < count; n ) {   

60     int valItem = items[n].e.ordinal();   

61     if (valItem == valX)// do stuff 1  

62     else if (valItem == valY)// do stuff 2  

63 }  



會使性能得到一些改善,但這並不是最終的解決之道。

將與內部類一同使用的變量聲明在包范圍內

請看下面的類定義:

Java代碼 

64 public class Foo {   

65     private int mValue;    

66     public void run() {   

67         Inner in = new Inner();   

68         mValue = 27;   

69         in.stuff();   

70     }   

71   

72     private void doStuff(int value) {   

73         System.out.println("Value is "   value);   

74     }   

75   

76     private class Inner {   

77         void stuff() {   

78             Foo.this.doStuff(Foo.this.mValue);   

79         }   

80     }   

81 }  



這其中的關鍵是,我們定義了一個內部類(Foo$Inner),它需要訪問外部類的私有域變量和函數。這是合法的,並且會打印出我們希望的結果"Value is 27"。

問題是在技術上來講(在幕後)Foo$Inner是一個完全獨立的類,它要直接訪問Foo的私有成員是非法的。要跨越這個鴻溝,編譯器需要生成一組方法:

Java代碼 

82 static int Foo.access$100(Foo foo) {   

83     return foo.mValue;   

84 }   

85   

86 static void Foo.access$200(Foo foo, int value) {   

87     foo.doStuff(value);   

88 }  



內部類在每次訪問"mValue"和"doStuff"方法時,都會調用這些靜態方法。就是說,上面的代碼說明了一個問題,你是在通過接口方法訪問這些成員變量和函數而不是直接調用它們。在前面我們已經說過,使用接口方法(getter、setter)比直接訪問速度要慢。所以這個例子就是在特定語法下面產生的一個“隱性的”性能障礙。

通過將內部類訪問的變量和函數聲明由私有范圍改為包范圍,我們可以避免這個問題。這樣做可以讓代碼運行更快,並且避免產生額外的靜態方法。(遺憾的是,這些域和方法可以被同一個包內的其他類直接訪問,這與經典的 OO原則相違背。因此當你設計公共API的時候應該謹慎使用這條優化原則)

避免使用浮點數

在奔騰CPU出現之前,游戲設計者做得最多的就是整數運算。隨著奔騰的到來,浮點運算處理器成為了CPU內置的特性,浮點和整數配合使用,能夠讓你的游戲運行得更順暢。通常在桌面電腦上,你可以隨意的使用浮點運算。

但是非常遺憾,嵌入式處理器通常沒有支持浮點運算的硬件,所有對"float"和"double"的運算都是通過軟件實現的。一些基本的浮點運算,甚至需要毫秒級的時間才能完成。

甚至是整數,一些芯片有對乘法的硬件支持而缺少對除法的支持。這種情況下,整數的除法和取模運算也是有軟件來完成的。所以當你在使用哈希表或者做大量數學運算時一定要小心謹慎。 ”

 

五,學會至少一門服務器端開發技術

可能有朋友會問:學習Android應用程序開發為什麼還需要學習學會至少一門服務器端開發技術呢?答案如下:一方面 Android號稱是首個為移動終端打造的真正開放和完整的移動軟件。作為一種移動終端,必須與服務器端結合才能發揮巨大的作用。簡言之,需要:雲端 雲的方式。Android是為移動互聯網時代量身打造的,移動互聯網時代的服務模式是“手機終端 互聯網絡 應用軟件”,移動互聯網時代應用技術之一的 Android只是用於開發移動終端軟件,而服務端技術用於開發互聯網絡應用,所以未來移動互聯網時代軟件的主流應用模式將是“手機客戶端 互聯網絡應用服務端”,這種模式要求做移動互聯網開發的程序員不但要掌握像Android這樣的手機終端軟件技術還要掌握開發互聯網絡應用的服務器端技術。目前,軟件企業普遍存在這樣的問題,做移動互聯網開發Android終端軟件的程序員不了解web應用技術,而做web應用的程序員不了解移動終端技術,這樣就導致了客戶端與服務端在銜接上出現了問題。目前的現狀是:既掌握移動互聯網Android終端技術,又掌握web應用技術的程序員比較稀缺,隨著中國步入移動互聯網時代,企業對這種移動互聯網時代綜合性人才的需求很旺盛。如果不了解web應用技術,最終會遇到了技術和發展的瓶頸;另一方面,Google聯合 OHA推出的真正優勢之一也在於和和互聯網結合,Google的用意之一也是想開辟新的終端去使用Google的優勢服務。

服務器端開發技術目前主流的有Sun的Java EE、微軟的.NET,開源的以PHP和MySQL為代表的LAMP體系,我們該選擇哪一種呢?從理論上講,很多人傾向於選擇Java EE,畢竟它們都是使用Java作為開發語言的,但是很多人面對Java EE眾多的框架就望而生畏,其實在學習Java EE的時候可以從Struts入手,隨著業務的需求逐步深入。當然,選擇微軟的.NET也行,畢竟該技術體系也占有很大 市場份額。其實,筆者認為,選擇LAMP可以是會獲得最高的“性價比”的,一方面PHP是現在Web方面的主流語言,大多數新型的網站尤其是創業性質的網站一般都會選用PHP作為服務端開發語言,另一方面,前面也說過,Android是為移動互聯而生的,兩者達到了完美的契合。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved