代碼變得更整潔的 Android 庫(kù)

轉(zhuǎn)自:https://mp.weixin.qq.com/s?__biz=MjM5MTM0NjQ2MQ==&mid=2650140141&idx=2&sn=78862743a5385691b946cca26f846362&chksm=beb7b79f89c03e8989f62b4fa12148ef8b8b2976e6e9a374ad56a5cc2b581cc7cf9fcae8aa30&mpshare=1&scene=1&srcid=0714F0yHeWcXzvvw07UXe7lh&pass_ticket=Ae%2BxiwckdEylxCmXTOUIDEjAuWT6Fbr8apD1GgVq6hz899BUrrcgz1i5ntWE2n2a#rd

Android開發(fā)是有趣的——這毫無疑問。然而,還是有很多平臺(tái)迫使我們編寫重復(fù)的樣板代碼。很多時(shí)候這都與需要你處理的UI組件相關(guān)。有一些確實(shí)是你需要的,當(dāng)你希望你的應(yīng)用程序架構(gòu)能夠干干凈凈的時(shí)候。有很多操作在后臺(tái)異步執(zhí)行;事實(shí)上,最后很容易成為一堆意大利面條似的代碼,不可讀或者就是讓人感覺不正確。
今天,我們將看看6個(gè)可以幫助保持代碼清晰和可讀性的Android庫(kù),并且使用示例項(xiàng)目以方便你可以看到庫(kù)的作用。
項(xiàng)目
我們將使用之前我們?cè)赗etrofit指南中使用過的Retrofit 2 Sample應(yīng)用程序。這是一個(gè)簡(jiǎn)單的開源項(xiàng)目,可以在GitHub上找到。它需要一個(gè)公司名稱和一個(gè)Git存儲(chǔ)倉(cāng)庫(kù),并列出所有的貢獻(xiàn)者,貢獻(xiàn)者顯示為帶有頭像的一個(gè)列表。雖然它不是一個(gè)革命性的app,但是它展示了如何執(zhí)行網(wǎng)絡(luò),使用圖像,創(chuàng)建列表組件,以及處理用戶輸入。你可以隨意擺弄這個(gè)功能齊全的玩具項(xiàng)目。
讓我們將注釋庫(kù)應(yīng)用到代碼,來看看它們?nèi)绾螏椭S護(hù)Android app代碼的整潔。

  1. Butter Knife
    每當(dāng)你需要訪問代碼中的視圖時(shí),你需要獲取該視圖的對(duì)象實(shí)例。你可以通過編寫rootView.findViewById()方法來實(shí)現(xiàn),然后將返回的對(duì)象轉(zhuǎn)換為正確的視圖類型。但是,你的代碼很快就會(huì)建立起來,但是尤其是在onCreate和onCreateView方法中會(huì)有惱人的類似語(yǔ)句。想想看;在那些onCreate方法中,你初始化一切,綁定偵聽器,把整個(gè)UI綁在一起。你擁有的UI元素越多,那么單個(gè)方法就會(huì)越長(zhǎng)。
    讓我們舉個(gè)簡(jiǎn)單的例子:


    Butter-Knife

    此視圖將需要三個(gè)視圖:兩個(gè)EditTexts和一個(gè)Button,我們需要在片段中引用。一般我們會(huì)這樣做:

@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {  // Inflate the layout for this fragment
  View rootView = inflater.inflate(R.layout.fragment_search, container, false);
  companyEditText = (EditText) rootView.findViewById(R.id.company_edittext);
  repositoryEditText = (EditText) rootView.findViewById(R.id.repository_edittext);
  searchButton = (Button) rootView.findViewById(R.id.search_button);

  searchButton.setOnClickListener(new View.OnClickListener() {    @Override
    public void onClick(View v) {
      searchContributors();
    }
  });  return rootView;
}

在代碼中除了從布局中查找視圖,將它們存儲(chǔ)在活動(dòng)的字段中,以及添加一個(gè)匿名內(nèi)部類作為監(jiān)聽器來處理搜索命令之外,沒有太多事情發(fā)生。通過Butter Knife,我們可以使我們的工作和編碼更容易。視圖對(duì)象存儲(chǔ)在字段中,因此我們可以簡(jiǎn)單地向每個(gè)字段添加Butter Knife @BindView注解,如下所示:

@BindView(R.id.company_edittext) EditText companyEditText;
@BindView(R.id.repository_edittext) EditText repositoryEditText;
@BindView(R.id.search_button) Button searchButton;

我們還需要使onCreateView方法知道Butter Knife的存在?,F(xiàn)在,初始化代碼將只包含以下簡(jiǎn)短語(yǔ)句:

@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {  // Inflate the layout for this fragment
  View rootView = inflater.inflate(R.layout.fragment_search, container, false);
  ButterKnife.bind(this, rootView);  return rootView;
}

我們還可以進(jìn)一步,跳過綁定監(jiān)聽器到searchButton方法,并改為注解onSearchButtonClicked方法,通過神奇地將之綁定到按鈕點(diǎn)擊的@OnClick注解:

@OnClick(R.id.search_button)
public void onSearchButtonClicked(View searchButton) {  searchContributors();
}

在官方的Butter Knife主頁(yè)還有其他的例子。不妨一一查看一番!一般說來,如果你需要以編程方式訪問視圖元素,那么Butter Knife會(huì)讓你的代碼更簡(jiǎn)潔和可讀。

  1. Ice Pick
    許多Android應(yīng)用程序面臨的一個(gè)常見問題是活動(dòng)和片段生命周期的不正確處理。是啊,我們知道,它不是Android框架最優(yōu)雅的部分。但是,在AndroidManifest文件中禁用橫向模式,這樣當(dāng)用戶將設(shè)備側(cè)向移動(dòng)時(shí),應(yīng)用程序不會(huì)崩潰并非是一個(gè)正確的解決方案——首先,因?yàn)轱@得有點(diǎn)傻,其次,代碼不能正確處理的配置更改仍然會(huì)發(fā)生并破壞一切!因此,你必須正確處理應(yīng)用程序組件的狀態(tài)和生命周期。
    實(shí)現(xiàn)的目的是將活動(dòng)中所有字段的內(nèi)容存儲(chǔ)到bundle中,然后由Android框架通過生命周期正確管理。這可能是相當(dāng)無聊。
    幸運(yùn)的是,Ice Pick使我們的生活變得容易多了,因?yàn)槟阍俨槐匾粋€(gè)個(gè)添加所有的變量到bundle去保存。同樣從bundle中再次讀取數(shù)據(jù),如果存在,那么會(huì)很有挑戰(zhàn)性,但I(xiàn)ce Pick簡(jiǎn)化了很多很多。因此,作為示例,假設(shè)我們需要記住最后一家公司和存儲(chǔ)庫(kù)搜索的組合。
    首先,我們對(duì)要保存到bundle的字段進(jìn)行注解。
@State String lastSearchCombination;

現(xiàn)在我們需要在onSaveInstanceState()方法中調(diào)用Ice Pick:

@Overridepublic void onSaveInstanceState(Bundle outState) {  super.onSaveInstanceState(outState);
  Icepick.saveInstanceState(this, outState);
}

也在onCreateView()方法中調(diào)用Ice Pick來恢復(fù)狀態(tài):

@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,
                        Bundle savedInstanceState) {  // Inflate the layout for this fragment
  View rootView = inflater.inflate(R.layout.fragment_search, container, false);
  ButterKnife.bind(this, rootView);
  Icepick.restoreInstanceState(this, savedInstanceState); 
  return rootView;
}

記?。耗憧梢员4娴絙undle的內(nèi)容的限制仍然存在。但是,沒有必要因?yàn)闉閎undle鍵添加常量或?yàn)閟avedInstanceState添加空檢查搞得一團(tuán)亂。

  1. Dart和Henson
    與Ice Pick類似,Dart幫助我們避免為從一個(gè)活動(dòng)傳遞到另一個(gè)活動(dòng)的Intent Extras寫入所有鍵和檢查。它也適用于Fragments。這里有一個(gè)小例子,展示了我是如何使用@InjectExtra注釋將搜索關(guān)鍵字從搜索屏幕傳遞到貢獻(xiàn)者列表,實(shí)際上將執(zhí)行搜索的地方。
    所以我使用@InjectExtra注解定義了兩個(gè)類變量:
@InjectExtra String repositoryQuery;
@InjectExtra String companyQuery;

@InjectExtra String repositoryQuery;@InjectExtra String companyQuery;
一旦Dart.inject(this, getActivity());被調(diào)用,那么這些都將會(huì)被自動(dòng)初始化?,F(xiàn)在在Bundle中被添加到Intent的extras最終將如何。你可以手動(dòng)進(jìn)行,但這里使用Henson是非常有道理的。為了使它工作,我添加以下代碼到我的

Intent intentContributorsFragment = 
  Henson.with(getActivity())
        .gotoContributorsFragment()
        .companyQuery(companySearchKeyword)
        .repositoryQuery(repositorySearchKeyword).build();
Intent intentContributorsActivity = 
  Henson.with(getActivity())
        .gotoContributorsActivity().build();
intentContributorsActivity.putExtras(intentContributorsFragment);
startActivity(intentContributorsActivity);

這簡(jiǎn)化了代碼中Activity之間的通信,而無需每次都手動(dòng)指定每個(gè)extra。

  1. Parceler
    Parceler幫助你進(jìn)行對(duì)象序列化。它可以幫助你傳遞任何對(duì)象作為Intent extra,而不會(huì)讓你面對(duì)對(duì)象序列化的煩惱。
    最好的事情是,Icepick,Henson和Dart也能很好地和Parceler一起玩。在我們的應(yīng)用程序示例中,我使用@Parcel注釋了我的Contributor類。這允許我使用Dart傳遞Contributor作為Intent Extra,使我的代碼簡(jiǎn)潔和可讀。

  2. Timber
    當(dāng)我寫代碼的時(shí)候,過不了一會(huì),我總有犯錯(cuò)誤的傾向。通常情況下,這會(huì)導(dǎo)致應(yīng)用程序的意外行為。我需要重現(xiàn)它,這樣我才能解決這個(gè)問題。當(dāng)你知道重現(xiàn)的步驟時(shí),調(diào)試器會(huì)很方便,但是通常情況下,日志也包含了真相!
    在Android中開箱即用的Log類足夠好,因?yàn)榭梢蕴峁┎煌娜罩居涗浖?jí)別,等等。然而,每個(gè)Log.d()語(yǔ)句有兩個(gè)參數(shù);首先是tag,第二是message。99%的時(shí)間里,tag將是this.class.getName(),并且一次又一次地寫會(huì)很煩人。幸運(yùn)的是,使用Timber庫(kù),你只要這樣做:

Timber.d("Informative output that needs to be logged.");

…并且它將為你提供正確的默認(rèn)tag!此外,請(qǐng)記住,你需要在使用之前初始化Timber。查看我已添加調(diào)用的ContributorsApplication.onCreate()代碼:

Timber.plant(new Timber.DebugTree());

這就是正確初始化Timber所有需要做的事情,所有沒有理由你的app不使用Timber。

  1. Dagger和Dagger2
    最后,但并非最不重要的,Dagger和Dagger2庫(kù)在app中管理依賴注入的表現(xiàn)真令人驚嘆。為你處理依賴注入是編寫代碼的超棒做法。你指定應(yīng)用程序的組件以及它們應(yīng)如何相互交互。你可以定義代碼的哪些部分需要其他部件的工作,瞧,這個(gè)庫(kù)將為你初始化子部件,并根據(jù)需要注入它們。你可以檢查示例項(xiàng)目代碼以查看使用示例。
    然而,Dagger和Dagger 2涉及面太廣泛了,所以在這篇文章中我們就不做詳細(xì)解釋了。如果你想從使用Dagger開始,那么有一個(gè)很好的代碼例子,coffee maker,它也得到了優(yōu)秀的注釋支持。

結(jié)論
有很多有趣的Android庫(kù),我在這里只列出了一些。安裝起來相當(dāng)容易,因?yàn)槟阒恍枰付ㄒ蕾囮P(guān)系就可以了。這些都是被積極維護(hù)的項(xiàng)目,所以它們有偉大的文檔。
你要做的就是小心構(gòu)建過程。當(dāng)你開始結(jié)合多個(gè)庫(kù)與注解處理器時(shí),確保使用provided()或annotationprocessor(),而不是在build.gradle中將它們結(jié)合起來。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容