導航:首頁 > 操作系統 > androidworkthread

androidworkthread

發布時間:2024-07-17 05:36:21

Ⅰ 針對android的性能優化集中哪些方面

一、概要:

本文主要以Android的渲染機制、UI優化、多線程的處理、緩存處理、電量優化以及代碼規范等幾方面來簡述Android的性能優化

二、渲染機制的優化:

大多數用戶感知到的卡頓等性能問題的最主要根源都是因為渲染性能。

Android系統每隔16ms發出VSYNC信號,觸發對UI進行渲染, 如果每次渲染都成功,這樣就能夠達到流暢的畫面所需要的60fps,為了能夠實現60fps,這意味著程序的大多數操作都必須在16ms內完成。

*關於JobScheler的更多知識可以參考http://hukai.me/android-training-course-in-chinese/background-jobs/scheling/index.html

七、代碼規范

1)for loop中不要聲明臨時變數,不到萬不得已不要在裡面寫try catch。

2)明白垃圾回收機制,避免頻繁GC,內存泄漏,OOM(有機會專門說)

3)合理使用數據類型,StringBuilder代替String,少用枚舉enum,少用父類聲明(List,Map)

4)如果你有頻繁的new線程,那最好通過線程池去execute它們,減少線程創建開銷。

5)你要知道單例的好處,並正確的使用它。

6)多用常量,少用顯式的"action_key",並維護一個常量類,別重復聲明這些常量。

7)如果可以,至少要弄懂設計模式中的策略模式,組合模式,裝飾模式,工廠模式,觀察者模式,這些能幫助你合理的解耦,即使需求頻繁變更,你也不用害怕牽一發而動全身。需求變更不可怕,可怕的是沒有在寫代碼之前做合理的設計。

8)View中設置緩存屬性.setDrawingCache為true.

9)cursor的使用。不過要注意管理好cursor,不要每次打開關閉cursor.因為打開關閉Cursor非常耗時。Cursor.require用於刷cursor.

10)採用SurfaceView在子線程刷新UI,避免手勢的處理和繪制在同一UI線程(普通View都這樣做)

11)採用JNI,將耗時間的處理放到c/c++層來處理

12)有些能用文件操作的,盡量採用文件操作,文件操作的速度比資料庫的操作要快10倍左右

13)懶載入和緩存機制。訪問網路的耗時操作啟動一個新線程來做,而不要再UI線程來做

14)如果方法用不到成員變數,可以把方法申明為static,性能會提高到15%到20%

15)避免使用getter/setter存取field,可以把field申明為public,直接訪問

16)私有內部類要訪問外部類的field或方法時,其成員變數不要用private,因為在編譯時會生成setter/getter,影響性能。可以把外部類的field或方法聲明為包訪問許可權

17)合理利用浮點數,浮點數比整型慢兩倍

18)針對ListView的性能優化,ListView的背景色與cacheColorHint設置相同顏色,可以提高滑動時的渲染性能。ListView中getView是性能是關鍵,這里要盡可能的優化。

getView方法中要重用view;getView方法中不能做復雜的邏輯計算,特別是資料庫操作,否則會嚴重影響滑動時的性能

19)不用new關鍵詞創建類的實例,用new關鍵詞創建類的實例時,構造函數鏈中的所有構造函數都會被自動調用。但如果一個對象實現了Cloneable介面,我們可以調用它的clone()方法。

clone()方法不會調用任何類構造函數。在使用設計模式(Design Pattern)的場合,如果用Factory模式創建對象,則改用clone()方法創建新的對象實例非常簡單。例如,下面是Factory模式的一個典型實現:

20)public static Credit getNewCredit() {
return new Credit();
}
改進後的代碼使用clone()方法,如下所示:
private static Credit BaseCredit = new Credit();
public static Credit getNewCredit() {
return (Credit) BaseCredit.clone();
}
上面的思路對於數組處理同樣很有用。

21)乘法和除法

考慮下面的代碼:

  • for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }
    用移位操作替代乘法操作可以極大地提高性能。下面是修改後的代碼:
    for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }

  • 22)ViewPager同時緩存page數最好為最小值3,如果過多,那麼第一次顯示時,ViewPager所初始化的pager就會很多,這樣pager累積渲染耗時就會增多,看起來就卡。

    23)每個pager應該只在顯示時才載入網路或資料庫(UserVisibleHint=true),最好不要預載入數據,以免造成浪費

    24)提高下載速度:要控制好同時下載的最大任務數,同時給InputStream再包一層緩沖流會更快(如BufferedInputStream)

    25)提供載入速度:讓服務端提供不同解析度的圖片才是最好的解決方案。還有合理使用內存緩存,使用開源的框架

    引用:Android性能優化的淺談

    Ⅱ Framework事件機制——手撕Android事件處理的三種方法

    Android的事件處理的三種方法:

    setOnClickListener,setOnLongClickListener、setOnTouchListener

    注意:如果onTouchEvent方法return true,則單擊事件和長摁事件不再執行;若onLongClick方法返回true,則單擊事件不再處理。

    需要定義繼承組件的類,重寫回調方法Touch方法執行時,先被Activity捕獲,DispatchTouchEvent方法處理。return false,交給上層的onTouchEvent方法處理;return super.dispatchTouchEvent(ev),則傳遞給最外層的View。

    View用Dispatch方法處理,return false,由上層的onTouchEvent方法處理。如果返回super.dispatchTouchEvent(ev),則本層的onInterceptTouchEvent攔截,如果攔截true,則攔截,false不攔截,傳遞給子View的DispatchTouchEvent處理。

    常用的回調方法:onKeyDown,onKeyLongPress,onKeyUp,onTouchEvent,onTrackballEvent(軌跡球事件)監聽和回調同時存在時,先調用監聽。

    流程模型圖:

    Event source 事件源
    Event 事件
    Event Listener 事件監聽器
    下面我們來看一下點擊事件和觸摸事件的監聽三要素具體是那部分:

    由於點擊事件比較簡單,系統已經幫我們處理了,並沒有找到具體事件是哪個。

    View.OnClickListener 單擊事件監聽器必須實現的接⼝
    View.OnCreateContextMenuListener 創建上下⽂菜單事件
    View.OnFocusChangeListener 焦點改變事件
    View.OnKeyListener 按鍵事件監聽器
    View.OnLongClickListener 長按事件監聽器
    View.OnTouchListener 觸摸屏事件監聽器

    ⾸先,事件監聽機制中由事件源,事件,事件監聽器三類對象組成。
    事件監聽器處理流程:

    在此以OnClickListener單擊事件為例使用intent來實現頁面的跳轉

    監聽事件處理是事件源與事件監聽器分開的而基於回調的事件處理UI組件不但是事件源,而且還是事件監聽器,通過組件的相關回調方法處理對應的事件。

    Ⅰ. 自定義View類,繼承自需要的View UI類。ex :自定義 MyButton按鈕類 extends 基礎Button類

    Ⅱ. 復寫回調函數。ex:public boolean onTouchEvent(MotionEvent event)

    每一個事件回調方法都會返回一個boolean值,①.如果返回true:表示該事件已被處理,不再繼續向外擴散,②.如果返回false:表示事件繼續向外擴散

    而說到基於回調就離不開監聽機制

    幾乎所有基於回調的事件處理方法都有一個boolean類型的返回值,該返回值用於表示該處理方法是否能完全處理該事件。
    如果處理事件的回調方法返回true,表明該處理方法已經完全處理改事件,該事件不會傳播出去。
    如果處理事件的回調方法返回false,表明該處理方法並未完全處理該事件,該事件會傳播出去。
    對於基於回調的時間傳播而言,某組件上所發生的事件不僅會激發該組件上的回調方法,也會觸發該組件所在Activity的回調方法——只要事件能傳播到該Activity。

    這里是在模擬器里進行的測試,這里按下鍵盤(而不是點擊),會看到 logcat 中的輸出,如下:

    View類實現了KeyEvent.Callback介面中的一系列回調函數,因此,基於回調的事件處理機制通過自定義View來實現,自定義View時重寫這些事件處理方法即可。

    Handler是一個消息分發對象。

    Handler是Android系統提供的一套用來更新UI的機制,也是一套消息處理機制,可以通過Handler發消息,也可以通過Handler處理消息。

    在下面介紹Handler機制前,首先得了解以下幾個概念:

    在子線程執行完耗時操作,當Handler發送消息時,將會調用 MessageQueue.enqueueMessage ,向消息隊列中添加消息。 當通過 Looper.loop 開啟循環後,會不斷地從消息池中讀取消息,即調用 MessageQueue.next , 然後調用目標Handler(即發送該消息的Handler)的 dispatchMessage 方法傳遞消息, 然後返回到Handler所在線程,目標Handler收到消息,調用 handleMessage 方法,接收消息,處理消息。

    從上面可以看出,在子線程中創建Handler之前,要調用 Looper.prepare() 方法,Handler創建後,還要調用 Looper.loop() 方法。而前面我們在主線程創建Handler卻不要這兩個步驟,因為系統幫我們做了。

    初始化Looper

    從上可以看出,不能重復創建Looper,每個線程只能創建一個。創建Looper,並保存在 ThreadLocal 。其中ThreadLocal是線程本地存儲區(Thread Local Storage,簡稱TLS),每個線程都有自己的私有的本地存儲區域,不同線程之間彼此不能訪問對方的TLS區域。

    開啟Looper

    發送消息

    post方法:

    send方法:

    在子線程中,進行耗時操作,執行完操作後,發送消息,通知主線程更新UI。

    本文講解了三個方面;Android事件機制;基於監聽、基於回調以及Handler消息處理。還有許多沒有講解到的知識點,我總結在了整理的一套Android進階筆記裡面;需要學習進階的同學可以前往獲取: Frame Work源碼解析手冊 、 Android核心技術進階手冊、實戰筆記、面試題綱資料

    Ⅲ android 7.0對開發者會有哪些影響

    Android N 除了提供諸多新特性和功能外,還對系統和 API 行為做出了各種變更。 本文重點介紹您應該了解並在開發應用時加以考慮的一些重要變更。

    如果您之前發布過 Android 應用,請注意您的應用可能受到這些平台變更的影響。

    電池和內存

    Android N 包括旨在延長設備電池壽命和減少 RAM 使用的系統行為變更。 這些變更可能會影響您的應用訪問系統資源,以及您的系統通過特定隱式 Intent 與其他應用互動的方式。

    低電耗模式

    Android 6.0(API 級別
    23)引入了低電耗模式,當用戶設備未插接電源、處於靜止狀態且屏幕關閉時,該模式會推遲 CPU 和網路活動,從而延長電池壽命。而 Android N
    則通過在設備未插接電源且屏幕關閉狀態下、但不一定要處於靜止狀態(例如用戶外出時把手持式設備裝在口袋裡)時應用部分 CPU
    和網路限制,進一步增強了低電耗模式。

    圖 1. 低電耗模式如何辯蠢應用第一級系統活動限制以延攜畢陪長電池壽命的圖示。

    當設備處於充電狀態且屏幕已關閉一定時間後,設備會進入低電耗模式並應用第一部分限制: 關閉應用網路訪問、推遲作業和同步。 如果進入低電耗模式後設備處於靜止狀態達到一定時間,系統則會對 PowerManager.WakeLock、AlarmManager 鬧鈴、GPS
    和 Wi-Fi 掃描應用餘下的低電耗模式限制。 無論是應用部分還是全部低電耗模式限制,系統都會喚醒設備以提供簡短的維護時間窗口,在此窗口期間,應用程序可以訪問網路並執行任何被推遲的作業/同步。

    圖 2. 低電耗模式如何在設備處於靜止狀態達到一定時間後應用第二級系統活動限制的圖示。

    請注意,激活屏幕或插接設備電源時,系統將退出低電耗模式並取消這些處理限制。 此項新增的行為不會影響有關使您的應用適應 Android 6.0(API 級別 23)中所推出的舊版本低電耗模式的建議和最佳實踐,如低電耗模式和應用待機模式優化中所討論。
    您仍應遵循這些建議(例如使用 Google Cloud Messaging (GCM) 發送和接收消息)並開始安排更新計劃以適應新增的低電耗模式行為。

    Project Svelte:後台優化

    Android N 刪除了三項隱式廣播,以幫助優化內存使用和電量消耗。 此項變更很有必要,因為隱式廣播會在後台頻繁啟動已注冊偵聽這些廣播的應用。 刪除這些廣播可以顯著提升設備性能和用戶體驗。

    移動設備會經歷頻繁的連接變更,例如在 Wi-Fi 和移動數據之間切換時。 目前,可以通過在應用清單中注冊一個接收器來偵聽隱式 CONNECTIVITY_ACTION廣播,讓應用能夠監控這些變更。
    由於很多應用會注冊接收此廣播,因此單次網路切換即會導致所有應用被喚醒並同時處理此廣播。

    同理,應用可以注冊接收來自數碰其他應用(例如相機)的隱式 ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO 廣播。
    當用戶使用相機應用拍攝照片時,這些應用即會被喚醒以處理廣播。

    為緩解這些問題,Android N 應用了以下優化措施:

    面向 Android N 開發的應用不會收到 CONNECTIVITY_ACTION 廣播,即使它們已有清單條目來請求接受這些事件的通知。
    在前台運行的應用如果使用BroadcastReceiver 請求接收通知,則仍可以在主線程中偵聽 CONNECTIVITY_CHANGE。
    應用無法發送或接收 ACTION_NEW_PICTURE 或 ACTION_NEW_VIDEO 廣播。此項優化會影響所有應用,而不僅僅是面向
    Android N 的應用。

    如果您的應用使用任何 Intent,您仍需要盡快移除它們的依賴關系,以正確適配 Android N 設備。 Android 框架提供多個解決方案來緩解對這些隱式廣播的需求。 例如,JobScheler API
    提供了一個穩健可靠的機制來安排滿足指定條件(例如連入無限流量網路)時所執行的網路操作。 您甚至可以使用JobScheler 來適應內容提供程序變化。

    如需了解有關 Android N 中後台優化以及如何改寫應用的詳細信息,請參閱後台優化。

    許可權更改

    Android N 做了一些許可權更改,這些更改可能會影響您的應用。

    系統許可權更改

    為了提高私有文件的安全性,面向 Android N 或更高版本的應用私有目錄被限制訪問(0700)。 此設置可防止私有文件的元數據泄漏,如它們的大小或存在。 此許可權更改有多重副作用:

    私有文件的文件許可權不應再由所有者放寬,為使用 MODE_WORLD_READABLE 和/或 MODE_WORLD_WRITEABLE 而進行的此類嘗試將觸發SecurityException。
    註:迄今為止,這種限制尚不能完全執行。 應用仍可能使用原生 API 或 File API 來修改它們的私有目錄許可權。 但是,我們強烈反對放寬私有目錄的許可權。

    傳遞軟體包網域外的 file:// URI 可能給接收器留下無法訪問的路徑。 因此,嘗試傳遞 file:// URI 會觸發 FileUriExposedException。 分享私有文件內容的推薦方法是使用 FileProvider。
    DownloadManager 不再按文件名分享私人存儲的文件。
    舊版應用在訪問 COLUMN_LOCAL_FILENAME 時可能出現無法訪問的路徑。
    面向 Android N 或更高版本的應用在嘗試訪問 COLUMN_LOCAL_FILENAME 時會觸發 SecurityException。
    通過使用DownloadManager.Request.() 或 DownloadManager.Request.() 將下載位置設置為公共位置的舊版應用仍可以訪問 COLUMN_LOCAL_FILENAME 中的路徑,但是我們強烈反對使用這種方法。
    訪問由 DownloadManager 公開的文件的首選方式是使用 ContentResolver.openFileDescriptor()。

    應用間共享文件

    對於面向 Android N 的應用,Android 框架執行的 StrictMode API
    政策禁止向您的應用外公開 file:// URI。 如果一項包含文件 URI 的 Intent 離開您的應用,應用失敗,並出現 FileUriExposedException 異常。

    若要在應用間共享文件,您應發送一項 content:// URI,並授予 URI 臨時訪問許可權。 進行此授權的最簡單方式是使用 FileProvider 類。
    如需有關許可權和共享文件的更多信息,請參閱共享文件。

    無障礙改進

    為提高平台對於視力不佳或視力受損用戶的可用性,Android N 做出了一些更改。這些更改一般並不要求更改您的應用代碼,不過您應仔細檢查並使用您的應用測試這些功能,以評估它們對用戶體驗的潛在影響。

    屏幕縮放

    Android N 支持用戶設置顯示尺寸,以放大或縮小屏幕上的所有元素,從而提升設備對視力不佳用戶的可訪問性。用戶無法將屏幕縮放至低於最小屏幕寬度 sw320dp,該寬度是
    Nexus 4 的寬度,也是常規中等大小手機的寬度。

    圖 3. 右側屏幕顯示的是一台運行 Android N 系統映像的設備增大顯示尺寸後的效果。

    當設備密度發生更改時,系統會以如下方式通知正在運行的應用:

    如果是面向 API 級別 23 或更低版本系統的應用,系統會自動終止其所有後台進程。 這意味著如果用戶切換離開此類應用,轉而打開「Settings」屏幕並更改 Display size 設置,則系統會像處理內存不足的情況一樣終止該應用。 如果應用具有任何前台進程,則系統會如處理運行時變更中所述將配置變更通知給這些進程,就像對待設備屏幕方向變更一樣。
    如果是面向 Android N 的應用,則其所有進程(前台和後台)都會收到有關配置變更的通知,如處理運行時變更中所述。

    大多數應用並不需要進行任何更改即可支持此功能,不過前提是這些應用遵循 Android 最佳實踐。具體要檢查的事項:

    在屏幕寬度為 sw320dp 的設備上測試您的應用,並確保其充分運行。
    當設備配置發生變更時,更新任何與密度相關的緩存信息,例如緩存點陣圖或從網路載入的資源。當應用從暫停狀態恢復運行時,檢查配置變更。
    註:如果您要緩存與配置相關的數據,則最好也包括相關元數據,例如該數據對應的屏幕尺寸或像素密度。 保存這些元數據便於您在配置變更後決定是否需要刷新緩存數據。

    避免用像素單位指定尺寸,因為像素不會隨屏幕密度縮放。應改為使用與密度無關像素 (dp)
    單位指定尺寸。

    設置向導中的視覺設置

    Android N 在「Welcome」屏幕中加入了「Vision Settings」,用戶可以在新設備上設置以下無障礙功能設置: Magnification gesture、Font size、Display size 和 TalkBack。 此項變更增強了與不同屏幕設置相關的錯誤的可見性。
    要評估此功能的影響,您應在啟用這些設置的狀態下測試應用。 您可以在Settings > Accessibility 中找到這些設置。

    NDK 應用鏈接至平台庫

    Android N 做了一些命名空間更改,以阻止載入非公開 API。 如果您使用 NDK,則只能使用 Android 平台提供的公開 API。 在下一個官方發布的 Android 版本上使用非公開 API 會導致應用崩潰。

    為提醒您使用了非公開 API,在 Android N
    設備上運行的應用會在有應用調用非公開 API 時在日誌消息輸出中生成一個錯誤。
    此錯誤還會作為消息顯示在設備屏幕上,以幫助增強您對此情況的認識。 您應檢查應用代碼以刪除使用非公開平台
    API,並使用預覽版設備或模擬器全面測試應用。

    如果您的應用依賴平台庫,則請參見 NDK 文檔,了解使用公開 API 等效項替換普通私有 API 的典型修復。 您還可以鏈接至平台庫,而無需實現此應用,如果應用使用的庫是平台的一部分(例如 libpng),但不屬於 NDK,則更可如此。 此情況下,請確保您的 APK 包含您打算鏈接到的所有 .so 文件。

    注意:有些第三方庫可能會鏈接至非公開 API。 如果您的應用使用這些庫,那麼當您的應用在下一個官方發布的 Android 版本上運行時可能會出現崩潰現象。

    應用不應依賴或使用不屬於 NDK
    的原生庫,因為這些庫可能會發生更改或從一個 Android 版本遷移至另一版本。 例如,從 OpenSSL 切換至 BoringSSL
    即屬於此類更改。 此外,不同的設備可能提供不同級別的兼容性,因為不屬於 NDK 中的平台庫沒有兼容性要求。 如果您必須在較舊設備上訪問非 NDK
    庫,則請依據 Android API 級別進行載入。

    為幫助您診斷此類問題,下面列舉了一些在您試圖使用 Android N 開發應用時可能遇到的 java 和 NDK 錯誤:

    Java 錯誤示例:
    java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libcutils.so"
    is not accessible for the namespace "classloader-namespace"

    NDK 錯誤示例:
    dlopen failed: cannot locate symbol "__system_property_get" referenced by ...

    以下是遇到這類錯誤的應用的一些典型修復:

    可以使用標准 JNI 函數來替代使用 libandroid_runtime.so 中的 getJavaVM 和 getJNIEnv:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.

    可以使用公開 alternative __system_property_get 來替代使用 libcutils.so 中的 property_get 符號。如需這樣做,請使用__system_property_get 及以下 include 函數:
    #include <sys/system_properties.h>

    應使用應用本地版本來替代使用 libcrypto.so 中的 SSL_ctrl 符號。例如,您應在 .so 文件中靜態鏈接 libcyrpto.a,或者在應用中包含您自己的來自 BoringSSL 或 OpenSSL 的動態 libcrypto.so。

    Android for Work

    Android N 包含一些針對面向 Android
    for Work 的應用的變更,包括對證書安裝、密碼重置、二級用戶管理、設備標識符訪問許可權的變更。如果您是要針對 Android for
    Work 環境開發應用,則應仔細檢查這些變更並相應地修改您的應用。

    您必須先安裝授權證書安裝程序,然後 DPC 才能對其進行設置。 對於面向 N SDK 的個人資料和設備所有者應用,您應在設備策略控制器 (DPC) 調用DevicePolicyManager.setCertInstallerPackage() 之前安裝授權證書安裝程序。 如果尚未安裝此安裝程序,則系統會引發IllegalArgumentException。
    針對設備管理員的重置密碼限制現在也適用於個人資料所有者。 設備管理員無法再使用 DevicePolicyManager.resetPassword() 來清除或更改已經設置的密碼。 設備管理員仍可以設置密碼,但只能在設備沒有密碼、PIN 或圖案時這樣做。
    即使設置了限制,設備所有者和個人資料所有者仍可以管理帳戶。而且,即使具有 DISALLOW_MODIFY_ACCOUNTS 用戶限制,設備所有者和個人資料所有者仍可調用 Account Management API。
    設備所有者可以更輕松地管理二級用戶。當設備在設備所有者模式下運行時,系統將自動設置 DISALLOW_ADD_USER 限制。 這樣可以防止用戶創建非託管二級用戶。 此外,CreateUser() 和 createAndInitializeUser() 方法已棄用,取而代之的是 DevicePolicyManager.createAndManageUser() 方法。
    設備所有者可以訪問設備標識符。設備所有者可以使用 DevicePolicyManagewr.getWifiMacAddress() 訪問設備的 Wi-Fi MAC 地址。 如果設備上從未啟用 Wi-Fi,則此方法將返回一個 null 值。
    工作模式設置控制工作應用訪問。當工作模式關閉時,系統啟動器通過使工作應用顯示為灰色來指示它們不可用。 啟用工作模式會再次恢復正常行為。

    如需了解有關 Android N 中針對 Android for Work 所做變更的詳細信息,請參閱 Android for
    Work 更新。

    註解保留

    Android N 在註解可見性被忽略時修復錯誤。這種問題將啟用本不應被允許的運行時訪問註解。 這些註解包括:

    VISIBILITY_BUILD:僅應編譯時可見。
    VISIBILITY_SYSTEM:運行時應可見,但僅限基本系統。

    如果您的應用依賴這種行為,請在註解中添加一項運行時必須可用的保留政策。 您可通過使用 @Retention(RetentionPolicy.RUNTIME) 來如此做。

    其他重要說明

    如果一個應用在 Android N 上運行,但卻是針對更低 API 級別開發的,那麼在用戶更改顯示尺寸時,系統將終止此應用進程。 應用必須能夠正常處理此情景。 否則,當用戶從最近使用記錄中恢復運行應用時,應用將會出現崩潰現象。
    您應測試應用以確保不會發生此行為。要進行此測試,您可以通過 DDMS 手動終止應用,以造成相同的崩潰現象。

    在密度發生更改時,系統不會自動終止面向 N 及更高版本的應用;不過,這些應用仍可能對配置變更做出不良響應。

    Android N 上的應用應能夠正常處理配置變更,並且在後續啟動時不會出現崩潰現象。您可以通過更改字體大小 (Setting > Display > Font size) 並隨後從最近使用記錄中恢復運行應用,來驗證應用行為。
    由於之前的 Android 版本中的一項錯誤,系統未能將對主線程上的一個 TCP 套接字的寫入操作舉報為嚴格模式違反。 Android N 修復了此錯誤。呈現出這種行為的應用引發 android.os.NetworkOnMainThreadException。一般情況下,我們不建議在主線程上執行網路操作,因為這些操作通常都有可能導致 ANR 和卡頓的高尾延遲。
    Debug.startMethodTracing() 方法族現在默認在您的共享的存儲空間上的軟體包特定目錄中存儲輸出,而非 SD 卡頂級。 這意味著應用不再需要請求WRITE_EXTERNAL_STORAGE 使用這些 API 的許可權。
    許多平台 API 現在開始檢查在 Binder 事務間發送的大負載,系統現在會將 TransactionTooLargeExceptions 再次作為 RuntimeExceptions 引發,而不再只是默默記錄或抑制它們。
    一個常見例子是在 Activity.onSaveInstanceState() 上存儲過多數據,導致 ActivityThread.StopInfo 在您的應用面向
    Android N 時引發 RuntimeException。
    如果應用向 View 發布 Runnable 任務,並且 View 未附加到窗口,系統會用 View 為 Runnable 任務排隊;在 View 附加到窗口之前,Runnable 任務不會執行。
    此行為會修復以下錯誤:
    如果一項應用是從並非預期窗口 UI 線程的其他線程發布到 View,則Runnable 可能會因此運行錯誤的線程。
    如果 Runnable 任務是從並非環路線程的其他線程發布,則應用可能會曝光 Runnable 任務。
    如果 Android N 上一項有 DELETE_PACKAGES 許可權的應用嘗試刪除一個軟體包,但另一項應用已經安裝了這個軟體包,則系統可能要求用戶確認。
    在這種情況下,應用在調用 PackageInstaller.uninstall() 時的返回狀態應為 STATUS_PENDING_USER_ACTION。

    Ⅳ 如何實現一個android的log自動化分析工具

    首先,讓我們看一看AndroidLog的格式。下面這段log是以所謂的long格式列印出來的。從前面Logcat的介紹中可以知道,long格式會把時間,標簽等作為單獨的一行顯示。

    [ 12-09 21:39:35.510 396: 416 I/ActivityManager ]

    Start procnet.coollet.infzmreader:umengService_v1 for service
    net.coollet.infzmreader/com.umeng.message.

    UmengService:pid=21745 uid=10039 gids={50039, 3003, 1015,1028}

    [ 12-09 21:39:35.518 21745:21745I/dalvikvm ]

    Turning on JNI app bug workarounds fortarget SDK version 8...

    [ 12-09 21:39:35.611 21745:21745D/AgooService ]

    onCreate()

    我們以第一行為例:12-09 是日期,21:39:35.510是時間396是進程號,416是線程號;I代表log優先順序,ActivityManager是log標簽。

    在應用開發中,這些信息的作用可能不是很大。但是在系統開發中,這些都是很重要的輔助信息。開發工程師分析的log很多都是由測試工程師抓取的,所以可能有些log根本就不是當時出錯的log。如果出現這種情況,無論你怎麼分析都不太可能得出正確的結論。如何能最大限度的避免這種情況呢?筆者就要求測試工程師報bug時必須填上bug發生的時間。這樣結合log里的時間戳信息就能大致判斷是否是發生錯誤時的log。而且根據測試工程師提供的bug發生時間點,開發工程師可以在長長的log信息中快速的定位錯誤的位置,縮小分析的范圍。

    同時我們也要注意,時間信息在log分析中可能被錯誤的使用。例如:在分析多線程相關的問題時,我們有時需要根據兩段不同線程中log語句執行的先後順序來判斷錯誤發生的原因,但是我們不能以兩段log在log文件中出現的先後做為判斷的條件,這是因為在小段時間內兩個線程輸出log的先後是隨機的,log列印的先後順序並不完全等同於執行的順序。那麼我們是否能以log的時間戳來判斷呢?同樣是不可以,因為這個時間戳實際上是系統列印輸出log時的時間,並不是調用log函數時的時間。遇到這種情況唯一的辦法是在輸出log前,調用系統時間函數獲取當時時間,然後再通過log信息列印輸出。這樣雖然麻煩一點,但是只有這樣取得的時間才是可靠的,才能做為我們判斷的依據。

    另外一種誤用log中時間戳的情況是用它來分析程序的性能。一個有多年工作經驗的工程師拿著他的性能分析結果給筆者看,但是筆者對這份和實際情況相差很遠的報告表示懷疑,於是詢問這位工程師是如何得出結論的。他的回答讓筆者很驚訝,他計算所採用的數據就是log信息前面的時間戳。前面我們已經講過,log前面時間戳和調用log函數的時間並不相同,這是由於系統緩沖log信息引起的,而且這兩個時間的時間差並不固定。所以用log信息前附帶的時間戳來計算兩段log間代碼的性能會有比較大的誤差。正確的方法還是上面提到的:在程序中獲取系統時間然後列印輸出,利用我們列印的時間來計算所花費的時間。

    了解了時間,我們再談談進程Id和線程Id,它們也是分析log時很重要的依據。我們看到的log文件,不同進程的log信息實際上是混雜在一起輸出的,這給我們分析log帶來了很大的麻煩。有時即使是一個函數內的兩條相鄰的log,也會出現不同進程的log交替輸出的情況,也就是A進程的第一條log後面跟著的是B進程的第二條log,對於這樣的組合如果不細心分析,就很容易得出錯誤的結論。這時一定要仔細看log前面的進程Id,把相同Id的log放到一起看。

    不同進程的log有這樣的問題,不同的線程輸出的log當然也存在著相同的問題。Logcat加上-vthread就能列印出線程Id。但是有一點也要引起注意,就是Android的線程Id和我們平時所講的linux線程Id並不完全等同。首先,在Android系統中,C++層使用的Linux獲取線程Id的函數gettid()是不能得到線程Id的,調用gettid()實際上返回的是進程Id。作為替代,我們可以調用pthread_self()得到一個唯一的值來標示當前的native線程。Android也提供了一個函數androidGetThreaId()來獲取線程Id,這個函數實際上就是在調用pthread_self函數。但是在Java層線程Id又是另外一個值,Java層的線程Id是通過調用Thread的getId方法得到的,這個方法的返回值實際上來自Android在每個進程的java層中維護的一個全局變數,所以這個值和C++層所獲得的值並不相同。這也是我們分析log時要注意的問題,如果是Java層線程Id,一般值會比較小,幾百左右;如果是C++層的線程,值會比較大。在前裡面的log樣本中,就能很容易的看出,第一條log是Jave層輸出的log,第二條是native層輸出的。明白了這些,我們在分析log時就不要看見兩段log前面的線程Id不相同就得出是兩個不同線程log的簡單結論,還要注意Jave層和native層的區別,這樣才能防止被誤導。

    AndroidLog的優先順序在列印輸出時會被轉換成V,I,D,W,E等簡單的字元標記。在做系統log分析時,我們很難把一個log文件從頭看到尾,都是利用搜索工具來查找出錯的標記。比如搜索「E/」來看看有沒有指示錯誤的log。所以如果參與系統開發的每個工程師都能遵守Android定義的優先順序含義來輸出log,這會讓我們繁重的log分析工作變得相對輕鬆些。

    Android比較常見的嚴重問題有兩大類,一是程序發生崩潰;二是產生了ANR。程序崩潰和ANR既可能發生在java層,也可能發生在native層。如果問題發生在java層,出錯的原因一般比較容易定位。如果是native層的問題,在很多情況下,解決問題就不是那麼的容易了。我們先看一個java層的崩潰例子:

    I/ActivityManager( 396): Start proccom.test.crash for activity com.test.crash/.MainActivity:
    pid=1760 uid=10065 gids={50065, 1028}

    D/AndroidRuntime( 1760): Shutting downVM

    W/dalvikvm( 1760): threadid=1: threadexiting with uncaught exception(group=0x40c38930)

    E/AndroidRuntime( 1760): FATALEXCEPTION: main

    E/AndroidRuntime( 1760):java.lang.RuntimeException: Unable to start activityComponentInfo
    {com.test.crash/com.test.crash.MainActivity}:java.lang.NullPointerException

    E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)

    E/AndroidRuntime( 1760): atandroid.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)

    E/AndroidRuntime( 1760): atandroid.app.ActivityThread.access$600(ActivityThread.java:141)

    E/AndroidRuntime( 1760): atandroid.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)

    E/AndroidRuntime( 1760): atandroid.os.Handler.dispatchMessage(Handler.java:99)

    E/AndroidRuntime( 1760): atandroid.os.Looper.loop(Looper.java:137)

    E/AndroidRuntime( 1760): atandroid.app.ActivityThread.main(ActivityThread.java:5050)

    E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invokeNative(NativeMethod)

    E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invoke(Method.java:511)

    E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
    (ZygoteInit.java:793)

    E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)

    E/AndroidRuntime( 1760): atdalvik.system.NativeStart.main(NativeMethod)

    E/AndroidRuntime( 1760): Caused by:java.lang.NullPointerException

    E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.setViewText(MainActivity.java:29)

    E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.onCreate(MainActivity.java:17)

    E/AndroidRuntime( 1760): atandroid.app.Activity.performCreate(Activity.java:5104)

    E/AndroidRuntime( 1760): atandroid.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)

    E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)

    E/AndroidRuntime( 1760): ... 11more

    I/Process ( 1760): Sending signal.PID: 1760 SIG: 9

    W/ActivityManager( 396): Force finishing activitycom.test.crash/.MainActivity

    Jave層的代碼發生crash問題時,系統往往會列印出很詳細的出錯信息。比如上面這個例子,不但給出了出錯的原因,還有出錯的文件和行數。根據這些信息,我們會很容易的定位問題所在。native層的crash雖然也有棧log信息輸出,但是就不那麼容易看懂了。下面我們再看一個native層crash的例子:

    F/libc ( 2102): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread2102 (testapp)

    D/dalvikvm(26630):GC_FOR_ALLOC freed 604K, 11% free 11980K/13368K, paused 36ms, total36ms

    I/dalvikvm-heap(26630):Grow heap (frag case) to 11.831MB for 102416-byteallocation

    D/dalvikvm(26630):GC_FOR_ALLOC freed 1K, 11% free 12078K/13472K, paused 34ms, total34ms

    I/DEBUG ( 127):*** *** *** *** *** *** *** *** *** *** *** *** *** *** ******

    I/DEBUG ( 127):Build fingerprint:
    'Android/full_maguro/maguro:4.2.2/JDQ39/eng.liuchao.20130619.201255:userdebug/test-keys'

    I/DEBUG ( 127):Revision: '9'

    I/DEBUG ( 127):pid: 2102, tid: 2102, name: testapp >>>./testapp <<<
    I/DEBUG ( 127):signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr00000000

    I/DEBUG ( 127): r0 00000020 r173696874 r2 400ff520 r300000000

    I/DEBUG ( 127): r4 400ff469 r5beb4ab24 r6 00000001 r7beb4ab2c

    I/DEBUG ( 127): r8 00000000 r900000000 sl 00000000 fpbeb4ab1c

    I/DEBUG ( 127): ip 4009b5dc spbeb4aae8 lr 400ff46f pc400ff45e cpsr 60000030

    I/DEBUG ( 127): d0 000000004108dae8 d1 4108ced84108cec8

    I/DEBUG ( 127): d2 4108cef84108cee8 d3 4108cf184108cf08

    I/DEBUG ( 127): d4 4108c5a84108c598 d5 4108ca084108c5b8

    I/DEBUG ( 127): d6 4108ce684108ce58 d7 4108ce884108ce78

    I/DEBUG ( 127): d8 0000000000000000 d9 0000000000000000

    I/DEBUG ( 127): d10 0000000000000000 d110000000000000000

    I/DEBUG ( 127): d120000000000000000 d130000000000000000

    I/DEBUG ( 127): d14 0000000000000000 d150000000000000000

    I/DEBUG ( 127): d16 c1dcf7c087fec8b4 d173f50624dd2f1a9fc

    I/DEBUG ( 127): d18 41c7b1ac89800000 d190000000000000000

    I/DEBUG ( 127): d20 0000000000000000 d210000000000000000

    I/DEBUG ( 127): d22 0000000000000000 d230000000000000000

    I/DEBUG ( 127): d24 0000000000000000 d250000000000000000

    I/DEBUG ( 127): d26 0000000000000000 d270000000000000000

    I/DEBUG ( 127): d28 0000000000000000 d290000000000000000

    I/DEBUG ( 127): d30 0000000000000000 d310000000000000000

    I/DEBUG ( 127): scr 00000010

    I/DEBUG ( 127):

    I/DEBUG ( 127):backtrace:

    I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

    I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

    I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

    I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

    I/DEBUG ( 127):

    I/DEBUG ( 127):stack:

    I/DEBUG ( 127): beb4aaa8 000000c8
    I/DEBUG ( 127): beb4aaac 00000000
    I/DEBUG ( 127): beb4aab0 00000000
    I/DEBUG ( 127): beb4aab4 401cbee0 /system/bin/linker

    I/DEBUG ( 127): beb4aab8 00001000
    I/DEBUG ( 127): beb4aabc 4020191d /system/lib/libc.so (__libc_fini)

    I/DEBUG ( 127): beb4aac0 4020191d /system/lib/libc.so (__libc_fini)

    I/DEBUG ( 127): beb4aac4 40100eac /system/bin/testapp

    I/DEBUG ( 127): beb4aac8 00000000
    I/DEBUG ( 127): beb4aacc 400ff469 /system/bin/testapp

    I/DEBUG ( 127): beb4aad0 beb4ab24 [stack]

    I/DEBUG ( 127): beb4aad4 00000001
    I/DEBUG ( 127): beb4aad8 beb4ab2c [stack]

    I/DEBUG ( 127): beb4aadc 00000000
    I/DEBUG ( 127): beb4aae0 df0027ad
    I/DEBUG ( 127): beb4aae4 00000000
    I/DEBUG ( 127): #00 beb4aae8 00000000
    I/DEBUG ( 127): ........ ........

    I/DEBUG ( 127): #01 beb4aae8 00000000
    I/DEBUG ( 127): beb4aaec 401e9721 /system/lib/libc.so (__libc_init+40)

    I/DEBUG ( 127): #02 beb4aaf0 beb4ab08 [stack]

    I/DEBUG ( 127): beb4aaf4 00000000
    I/DEBUG ( 127): beb4aaf8 00000000
    I/DEBUG ( 127): beb4aafc 00000000
    I/DEBUG ( 127): beb4ab00 00000000
    I/DEBUG ( 127): beb4ab04 400ff404 /system/bin/testapp

    I/DEBUG ( 127):

    這個log就不那麼容易懂了,但是還是能從中看出很多信息,讓我們一起來學習如何分析這種log。首先看下面這行:

    pid: 2102, tid: 2102,name: testapp >>>./testapp <<<
    從這一行我們可以知道crash進程的pid和tid,前文我們已經提到過,Android調用gettid函數得到的實際是進程Id號,所以這里的pid和tid相同。知道進程號後我們可以往前翻翻log,看看該進程最後一次列印的log是什麼,這樣能縮小一點范圍。

    接下來內容是進程名和啟動參數。再接下來的一行比較重要了,它告訴了我們從系統角度看,出錯的原因:

    signal 11 (SIGSEGV), code 1(SEGV_MAPERR), fault addr 00000000

    signal11是Linux定義的信號之一,含義是Invalidmemory reference,無效的內存引用。加上後面的「faultaddr 00000000」我們基本可以判定這是一個空指針導致的crash。當然這是筆者為了講解而特地製造的一個Crash的例子,比較容易判斷,大部分實際的例子可能就沒有那麼容易了。

    再接下來的log列印出了cpu的所有寄存器的信息和堆棧的信息,這裡面最重要的是從堆棧中得到的backtrace信息:

    I/DEBUG ( 127):backtrace:

    I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

    I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

    I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

    I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

    因為實際的運行系統里沒有符號信息,所以列印出的log里看不出文件名和行數。這就需要我們藉助編譯時留下的符號信息表來翻譯了。Android提供了一個工具可以來做這種翻譯工作:arm-eabi-addr2line,位於prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin目錄下。用法很簡單:

    #./arm-eabi-addr2line -f -eout/target/proct/hammerhead/symbols/system/bin/testapp0x0000045e

    參數-f表示列印函數名;參數-e表示帶符號表的模塊路徑;最後是要轉換的地址。這條命令在筆者的編譯環境中得到的結果是:

    memcpy /home/rd/compile/android-4.4_r1.2/bionic/libc/include/string.h:108

    剩餘三個地址翻譯如下:

    main /home/rd/compile/android-4.4_r1.2/packages/apps/testapp/app_main.cpp:38

    out_vformat /home/rd/compile/android-4.4_r1.2/bionic/libc/bionic/libc_logging.cpp:361

    _start libgcc2.c:0

    利用這些信息我們很快就能定位問題了。不過這樣手動一條一條的翻譯比較麻煩,筆者使用的是從網上找到的一個腳本,可以一次翻譯所有的行,有需要的讀者可以在網上找一找。

    了解了如何分析普通的Log文件,下面讓我們再看看如何分析ANR的Log文件。

    Ⅳ android Software caused connection abort異常 手機通過wifi(ESP8266)採集數據 幾個小時後報錯

    出現這個情況一般是客戶端那邊寫完流後,就立即關閉了socket。伺服器端這邊還沒讀完,所以就報錯了,你可以讓客戶端那邊寫完對象後,等伺服器端回一個狀態給客戶端。客戶端再關閉流。

    Ⅵ 如何使用Android藍牙開發

    Android平台支持藍牙網路協議棧,實現藍牙設備之間數據的無線傳輸。本文檔描述了怎樣利用android平台提供的藍牙API去實現藍壓設備之間的通信。藍牙具有point-to-point 和 multipoint兩種連接功能。
    使用藍牙API,可以做到:
    * 搜索藍牙設備
    * 從本地的Bluetooth adapter中查詢已經配對的設備
    * 建立RFCOMM通道
    * 通過service discovery連接到其它設備
    * 在設備之間傳輸數據
    * 管理多個連接

    基礎知識
    本文檔介紹了如何使用Android的藍牙API來完成的四個必要的主要任務,使用藍牙進行設備通信,主要包含四個部分:藍牙設置、搜索設備(配對的或可見的)、連接、傳輸數據。
    所有的藍牙API在android.bluetooth包中。實現這些功能主要需要下面這幾個類和介面:

    BluetoothAdapter
    代表本地藍牙適配器(藍牙發射器),是所有藍牙交互的入口。通過它可以搜索其它藍牙設備,查詢已經配對的設備列表,通過已知的MAC地址創建BluetoothDevice,創建BluetoothServerSocket監聽來自其它設備的通信。

    BluetoothDevice
    代表了一個遠端的藍牙設備, 使用它請求遠端藍牙設備連接或者獲取 遠端藍牙設備的名稱、地址、種類和綁定狀態。 (其信息是封裝在 bluetoothsocket 中) 。

    BluetoothSocket
    代表了一個藍牙套接字的介面(類似於 tcp 中的套接字) ,他是應用程 序通過輸入、輸出流與其他藍牙設備通信的連接點。

    BluetoothServerSocket
    代表打開服務連接來監聽可能到來的連接請求 (屬於 server 端) , 為了連接兩個藍牙設備必須有一個設備作為伺服器打開一個服務套接字。 當遠端設備發起連 接連接請求的時候,並且已經連接到了的時候,Blueboothserversocket 類將會返回一個 bluetoothsocket。

    BluetoothClass
    描述了一個設備的特性(profile)或該設備上的藍牙大致可以提供哪些服務(service),但不可信。比如,設備是一個電話、計算機或手持設備;設備可以提供audio/telephony服務等。可以用它來進行一些UI上的提示。
    BluetoothProfile

    BluetoothHeadset
    提供手機使用藍牙耳機的支持。這既包括藍牙耳機和免提(V1.5)模式。

    BluetoothA2dp
    定義高品質的音頻,可以從一個設備傳輸到另一個藍牙連接。 「A2DP的」代表高級音頻分配模式。

    BluetoothHealth
    代表了醫療設備配置代理控制的藍牙服務

    BluetoothHealthCallback
    一個抽象類,使用實現BluetoothHealth回調。你必須擴展這個類並實現回調方法接收更新應用程序的注冊狀態和藍牙通道狀態的變化。

    Ⅶ 如何定時刷新Android界面

    Handler.sendEmptyMessageDelayed(0, 1000);來實現


    sendEmptyMessageDelayed:延時多少毫秒,向Handler發送信息


    具體代碼和效果

    每隔1秒刷新一次時間

    Ⅷ Android程序員的較好的職業規劃應該是怎樣

    Android程序員的職業規劃,怎麼說呢?一句話叫做:早知如此,又何必當初。命運有些是自己可以掌握的,有些可能需要運氣和機會。
    一、路徑可達
    先說說路徑可達這個詞吧?有些人會覺得他的路看不到未來,有些人就可以清晰的看到他的方向。如果你現在所做的工作過兩年會不會有所成長,達到你的目標。如果答案是否定的,那麼說明現在的工作是沒有上升通道的,就需要改變。當然安於現狀不思進取是另外一回事。時刻反思自己所走的路,然後迅速調整,可能會少走很多彎路,畢竟時間不可逆。

    二、時間規劃
    我有時候會想我五年後在哪裡?做什麼?大部分人對於這個都會比較模糊。因為時間跨度太大。五年時間相當於整個生命長河其實比較短,但在職業規劃中確是很長的段,特別是剛畢業的那五年。從時間規劃來講肯定會用到時間的切分。宏觀的東西只有落地到一件件事上才是有效的,才算得上完整的規劃。但是話又說回來人是有惰性的,人對於這種有限制的東西有天然的排斥感,執行起來非常痛苦,即使開始執行起來很有激情,過不了幾個月,所有的計劃都縮水了,這同時也導致了很多時間的浪費和做事情的盲目性。所以計劃的時效性和執行很重要,這里又會涉及一個詞:「執行力」。
    沒有計劃也導致學習變成一個一個孤立的點,完全沒有串連性。因為你是想到學什麼學什麼,而不是計劃著學,一段時間後可能會有一些積累,但是永遠深度不夠。這可以做一個簡單的實驗,把自己腦子里的東西理一理,如果時間需要很長說明整體知識體系已經有些混亂,可以對比一下操作系統的磁碟整理。如果一個人能很好的管理時間那麼必成大牛。好學生好在哪裡,排除智商的因素外,就是時間管理和善於思考。我覺得我自己最大的問題:時間管理,自律性,溝通能力。這三塊是我覺得自己最缺乏一定程度上是致命的,很大程度上會決定我未來的所發展的高度。
    三、項目經理還是架構師
    在程序員中一直有個討論就是將來要做項目經理還是做架構師。這兩條路的側重點不一樣,所以積累的東西也可能不同。項目經理更強調綜合能力,比如說協調能力,溝通能力等一系列偏管理的能力。而架構師可能更專注於技術本身,技術上的宏觀方向。兩條路有重疊,但是更多的是區別。有些項目經理可能就不會寫代碼。但是同樣可以帶好一個項目,一個團隊。
    我曾經也問自己要是以後這兩條路走哪條,其實都可以嘗試一下。比如說給一個項目讓我帶帶,我能否把它帶好,其實需要機會,同時也需要自己去爭取這樣的機會。所以我的答案就是如果有機會的話兩條路都可以嘗試走走,就是兩個方向的一些能力都可以進行積累。很多人認為項目經理是一個職位,我倒覺得是動態的,這個項目中你做項目經理,另外一個項目中可能又是開發工程師。所以不永遠是項目經理,也不永遠是開發工程師。
    就程序員而言,專注技術是沒有任何問題的,先技術後管理。管理這個東西總的說有點虛無飄渺,各都有各的一套理論,比較難以評估。但是技術是可測量的,通過一定的努力技術水平都會有定的躍升。記得在《肖申克的救贖》裡面說到地質的形成只需要兩個條件:壓力和時間。其實對於學技術也是一樣的。只要肯學一定會達到某個水平。到大牛級別的確實需要一些悟性和天分。
    四、我的選擇
    我為什麼覺得自己應該走架構師這條路,這和我職業終極目標是契合的。這里先說一下架構師做什麼?架構師負責整個項目甚至整個系統的構架(這一句話等於廢話)。一般型的項目可能這個設計項目就做掉甚至可能就不需要架構。但是系統復雜度上升的時候,會涉及到系統之間的交互,還有技術的可行性和整個設計的方案。這個時候架構師就出場了。另外的工作就是承擔一定的培養新人的工作。所以架構師都需要具備比較好的口才,很多人都說程序員不會說話,錯了,那是低端的,到了高端的程序員口才都很好,看一下那些程序員大會中侃侃而談的架構師們,是不是有種「高端大氣上檔次」的感覺。這後面會發現有一個發展方向就是「培訓師」,還可以寫書,其實這些都可能是一些「副產品」。技術到一定的境界很多事情到都是水到渠成。
    架構師寫代碼嗎?當然寫。他們肯定不會寫那些簡單的代碼,他們一般寫什麼代碼?框架,一般來講優秀的框架都是一個人或者極少人寫出來的。比如說Linux的核心就是一個人寫出來的。好的代碼絕不是人堆出來的。你給100個初級程序員也整不出一個Struts來。這里會衍生出另外一條路,就是開源框架,很多牛人都是開源社區的愛好者。都或多或少的參與了一些開源項目。甚至把自己寫的一些東西開源出來。一般來講能做到這個級別那是相當厲害的了。

    五、領域方向
    我記得以前總有人問我你最擅長的領域是什麼?這個問題一問我就懵了,因為我從來就沒想過這個問題。可能本身還沒到分領域的級別,還處於一種「原始積累」階段。技術學到一定階段的時候是分領域的。領域之間會有一些交叉。
    我所知道的大方向是「高性能,大數據量,移到平台「。這是我給Java這所分的三個方向。其實我上面所說的三個方向不一定是同一個維度。但是我認為寫Java的如果沒有沾上這三個方向中的一個,一定沒有前途。高性能和大數據量的處理需要比較多的技術儲備。很多人說寫個Java就是CRUD(嚴格來講,對於計算機本身所有的操作都是CRUD)。可是在高性能情況下所涉及的問題一下成指數級增長。各種「水平擴展」,「服務化」,「容災」,」緩存」等各種牛B的詞彙就來了,你寫一般的CRUD最多也就知道個SSH,這是不一樣的。比如說做大數據量的處理一定會知道Hadoop,然後就是雲計算,雲存儲。反正什麼牛B什麼來。移動平台和上面我所說的維度不一樣,因為移動平台相對應的是PC平台。但是由於移動平台的發展時間很短。所以能搭上這趟快車也有不錯的發展。要是早些年(2012年以前)進入移動平台的開發,現在同水平的程序員工資肯定更高。這是平台發展所帶來的紅利。雖然三年前我預見到了移動平台的無可限量,但是那時候就像一個一無所有的人,還管它什麼移動平台還是PC平台,能寫代碼做項目就OK。以至於我學了一個月的Android就偃旗息鼓。
    不管怎麼樣技術的底層都是一樣的,所以扎實的基礎是必要的,這就是為什麼演算法和數據結構是永恆不衰的。很多人說演算法和數據結構無用那就是無知的表現。這個無知就像在討論讀大學有沒有用一樣。

    六、總結
    上面所說的一些東西可能都會比較虛,很多人都可能明白其中的道道,比如說到時間管理,這個估計從學生時代就在講。但是真正的執行還是千差萬別。所以又回歸到哪裡?回歸到人本身。後來我想明白一件事情,即使道理再明白,沒有好的執行仍然等於空談。這里我回想起劉未鵬的《暗時間》。裡面非常細致的講了對於時間的管理。這個我讀大學的時候同樣在一本書《讀大學,究竟讀什麼》裡面也有所論述。當然兩個方向是不一樣的,一個是程序員的思維,另外一個是文科生的思維。但是道理只有一個,時間利用率的本質是什麼。
    另外就是實踐,強烈的實踐。我記得大學的時候讀《人性的弱點》真是心潮澎湃,可是過不了多久我就忘了書中的內容。所以沒有把書中的一些東西深刻的印記在腦海里並轉化成你自己的東西,它永遠只是知識。

    閱讀全文

    與androidworkthread相關的資料

    熱點內容
    硬碟錄像機接什麼伺服器設備 瀏覽:498
    智慧醫療方面最優演算法 瀏覽:920
    伺服器ban掉了是什麼意思 瀏覽:394
    vvo手機拍的視頻在哪個文件夾 瀏覽:838
    華為防火牆cli命令手冊 瀏覽:895
    於正新劇玉樓春在什麼App播放 瀏覽:127
    學習社會經驗下載什麼app 瀏覽:475
    php發布站程序 瀏覽:204
    源碼編譯ntfs內核模塊 瀏覽:120
    r11s手機管家沒有加密 瀏覽:781
    怎麼看電腦連接哪個伺服器 瀏覽:191
    二手伺服器設備欺詐如何解決 瀏覽:877
    單片機伺服器安裝win10 瀏覽:658
    胸椎壓縮性骨折傷殘 瀏覽:954
    mt怎麼解壓文件 瀏覽:41
    達芬奇項目伺服器有什麼用 瀏覽:854
    自製怎麼捏都可以復原的解壓球 瀏覽:615
    qq軟體管理怎麼加密 瀏覽:740
    手機使用代碼編程器 瀏覽:939
    單片機四位99秒錶製作流程圖 瀏覽:617