在我寫我的第一個Android App時,我希望我能知道的6件事
我的***個app是糟糕的。實際上,它太糟糕了,所以我把它從商店中移除,我甚至不再因我把它列在我的簡歷之中而煩惱。如果我在寫它之前,知道一些有關(guān)Android開發(fā)的事,那個app就不會那么糟糕。
當你寫你的***個Android app時,這有一個列表你需要記著。這些經(jīng)驗教訓(xùn)是我在寫***個app源碼時,犯下的真實的錯誤。我將會在后面展示這些錯誤。記住這些事情能幫助你寫一個讓你感到有點自豪的app。
當然,如果你作為一個Android開發(fā)的學(xué)生正在做正確的工作,無論如何,不久后你都有可能恨你寫的app,正如@codestandards所說,如果你一年前碼的代碼并不能讓你感覺到不適,那你有可能沒怎么學(xué)習(xí)。
如果你是一個有經(jīng)驗的Java開發(fā)者, 第1,2和第5條可能并不能讓你感興趣。另外的第3,4條可能展示你一些很酷的但你可能還不知道的東西。
對Contexts不要有靜態(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);
- }
- }
這可能看起來對任何人來說,都是一個不可能犯的錯誤。但并非這樣,我就犯過。我也看到其他人犯過這樣的錯誤,并且我也看到很多人并不能在***時間指出為什么這是一個錯誤。不要這樣做。它是一個noob move
如果當這個Activity傳遞到它的構(gòu)造函數(shù)里,MeTrackerStore持有這個Activity的引用,那這個Activity將仍然不會被回收(除非這個靜態(tài)變量被重新賦值給另一個Activity)。這是因為mMeTrackerStore是靜態(tài)的,靜態(tài)變量的內(nèi)存是不會被回收的,直到程序里正在運行的進程停止。如果你發(fā)現(xiàn)自己嘗試這么做,那么你的代碼可能有一些嚴重的錯誤。尋找?guī)椭脑?,可以看看Google’s Udacity里的課程 “Android Development for Beginners”
注意:技術(shù)上講,你可以hold一個對Context的靜態(tài)引用,但不會引起內(nèi)存泄漏,但我不會推薦你這么做。
當心對那些你無法控制它的生命周期的對象進行隱式引用
- 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();
- //..
- }
- }
- }
- }
這段代碼有很多問題,但我將關(guān)注其中的一個。在Java中,非靜態(tài)的內(nèi)部類對包含它的類對象有一個隱式的引用。
在這個例子中,任何GetLatAndLongAndUpdateMapCameraAsyncTask對象都將有個DefineGeofenceFragment對象的引用。匿名類也是如此:它會對包含它的類對象有個隱式的引用。
這個GetLatAndLongAndUpdateMapCameraAsyncTask對象對Fragment對象有個隱式的的引用,一個我們無法控制它生命周期的對象。Android SDK負責(zé)適當?shù)膭?chuàng)建和銷毀Fragment對象,如果因為GetLatAndLongAndUpdateMapCameraAsyncTask對象正在執(zhí)行所以不能被回收的話,那它持有對象也無法被回收。
這里有一個很棒的Google IO 視頻解釋為什么這種事會發(fā)生
讓Android Studio為你工作
- public ViewPager getmViewPager() {
- return mViewPager;
- }
這個片段是我使用”Generate Getter”代碼補全時,Android Studio為我生成的,這個getter方法對這個實例變量保持了’m’前綴。這并不理想。
(另外,你一定想知道為毛實例變量神明的時候要帶個’m’前綴:這個’m’常常被約定作為實例變量的前綴。它代表了’member’。)
不論你是否認為’m’作為你實例變量的前綴是一個好主意,這里有一個經(jīng)驗:Android Studio可以幫你按照你養(yǎng)成的習(xí)慣去編寫代碼。比如說,你可以使用Android Studio中的代碼風(fēng)格框去讓Android Studio自動的加上’m’到你的實例變量并且自動移除’m’當它生成getters,setters,和構(gòu)造參數(shù)時。
Android Studio可以做很多事情,學(xué)習(xí)快捷鍵和活動模版會是一個好的開始。
方法應(yīng)該只做一件事
有一個方法我寫超過了1000行。這樣的方法很難讀懂,修改和重用。試著寫僅僅做一件事的方法。典型的,這意味著你應(yīng)該懷疑那些你寫超過20行的代碼。這里你可以招募Android Studio去幫助你指出有問題的方法:
向那些比你更聰明,更有經(jīng)驗的人學(xué)習(xí)
這好像挺起來不重要,但是這是我寫***個app時犯下的錯誤。
當你正在寫程序時,你將會犯錯。其他的人已經(jīng)犯過這樣的錯誤了。向其他人學(xué)習(xí)。如果你重復(fù)那些可以避免的錯誤,那你就是在浪費時間。
讀Pragmatic Programmer. 然后讀Effective Java.這兩本書會幫助你避免犯一些常見的錯誤。當你讀完這兩本書后,保持向聰明的人學(xué)習(xí)。
使用庫
當你寫一個app,你可能會遇到那鞋前人已經(jīng)解決了的問題。而且,大量的解決辦法都是開放的作為資源庫。 好好利用他們。
在我的***個app中,我寫的功能已經(jīng)被其他庫所提供了,它們中的一些庫來自于標準的java中的一部分。另一些則是像Retrofit和Picasso這樣的庫。如果你不確定你要應(yīng)該用什么庫,你能做3件事:
1.聽Google IO Fragmented podcast episode
2.訂閱Android Weekly
3.尋找解決類似問題的開源應(yīng)用。你可能發(fā)現(xiàn)它們用了第三發(fā)的庫(third-party library)或者用了你并沒有在意的標準的java庫。
總結(jié)
寫一個好的Android app是非常難的。不要因為重復(fù)我的錯誤讓它變的更加艱難。