歡迎光臨
每天分享高質量文章

通用的Android練習專案模板配置「常用工具類,專案結構,模板使用」

本篇文章,作者分享了他做程式碼整理的心得,我非常推薦大家參考作者的做法,擁有自己的程式碼管理倉庫、筆記記錄。

 

包括我也會思考下,如何做程式碼管理,也會借鑒作者的一些做法。

 

很慚愧,自己寫Android好幾年,寫了很多的測試demo,等哪天忽然想找的時候找不到了,又重新新建個專案,從頭開始,非常浪費時間。

剛好github也開放了個人私有的倉庫,配合一波,非常nice。

借本篇文章,希望大家養成好習慣有所幫助~

概述

為什麼會有這篇文章呢,是因為我發現我以前在學習開發知識時,程式碼整理得太不好了。經常是會發生以前學習過的知識,現在卻找不到程式碼在哪裡的情況,於是又要重新開始。

因為Android開發涉及的內容很多,如果想要系統的去整理筆記的話,就必須要分檔案夾,分專案進行管理。每個專案對應著不同方向的知識,而我們很多時候,每個練習專案都有著很多需要重覆配置的東西。

比如常用的依賴啊,工具類,分包啊,還有基本的測試按鈕,比如你想學習資料庫操作,可能就會在xml佈局中書寫4個Button,再寫上id,點選事件…基本上這些弄完,10分鐘過去了。

而我接下來分享的小技巧,可能讓你把原本半小時才能做完的事情,在5分鐘內完成,因為我們會編寫一個練習專案的模板,把重覆的東西抽取出來。

文章不僅僅是為了介紹如何節約時間,更是因為在專案開發中經常要對各種Api進行封裝處理,這也算是一個封裝示例了。

專案採用Java語言,同時提供kotlin語言版本作為小彩蛋,需要說明的是,專案的開發環境是3.1.1,在3.0以下的軟體執行起來需要調整,具體怎麼調整我不告訴你,因為推薦升級軟體。

專案原始碼已經上傳的Github倉庫的template檔案夾內了

https://github.com/13531982270/Blog4

現在,我們建立我們的template專案

建立專案結構

我們建立兩個module,一個是預設的app,一個是appk,一個庫common

 

  • app用來編寫Java測試程式碼

  • appk用來編寫kotlin測試程式碼

  • common庫用於存放一些公共的依賴,工具類

當然,這裡的app和appk並不要求百分百嚴格區分Java和kotlin程式碼,看實際情況,比如你比較多的時間是在使用Java,那麼就在app裡面寫,偶爾也可以在裡面寫些kotlin,這都無所謂。

現在開啟右上角的File-Prokect Structure,我們把common庫的依賴新增到app和appk中,這樣兩個module就能使用Common裡面的東西啦。

App執行庫

完成分包,配置主題,建立Menu選單,drawable-hdpi,color,assets檔案夾操作

1)建立專案的包結構

我們在module下建立以下包

 

然後,我來具體解釋一下每個包的含義(其實看名字也挺清晰的了)

  • adapter   配接器包,用來存放RecyclerView等的配接器

  • app 建立自定義Application,因為後面可能配置很多第三方,而第三方的初始化建議是每個第三方單獨的建立一個單例樣式的類,提供一個init方法去初始化,不然全都寫在Application裡面,Application程式碼會太多,太凌亂,後面會提供一個AppConfig類作為示範,可以使用外掛去生成單例樣式的類,參考我的另一篇文章 https://www.jianshu.com/p/6a3b0ae4aeb4

  • module 業務包,用來存放我們的各種實際練習程式碼,這裡視你的專案是用來做什麼來定,假如你是實際開發,就是一個登入包,一個主頁包,如圖,假如該專案你是用來學習Android原生控制元件,那麼下麵就是imageview,textview這樣子;

  • 還有一個refrence包,這是用來存放你的練習草稿的,怎麼說呢,你在練習的時候如果有什麼需要單獨提取出來測試的,你都可以在裡面建立一個Activity,那個draft.txt也很好理解,就是草稿,你可以把在網上複製的程式碼先放到裡面,後面寫時可以去參考;

  • net包用來存放網路請求相關的類;

  • util包用來存放工具類;

  • view包用來存放用到的自定義控制元件,可能你會有疑問了,實際開發中,view包不是都是放置在Common通用庫裡面的嗎?是的,因為我們實際開發可能會使用元件化,多Module的開發,把view提取到Common通用庫確確實實是為了讓多個module來使用,但是這裡我們只是練習模板專案,如果還要使用元件化那這個模板專案也就太複雜了,不符合我們當初節約時間的初衷,所以這裡直接是,哪個Module的view就放在哪個module。

你可能還會有疑問,你App的包分得都那麼詳細了,那麼還要Common通用庫來做什麼呢?

我是這麼打算的,像下麵舉例子的L工具類,Glide工具類封裝,都屬於專案通用,必備的工具類,那就放在Common庫,這樣後面我們App模組的類不會太多。

而像一些只有在特定業務場景下才會使用達到的util工具類,你就直接放在App模組的util包下就可以了,畢竟工具類實在是太多了。我們不可能將每種都先考慮好放在Common庫,而如果不在App下也設定一個util包,特定業務場景的工具類需要在Common庫來回跳轉就太麻煩了

比如下麵這篇教程https://www.jianshu.com/p/8b7186624ea5 中修改底部導航切換效果的工具類BottomNavigationViewHelper ,Common庫還有的作用就是把經常用到的依賴,不至於使Module的程式碼太多。

2)配置主題和顏色

 

以前自己學習東西建立專案時,很喜歡把主題改成沒有標題的,然後再到建立的Activity裡面去建立幾個Button,寫點選事件去測試,這是多浪費時間的事情啊!

其實我們可以使用預設的主題來解決這個問題(為什麼能解決後面會說),其實預設的主題並不醜,醜的是它的顏色,所以我們到res-values包下的colors檔案,修改一下它的配色

 


<resources>
    <color name="colorPrimary">#008577color>

<color name=“colorPrimaryDark”>#00574Bcolor>
<color name=“colorAccent”>#D81B60color>
resources>

執行程式

 

 

或者更加青春一點的藍色

 

<color name="colorAccent">#cc0094ffcolor>

<color name=“colorPrimary”>#33aaffcolor>
<color name=“colorPrimaryDark”>#2299eecolor>

你看,這樣就好看多了吧

3)建立Menu檔案,實現點選事件

上面已經解決了標題欄醜的問題,可能你還會覺得,預設的帶標題的主題,未免有點佔用我們的螢幕。是的,但是它的標題,卻帶給我們一個平時用的少,但是測試起來用的爽的東西,Menu

我們在res包下建立Menu檔案夾,再建立menu.xml檔案.

 


<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/one"
        android:title="one" />

    <item
        android:id="@+id/two"
        android:title="two" />

    <item
        android:id="@+id/three"
        android:title="three" />

    <item
        android:id="@+id/four"
        android:title="four" />

    <item
        android:id="@+id/five"
        android:title="five" />

    <item
        android:id="@+id/six"
        android:title="six" />
    <item
        android:id="@+id/seven"
        android:title="seven" />

    <item
        android:id="@+id/eight"
        android:title="eight" />
menu>

 

8個按鈕,足夠你一個Activity測試了吧,畢竟比如練習資料庫操作也就是增刪改查,再多的程式碼也不適合放在同一個Activity裡了,後面我們希望看到的,就是點選右邊的..,就可以彈出我們的Menu測試按鈕

 

之後我們在module-refrence包下建立JavaActiivty,將Activity作為第一啟動項,編寫以下程式碼來實現選單的點選事件。

 

public class JavaActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_java);
        setTitle("tonjies的頁面");//設定標題名稱
    }


    //建立選單
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        return true;
    }

    //選單選項
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int i = item.getItemId();
        switch (i) {
            //
            case R.id.one:
                Toast.makeText(this"one", Toast.LENGTH_SHORT).show();
                break;
            //
            case R.id.two:
                Toast.makeText(this"two", Toast.LENGTH_SHORT).show();
                break;
            //
            case R.id.three:
                Toast.makeText(this"three", Toast.LENGTH_SHORT).show();
                break;
            //
            case R.id.four:
                Toast.makeText(this"four", Toast.LENGTH_SHORT).show();
                break;
            //
            case R.id.five:
                Toast.makeText(this"five", Toast.LENGTH_SHORT).show();
                break;
            //
            case R.id.six:
                Toast.makeText(this"six", Toast.LENGTH_SHORT).show();
                break;
            //
            case R.id.seven:
                Toast.makeText(this"seven", Toast.LENGTH_SHORT).show();
                break;
            //
            case R.id.eight:
                Toast.makeText(this"eight", Toast.LENGTH_SHORT).show();
                break;

        }
        return true;
    }
}

執行效果如下,註意到我們onCreate方法裡面的  setTitle(“tonjies的頁面”);

 

如果我們不設定特定的標題,預設的標題名稱就全都是專案名稱,這樣所有的頁面標題都是一樣,不利於區分。所以我們可以透過setTitle設定標題來區分是哪一個介面

 

 

ok,我們已經完美的完成了,可能你會覺得,這樣程式碼量也不少啊,是的,但是它在所有Activity裡面的程式碼都是一樣的啊!

我們需要在哪個Activity用,就直接複製貼上就可以了,其實也不推薦複製貼上的方法,我們有更高效的,使用軟體自己的程式碼模板功能,接下來演示一下該方法

 

使用程式碼模板製作選單.gif

 

程式碼模板具體的製作方法可以檢視慕課網的教程的第三章,第二節

https://www.imooc.com/learn/924

不過實際上我們一般也用不了8個測試按鈕這麼多,我們快捷鍵一般設定4個就夠了,當同時也把8個按鈕的設定了,以防萬一,比圖4個按鈕的快捷鍵是btnMenu,8個按鈕的快捷鍵是btnMenu8這樣。

另外如果你是使用Java程式碼開發,強烈推薦新增一個ButterKnife來節約我們findId控制元件的時間。

 

4)建立drawable-hdpi,color,asstes檔案夾

 

可以將一些大圖放置到比較高解析度的檔案夾下,因為放置在該檔案夾裡面的圖片,多數情況下,如果螢幕解析度較低,系統會幫助你進行一些壓縮處理,避免當你不使用圖片載入框架的時候,ImageView有可能因為圖片過大而導致記憶體上限溢位,程式崩潰。

還有一個原因就是保持程式碼的整潔,我通常是.xml結尾的,例如選擇器,使用shape製作的圖片,vector圖片就放置在drawable,而其它能直接看到的格式的,如,png,jpg,就會放置在drawable-hdpi。

 

我們可以事先防止幾張圖片在模板裡,以備測試的不時之需。

 

 

有時候需要用網路圖片來測試,所以也可以在Common的string.xml檔案夾下新增幾條網路圖片連結

 

<resources>
    <string name="app_name">templatestring>

<string name=“meizi_01”>https://ww1.sinaimg.cn/large/0065oQSqly1fu7xueh1gbj30hs0uwtgb.jpgstring>
resources>

 

而上面的顏色選擇color包可能會在某些場景下用,比如使用BottomNavigationView的時候。

最後是我們的assets檔案夾,用來存放如字型,本地除錯html頁面等,在原始碼裡的Refrence包下會有呼叫字型檔案的參考程式碼。

Common通用庫

該庫用來存放我們練習中幾乎必備的工具類和相關的依賴,我們把這些東西提取在Common包裡面,讓app去新增它,這樣app就不用顯示過多的依賴,顯得比較簡潔,而且我們的appk同樣可以使用它。

1)Log工具類

我們在common庫中建立util檔案夾,然後建立L日誌列印工具類,簡化我們後面的日誌操作:

 

/**
 * Created by 舍長 on 2018/12/14
 * describe: 日誌工具類
 */
public class L {
    public void d(String msg) {
        Log.d("helloWorld", msg);
    }
}

後面就可以直接L.d使用啦。

不過實際專案開發中要再加一個過濾操作,因為我們的App上線之後,如果Log不關閉,有洩漏資料的風險,涉及到安全問題。所以我們可以這樣做。

 

public class L {

    private static final Boolean isOpen=true;

    //普通版
    public static void d(String msg{
        //開啟日誌
        if(isOpen){
            Log.d("helloWorld", msg);
        }else {
            //關閉日誌
        }
    }

    //進行String型別轉換,所以我們可以隨意傳入任意型別的引數
    public static void d(Object msg{
        String string = msg.toString();
        Log.d("helloWorld"string);
    }
}

設定一個變數,如何我們想要列印的話,就設定為true,不想列印的話,就將它設定為Fasle就可以啦,我們還多載了一個引數Object的d方法,該方法的作用是將傳入的任意型別的字串轉換成String型別

這樣做是為了方便我們可以傳入任何型別的資料,這樣我們就可以省去將資料轉成String型別這一步了,

相信這難不倒你啦,接著我們來看第二個封裝類,SharedPreferences封裝類。

 

2)SharedPreferences封裝類ACache

這裡我們需要考慮一個問題,就是SharedPreferences和Log列印不一樣,它是需要獲取到當前的Context物件的,如下麵所示在Activity中使用的getSharedPreferences,其實它隱藏了context的使用,實際程式碼是context.getSharedPreferences。

存資料

 

SharedPreferences.Editor editor=getSharedPreferences("data",MODE_PRIVATE).edit();
editor.putString("name","tonjies");
editor.putInt("age",20);
editor.apply();

取資料

 

SharedPreferences preferences = getSharedPreferences("data", MODE_PRIVATE);
String name = preferences.getString("name""");
int age = preferences.getInt("age"18);
L.d("name:" + name);
L.d("age" + age);

 

你第一個想到的,可能是可以透過引數,將當前Activity的Context物件傳進來進行封裝。

可是這樣每次都要寫個Activity.this,一點都不酷,所以我們使用另外一種方法,封裝統一的全域性Context物件,這在元件化的開發中也很常見,實際操作並不複雜,我們來看一下.

 

我們的Common庫中建立app包,在該包下建立BaseApp類,讓該類繼承於Application,作為我們的基礎Application,然後我們提供一個getContext()方法來傳回Context物件.

3)AGide

封裝思想在開發中應該是很重要的,其中不僅僅是因為我們為了節約時間,更是為了穩妥起見。

舉個例子,我們如果使用圖片載入框架glide,我們並不會直接的去使用它,而是會把它的程式碼寫在一個包裝類裡面,使用包裝類的方法去載入圖片,這樣實際上還是使用glide,那麼這樣有什麼意義呢?

 

/**
 * Created by 舍長 on 2019/1/2
 * describe:Glide封裝類
 */
public class AGlide {
    //獲取Url地址
    public static void getUrl(Context context, String url, ImageView imageView{
        Glide.with(context).load(url).into(imageView);
    }
}

試想這麼一個場景,某一天你因為某些原因,不得不放棄glide,使用另外一個圖片載入框架,那簡直就是災難,因為你程式碼中使用的地方實在是太多了,你要一個個的去註釋,然後改成新的Api,而如果你是使用包裝類,你只要把包裝類裡面的glide程式碼改了就行了,對整個專案並沒有太大的影響:

 

public class AGlide {
    //獲取Url地址
    public static void getUrl(Context context, String url, ImageView imageView) {
//        Glide.with(context).load(url).into(imageView);
        //偽程式碼,這裡假裝使用Picasso的Api
    }
}

工具類部分舉例子結束,除了這些常用的,我們還可以在工具類中封裝Toast工具類啊,字型工具類啊,在原始碼中我會把它兩補上。

 

3)新增常用依賴

 

這裡需要註意的是,3.0以上後,AndroidStudio新增依賴推薦使用api和implementation和替代compile,不然build時就會報紅(雖然還是可以執行)。

implementation和api的區別在於,implementation用於執行Module,api用於庫新增依賴,什麼意思呢,就是如果你在Common庫裡使用implementation來新增依賴,那麼你的AppModule是檢測不到你新增的依賴的。

換句話來說,implementation只能是當它自己的範圍使用,不管你是庫Module還是執行Module,所以如果我們想讓在Common通用庫裡面載入的框架到AppModule執行Module裡能使用的話,得使用api才行。

接下來我們在Common的budile.gradle下新增這幾個依賴:

 

dependencies {
    implementation fileTree(dir: 'libs'include: ['*.jar'])

     //Anko框架,用於kotlin開發擴充套件
    api "org.jetbrains.anko:anko-commons:0.10.7"

    //圓形處理框架
    api 'de.hdodenhof:circleimageview:2.2.0'

    //    材料設計
    api 'com.android.support:design:28.0.0'

    // Retrofit庫
    api 'com.squareup.retrofit2:retrofit:2.4.0'
    api 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'    // 此處一定要註意使用RxJava2的版本
    api 'com.squareup.retrofit2:converter-gson:2.4.0'    // 支援Gson解析

    // Okhttp庫
    api 'com.squareup.okhttp3:okhttp:3.11.0'
    api 'com.squareup.okhttp3:logging-interceptor:3.11.0'

    // 支援Gson解析
    api 'com.squareup.retrofit2:converter-gson:2.4.0'

    //    RxJava
    api 'io.reactivex.rxjava2:rxjava:2.1.7'
    api 'io.reactivex.rxjava2:rxandroid:2.0.1'

    //    圖片載入框架
    api 'com.github.bumptech.glide:glide:4.7.1'

    // 卡片佈局
    api 'com.android.support:cardview-v7:28.0.0'


    implementation 'com.android.support:appcompat-v7:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories {
    mavenCentral()
}

新增常用第三方

 

我們可以選擇使用騰訊bugly進行程式的異常檢測,整合步驟比較簡單,官網檔案非常詳細。

因為也不需要新增程式特定包名,所以我們註冊一個應用,後面就可以一直用同一個ID了。

為什麼要使用它呢,如果是上線應用,就必須使用它來進行異常檢測,不然別的使用者使用出現適配問題了,鬼知道發生了什麼。

但是如果是對於我們學習來說的話,有時候透過AndroidStudio你檢測不出error在哪裡,雖然場景比較少,比如使用RxJava進行封裝的時候,如果是獨立於Actiivty之外的封裝,log檢測不出來。

實際練習程式碼的分類

1)筆記庫的搭建

 

有了上面的專案模板,後面我們需要的話,就可以直接複製,貼上,改個名字就可以直接上手學習了,但是我們的Android開發的內容很多,顯然不是一個專案能放得下的。

所以根據學習內容的不同,我大致將它們分為以下內容,進而我們可以為不同的練習內容設定不同的專案檔案名

 

開發內容 專案英文名 解釋
Java基礎 java 這裡用IDEA
kotlin基礎 kotlin 這裡用IDEA
Android架構,開發規範 framework 如Mvp,mvc,程式碼抽取
Android控制元件 materialDesign Android原生控制元件,和原生有關的介面操作
四大元件 unit 包括Fragment也放在這裡
資料庫儲存 data 資料庫框框架,資料庫操作
Android混合開發 mixed 與H5的互動,ndk開發
開源庫 library 比較小的UI庫,比如PickerView
主流框架 frame 如RxJava,Dagger等
第三方服務 third 友盟,騰訊bugly
業務程式碼 profession 例如多語言切換
系統互動 system 如藍芽,相機,通知欄
Android安全與適配 safety 系統適配方案
你自己的練習專案1
你自己的練習專案2

大致就是這樣,我們複製以上數量的專案檔案夾,更改完名字後,我們的筆記庫到這裡就結束了,也許整個過程是稍顯複雜,但是我們只要製作一次。

後面我們需要找程式碼就方便很多,還有的好處就是如果你上次在某個方面學習到一半,有其他的事情,你下次可以很快的找到,繼續學習。

上面可能你會有個疑問,開源庫和主流框架的區別,其實本質上是沒有區別,但是我去區分它們的標準是,它們是否極其重要,不可替代的,極其重要的,如RxJava,就把它歸納到框架裡面。

而其它的,像提供某個UI控制元件的庫,使用的少,我們可以找到替代的,甚至我們可以自己寫一個的,就會被歸納到庫library裡面。

2)配合筆記軟體

 

上面製作的筆記目錄,不一定適合你,實際上你可以使用筆記軟體,石墨檔案製作屬於你自己的練習專案名稱目錄。

而有一些筆記,也是使用筆記軟體記錄比較合適。簡單來說就是,你的文字筆記目錄和你的練習程式碼倉庫的目錄是一致的。

不過需要註意的是,文字筆記和我們的練習程式碼倉庫一樣,不同類別的筆記是重新建立新的筆記來寫的

這是因為石墨檔案如果你這是同一份檔案寫的內容太多就會卡,這裡我把我的總目錄檔案發現出來作為參考:

 

 

點進去後就是每一類知識的具體筆記。

不過不同類別的檔案都會被放置在Android筆記的檔案夾中:

好了,本篇文章就到這裡了,老實說,這是我寫的30篇文章中感覺寫得最累的一次,因為涉及的東西雖然不難,但是很多,所以很累。但是本篇文章基本都是乾貨,實際運用中,能節約你大量配置專案的時間。

文章並沒有對RxJava和Retrofit的封裝進行詳細的講解,因為這一塊講起來是得花很多的篇幅,不過如果真要說封裝專案模組,它又幾乎是必需的。

再叨一下,例如元件化方案 https://blog.csdn.net/guiying712/article/details/55213884路由框架 https://blog.csdn.net/zhaoyanjun6/article/details/76165252的學習,雖然作為練習專案模組我不想用,但是實際開發用的還是蠻多的,安利,安利。

贊(0)

分享創造快樂