CSDN移動將持續(xù)為您優(yōu)選移動開發(fā)的精華內(nèi)容,共同探討移動開發(fā)的技術(shù)熱點話題,涵蓋移動應(yīng)用、開發(fā)工具、移動游戲及引擎、智能硬件、物聯(lián)網(wǎng)等方方面面。如果您想投稿、參與內(nèi)容翻譯工作,或?qū)で蠼硤蟮溃埌l(fā)送郵件至tangxy#csdn.net(請把#改成@)。
我的第一個應(yīng)用非常糟糕。事實上,它糟糕得以致于我從應(yīng)用市場上刪除它,同時我甚至都不會在我的簡歷上羅列出它。如果我在開發(fā)之前能夠知道一些Android開發(fā)的事情,也不會糟糕到這步田地。
本文中所羅列的事情是你在開發(fā)第一個Android應(yīng)用的時候需要牢記在大腦中的。我接下來將展示的實際錯誤均來自于我的第一個應(yīng)用程序代碼中。把這些錯誤經(jīng)驗牢記心頭能夠幫助你開發(fā)一個讓你引以為豪的應(yīng)用。
當然,正如Code Standards所說:如果你所做的工作和你作為學(xué)生開發(fā)的Android應(yīng)用類似,你很有可能會討厭你的應(yīng)用。
如果一年前你寫的代碼對于你來說感覺還不錯,你很大程度上沒有進行足夠的學(xué)習(xí)。
——Code Standards 2015.5.21
如果你是一位經(jīng)驗豐富的JAVA開發(fā)者,第1、2、5條很有可能對你沒有吸引力。另一方面,即使你從來沒有犯過這些例子中的錯誤,第3、4條也可能向你展示一些很酷的事物,你可以利用一款也許你不知道的軟件——Android Studio去實現(xiàn)這些事物。
1. 不要持有Context的靜態(tài)引用
public class MainActivity extends LocationManagingActivity implements ActionBar.OnNavigationListener, googlePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener { //... private static MeTrackerStore mMeTrackerStore; //... @Override protected void onCreate(Bundle savedInstanceState) { //... mMeTrackerStore = new MeTrackerStore(this); } }
這對于每個人來說看似是一個不可能犯的錯誤。但事實卻并非如此,我犯了這個錯誤,我也看到過別人犯這個錯誤,同時我也采訪過那些不能很快指出為什么這是放在第一位的錯誤的人。不要這樣做,它是會變的。
如果MeTrackerStore通過它的構(gòu)造函數(shù)保持一個指向Activity的引用,這個Activity將不會被垃圾回收(GC),除非靜態(tài)變量被從新分配到不同的Activity。這是因為mMeTrackerStore是靜態(tài)變量,而靜態(tài)變量的內(nèi)存是不會被回收,直到應(yīng)用程序退出才回收。如果你正在試圖做這樣的事情,你的代碼很有可能有嚴重的錯誤。尋找?guī)椭?,可能看看Google的Udacity課程“Android Development for Beginners”能夠幫助你。
注:從技術(shù)上說,你可以對一個Application Context進行靜態(tài)變量引用而不引起內(nèi)存泄露,但我不建議你這樣做。
2. 注意那些你無法控制生命周期的對象的隱式引用
public class DefineGeofenceFragment extends Fragment { public class GetLatAndLongAndUpdateMapCameraAsyncTask extends AsyncTask<String, Void, LatLng> { @Override protected LatLng doInBackground(String... params) { //... try { //Here we make the http request for the place search suggestions httpResponse = httpClient.execute(httpPost); HttpEntity entity = httpResponse.getEntity; inputStream = entity.getContent; //.. } } } }
這段代碼有很多問題,但我現(xiàn)在只會把重點問題放在“隱式引用”那些問題上。在Java中,(非靜態(tài))內(nèi)部類有個對外部類實例有個隱式引用。
在這個例子中,任何GetLatAndLongAndUpdateCameraAsyncTask都有一個外部類DefineGeofenceFragment的引用。對于匿名類是同樣的,它們也有一個對包含它們的類的實例的一個隱式引用。
GetLatAndLongAndUpdateCameraAsyncTask對生命周期我們無法控制的Fragment對象有一個隱式引用。Android SDK負責創(chuàng)建和銷毀Fragment,如果GetLatAndLongAndUpdateCameraAsyncTask 因為正在運行而不能被垃圾回收,那么DefineGeofenceFragment也將因為具有隱式引用而保留不能被垃圾回收。
這里有一個很棒的Google視頻,解釋它為什么會發(fā)生這種事情(友情提示:需自備梯子哈)。
3. 使用Android Studio進行工作
public ViewPager getmViewPager { return mViewPager; }
這段代碼是我使用“Generate Getter”在Android Studio中進行生成的。這些getter保持了’m’前綴的實例變量,同樣通過它也能為一個方法產(chǎn)生相同的效果,這已經(jīng)不是空想。
(如果你想知道為什么’m’是實例變量的名稱的第一個字母,’m’往往是實例變量的公認約定。它代表了’member'(成員)的意思)。
不管你是否認為實例變量的前綴’m’是一個好注意,在這有一個知識,Android Studio能夠幫助你編寫任何你想要實現(xiàn)的公認約定。例如,在你為實例變量生成getters、setters和connstructor參數(shù)時,你可以使用Android Studio代碼風格對話框的設(shè)置使Android Studio在你的實例變量前自動添加’m’和移除’m’。
Android Studio能夠做的遠不止于此。學(xué)習(xí)Android Studio從學(xué)習(xí)快捷鍵和模版是不錯的開始。
4. 一個函數(shù)只做一件事
在我寫的眾多類中,有一個類的一個方法我便寫了有100多行。這類的方法是非常難以讀懂、修改和重用,努力讓一個方法只做一件事情。顯然,這意味著你應(yīng)該對超過20行的方法持有懷疑態(tài)度。這里,你可以使用Android Studio來幫助你發(fā)現(xiàn)有問題的方法:
5. 向聰明和有經(jīng)驗的人學(xué)習(xí)
這可能聽起來微不足道,但是這是我開發(fā)第一個應(yīng)用時候犯下的錯誤。
當你開發(fā)一個應(yīng)用的時候,你會犯別人已經(jīng)犯過的錯誤。向別人學(xué)習(xí),你可以避免犯別人犯過的錯誤來節(jié)約你的時間。我在我的第一個應(yīng)用中浪費了大量的時間去犯錯,這些錯誤如果我花點時間向有經(jīng)驗的軟件開發(fā)工程師學(xué)習(xí)就可以避免。
閱讀Pragmatic Programmer,然后閱讀Effective Java。這兩本書會幫助你避免開發(fā)新手常犯的錯誤。在你學(xué)習(xí)了這兩本書后,不停地尋找聰明的人并向他們學(xué)習(xí)。
6. 使用類庫
當你開發(fā)應(yīng)用的時候,你可能會遇到一些聰明人和有經(jīng)驗人已經(jīng)解決過的問題。而且,許多這些問題的解決方案是可以作為開源庫的,充分利用它們。
在我的第一個應(yīng)用中,我寫了一些類庫已經(jīng)提供的功能代碼。其中一些是Java標準庫,還有一些是第三方類庫,如Retrofit和Picasso。如果你不確定你使用什么樣的類庫,你可以做下面3件事情:
- 聽Google IO Fragmented廣播。在這期間,詢問這些開發(fā)者什么第三方類庫類庫對Android很重要。
- 訂閱Android周刊。這里包含了一部分最新的類庫,時刻注意哪些對自己有用。
- 尋找那些能夠解決與你在開發(fā)應(yīng)用中遇到問題類似的開源應(yīng)用。你可能發(fā)現(xiàn)某個應(yīng)用使用的第三方類庫就是你想要的,或者你會發(fā)現(xiàn)一個你所不知道的Java類庫。
總結(jié)
開發(fā)優(yōu)秀的Android應(yīng)用是非常困難的,不要用重蹈覆轍來難為自己。如果你發(fā)現(xiàn)我寫的代碼中的錯誤請在評論中告訴我。(誤導(dǎo)性評論比沒有評論更糟糕)。如果你認為這篇文章對于新手開發(fā)者有用,請分享它,以解決他們的一些令人頭疼的難題。