主頁 > 移動端開發 > 2020年9月,面對“金九銀十”,一個無法跳槽的程式員附答案

2020年9月,面對“金九銀十”,一個無法跳槽的程式員附答案

2021-06-14 07:23:53 移動端開發

面試如作戰,我們看戰爭影視劇的時候,經常看到這些劇作往往主要聚焦于作戰程序、戰場戰略,對戰前準備給的篇幅往往很少,實際上,戰前準備也是關鍵的一環,沒有充足的糧草、車馬、兵器的準備,別說贏得戰爭,投入戰斗都不可能,

這個道理在面試中也是一樣,如果不做面試準備,就猶如不磨刀槍上戰場,勝負更多則靠運氣,尤其是對于剛剛畢業的大學生來說,成功的面試,往往基于充分的準備,充足的準備,有可能做到十發九中,面試一家成一家,

那么面試之前,我們需要做哪些準備,才能做到胸有成竹呢?這個話題將從對于簡歷的準備、對面試公司的了解等方面來說,今天在這里給大家之后的面試提出3個走心的面試建議,希望對大家有幫助,也祝大家面試順利~

經常會有朋友私聊我幫他看下簡歷,發現了一些共性問題;除此以外,我偶爾面試一些同學,有一些個人的感受分享給大家,

寫在前面

一直以來,技術圈里面只要涉及 Android Library 的文章,幾乎都在講如何發布到 Maven/Jcenter,卻很少見到有文章來指導大家如何撰寫一個規范又好用的 Android Library,

這幾年 Android 各式各樣的開源庫層出不窮,國內的很多開發者都慷慨地將自己的一些成果做成開源庫發布出去,然而當我們興致盎然地想去試用一下這些庫的時候,卻時常會遇到“參考”“依賴”“沖突”“API 呼叫”等各種問題,這其中有很多問題,其實是庫的作者本身造成的,

魅族的聯運 SDK 從去年8月份開始立項,10月份開始逐漸有合作伙伴開始接入,經過半年多以來已經有超過50家 cp 應用接入,期間版本僅升級了1次,其余時間一直在穩定運行并尋求新的合作伙伴,在期間我們也收到了很多 cp 應用開發者的反饋,但更多的都表示這個庫接起來非常輕松易上手,這也讓我非常欣慰,

image.png

事實上,我在正式參加作業之前,已經做了2年多時間的個人開發者,這段經歷讓我深刻地體會到了開發者究竟喜歡什么,不喜歡什么,如果每一個 Android Library 的作者在撰寫的時候能夠常去換位思考,多站在接入者的角度審視自己這個庫的設計與實作,那么往往出來的 Android Library 效果都不會差,所以我會在接下來的內容中跟大家分享一些我們的做法,這些做法有一些也是踩了坑之河駁上的,我會把他們寫出來,希望對大家今后的開發作業有所幫助,

規范工程結構

一個規范的 Android Library 工程應該由一個 library模塊與一個demo模塊共同組成,

image.png

demo模塊的好處有兩點:

  1. 方便開發時自己除錯,自己寫的庫,自己寫的程序中就要不停嘗嘗咸淡才能保證“真香”
  2. 庫發布后可以編譯出 apk 供人先行體驗

注意 demo 模塊的 build.gradle 在參考 library 時應該做出區分,如果是 debug編譯模式,則直接參考 library 專案,如果是 release編譯模式,則應該參考你發布的版本,相信 android 開發者都有過“開發除錯的時候好好的,編出來的正式版就有問題”的經歷,使用這樣的參考模式,萬一你發布的庫有問題,則可以在編譯 demo apk 的時候立刻發現,好在 build.gradle 在參考的時候可以很方便做出區分:

        debugImplementation project(':library') //debug 版本直接參考本地專案
        releaseImplementation '遠程庫地址'   //release 版本參考遠程版本用來最終測驗發現問題

指導接入者快速依賴全部 aar

如果你的庫沒辦法發布到 mavenCentral,那么提供 SDK 給別人的時候 可能會有多個 aar 需要對方添加到專案里,我們經常在網上看到一做法,要求接入者在依賴時,先把 aar 檔案拷貝到專案下,然后修改 build.gradle 申明參與編譯,接入者必須仔細看 aar 的名字是什么,因為在 build.gradle 是需要宣告清楚的,

事實上,你的接入者沒有義務去弄清你的 aar 命名,接你的庫已經夠累了,為什么還要人家仔細看你的命名呢?這里推薦一種做法:

  1. 讓你的接入者在他們專案 app 模塊下新建 libs/xxx 目錄,將你們提供的所有 aar拷貝進去,這個 XXX 可以是你們渠道的名字,以后這個下面的 aar 就全是你們的,跟其它的隔離開,
  2. 打開 appbuild.gradle,在根節點宣告:
repositories {
    flatDir {
        dirs 'libs/xxx'
    }
}

3.在 dependencies{} 閉包內添加如下宣告:

//遞回 'libs/xxx` 下所有的 aar 并參考
def xxxLibs = project.file('libs/xxx')
xxxLibs.traverse(nameFilter: ~/.*\.aar/) { file ->
    def name = file.getName().replace('.aar', '')
    implementation(name: name, ext: 'aar')
}

或者,我們可以參考依賴的第一行,直接用下面的代碼一步到位(感謝評論區 @那時年少):

    implementation fileTree(include: ['*.aar'], dir: 'libs/xxx')

這么一來,gradle 在編譯前就會自動進到 xxx 目錄下面,遍歷并參考所有 aar 檔案,之后哪個 aar 有更新,就讓你的接入者直接把新的扔到 XXX 目錄,洗掉老的就行,至于你的 aar前綴是啥,他們根本不用關心,

Kotlin?大膽用!

Google 早在2017年就官宣了 Android 與 Kotlin 的關系,我在這次寫 SDK 的時候最大膽的決定就是全部使用 Kotlin,事實證明我是正確的,Kotlin 的引入幫我省去了大量的膠水代碼,各種語法糖吃起來也是真香,所以從現在起如果你決心造一個輪子,大膽全部使用 Kotlin 來寫吧,但是請注意,因為你的參考者大部還是 Java 程式員,甚至可能還不熟悉 Kotlin,因此一些兼容點還是值得注意的,

參考者的專案必須添加 Kotlin 支持

如果你的庫是 Kotlin 撰寫的,不管用你庫的人是用 Java 調還是 Kotlin,請他們把專案添加 Kotlin 支持,否則在編譯期間沒問題,但在運行期間很有可能遇到NoClassDefError,比如下面這個:

java.lang.NoClassDefFoundError:Failed resolution of: Lkotlin/jvm/internal/Intrinsics

而添加依賴的方法也很簡單:只需要 Android Studio -> Tools -> Kotlin -> Configure Kotlin in project, Android Studio 會自動幫助專案添加依賴插件, Gradle Sync 一下如果沒問題,就搞定了,

伴生物件里需要暴露的 api 請打上 @JvmStatic

已經在寫 Kotlin 的小伙伴應該都清楚,Kotlin 的“靜態方法”、“靜態常量”是靠“伴生物件”來實作的,比如一個簡單的類:

class DemoPlatform private constructor() {
    companion object {
        fun sayHello() {
            //do something
        }
    }
}

這個類如果我想調 sayHello() 方法,在 Kotlin 里非常簡單,直接 DemoPlatform.sayHello()就好,但是如果在 Java 里,就必須使用編譯器自動幫我們生成的 Companion 類,變成 DemoPlatform.Companion.sayHello(),這對于不熟悉 Kotlin 的 Java 程式員來說是很不友好的,盡管 IDE 的提示可能會讓他們自己最終摸索出這個方法,但是面對不熟悉的 Companion 類仍然會一臉懵,所以最佳的做法是給這個方法打上@JvmStatic注解:

        @JvmStatic
        fun sayHello() {
            //do something
        }

這么一來編譯器就會為你這個 Kotlin 方法(Kotlin function)單獨生成一個靜態可直接訪問的 Java 方法(Java method),此時再回到 Java 類里面,你就可以直接 DemoPlatform.sayHello()了,

事實上這個方法 Google 自己也在用,如果你的專案在用 Kotlin,你可以嘗試在代碼樹上右擊 -> New -> Fragment -> Frgment(Blank),讓 Android Studio 自動為我們創建一個 Fragment,我們都知道一個規范的 Fragment 必須包含一個靜態的 newInstance() 方法,來限制傳進來的引數,可以看到 Android Studio 自動幫我們生成的這個方法上面,也有一個 @JvmStatic 注解,

        @JvmStatic
        fun newInstance(param1: String, param2: String) =
                BlankFragment().apply {
                    arguments = Bundle().apply {
                        putString(ARG_PARAM1, param1)
                        putString(ARG_PARAM2, param2)
                    }
                }

很多專案在遷移階段肯定是 Java 與 Kotlin 混調的,而我們作為一個給別人用的 Android Library 就更不用說了,一個小小的注解可以省下接入者的一些學習成本,何樂而不為呢?

Proguard 混淆

自我混淆

如果你的庫僅僅想供人使用,而并沒有打算完全開源,請一定記得打開混淆,在打開之前,把需要完全暴露給呼叫者的方法或者屬性打上@android.support.annotation.Keep注解就行,比如上面的 sayHello()方法,我希望把它暴露出去,那就變成了:

        @Keep
        @JvmStatic
        fun sayHello() {
            //do something
        }

當然了,不僅僅是方法,只要是@Keep注解支持的范圍都可以,如果你還不知道 @Keep注解是咋回事,兄弟你再不補課就真的要失業了,

而啟用混淆的方法也很簡單,在編譯 release 版本的時候把混淆啟用即可,就像這樣:

release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}

這樣一來,呼叫者依賴了你的庫之后,除了你自己暴露的方法或者類,一些內部實作就不那么容易找到了,

把自己的 ProGuard 組態檔打包進 aar

我們經常在一些開源庫的主頁介紹下面看到一段 Proguard 內容,目的是讓呼叫者把他加到自己 app 模塊的 Proguard 組態檔中去,其實 Android 的編譯系統早就支持庫模塊包含自己的 ProGuard 組態檔了,如果你希望你自己庫里的一些代碼,在呼叫者編譯時也不被混淆,可以在自己 library 的 proguard-rules.pro里定義好:

image.png

然后打開 library 的 build.gradle, 在 defaultConfig 閉包里呼叫 consumerProguardFiles() 方法:

    defaultConfig {
        minSdkVersion build_versions.min_sdk
        targetSdkVersion build_versions.target_sdk

        consumerProguardFiles 'proguard-rules.pro'

        ...
    }

加上之后我們可以編譯一次 aar,打開看一下,會發現里面多了一個 proguard.txt檔案,一旦你的庫被依賴,Gradle 會把這個規則與 app 模塊的 Proguard 組態檔 合并后一起運行混淆,這樣一來參考你 library 的人就再也不用擔心混淆配置的問題了,因為你已經完全幫他做好,

image.png

so 檔案

CMake 直接編譯 so 檔案

聯運 SDK 由于涉及支付業務,一些安全相關的作業勢必要放到 C 層去執行,在最開始的時候我也考慮過直接編譯好 so 檔案,讓接入方直接拷貝到 jni 目錄下,事實上國內現在很多第三方庫讓別人接的時候都是這么做的,然而這個做法實在是太不酷了,接入方在操作程序中經常會遇到這幾個問題:

  1. so 名字是什么?
  2. 拷到哪個目錄下面?
  3. build.gradle怎么配?
  4. abi 怎么區分?

好的是,從 Android Studio 2.3 開始,CMake 已經被很好地集成了進來,我們可以在專案里直接添加 C/C++ 的代碼,然后編譯期間動態生成 so 檔案,

關于專案里集成 C/C++ 編譯的方法,網上已經有很多教程了,大家 Google 一下 Android Studio Cmake 就會有很多,當然我最推薦的還是官網教程,或者如果你跟我一樣喜歡動手實踐的話,可以新建一個干凈的 Android Project,然后在向導里勾上 Include C++ Support,最后生成出來的工程就會包含一個簡單的例子,學習起來非常容易,

extern "C" JNIEXPORT jstring JNICALL
Java_your_app_package_name_YourClass_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
class YourClass(private val context: Context) {
    init {
        System.loadLibrary(your-name-lib")
    }
    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    external fun stringFromJNI(): String  //Kotlin 的 external 關鍵字 類似 Java 的 native 關鍵字
}

盡量包含所有 abi,把選擇權交給接入方

在聯運 SDK 上線后的一個月,我們收到 cp 反饋接入了之后有奔潰,后來檢查發現是 armeabi 下沒有 so 檔案導致的,這本沒有什么問題,但是你沒有辦法保證接入方應用的 armeabi 檔案里也是空的,一旦這里面有 so ,android 就會去這里面找;還有一種可能就是現在很多應用會設定 abiFilter 去過濾掉一些 abi,萬一人家只想保留 armeabi,而你的 library 里面又沒有,這兩種情況都會導致 crash,然而:

ndk r16b 已經棄用了 armeabi ,r17c 直接移除了對 armeabi 的支持, 如果有生成 armeabi 的需求只能降低 ndk 版本,(感謝評論區 @我啥時候說啦jj整理指出)

所以為了確保兼容,我們必須在 library 的 build.gradle里手動宣告自己需要編出哪幾個 abi:

    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters 'arm64-v8a', 'armeabi', 'armeabi-v7a', 'x86', 'x86_64'
            }
        }
    }

這么一來你的 library 編出來之后就會包含上面 5 種 abi,確保所有的新老機型起碼都不會崩潰,如果你的接入方嫌你的 so 太多太大了,他自己可以在 app編譯期間設定過濾,“反正我都有,你自己挑吧”,

Resource 資源

庫內部資源的命名不要干擾接入方

相信大家平時開發程序中都有過類似的經歷:一旦引入了一些第三方庫,自己寫代碼的時候,想呼叫某個資源檔案,一按提示,IDE 提示的全是這些第三方庫里面的資源,而自己 app 里面的資源卻要找半天,

我們平時寫庫的時候難免會自己定義一些 Resource 檔案,包括string.xml xxx_layout.xml color.xml 等等,這些庫生成的 R.java 一旦參與 app 的編譯之后,是可以直接被參考到的,所以自然而言也會被 IDE 索引進提示里面,而照常來講,一個應用是不應該直接參考一些第三方庫里面的資源的,搞不好就很容易出現一些問題,比如萬一哪天人家庫升級把這串值改掉了,或者干脆拿掉了,你 app 就跪了,

聯運 SDK 在開發的時候就注意到了這一點,比如我們的 SDK 叫 MeizuLibrarySdk,那么我在定義 strings.xml時,我會寫:

    <string name="mls_hello">你好</string>
    <string name="mls_world">世界</string>

再比如,我需要定義一個顏色,我會在 colors.xml里面寫:

    <color name="mls_blue">#8124F6</color>

相信大家應該已經發現了,每一個資源都會以 mls 開頭,這樣有個好處,就是別人在參考了你的庫之后,用代碼提示的時候,只要看到 mls 開頭的資源,就知道是你庫里面的,不要用,但是這還不夠,因為 Android Studio 還是會在人家寫代碼的時候把你的資源提示出來:

image.png

有沒有一種辦法,來讓 library 開發者可以向 Android Studio 申明自己需要暴露哪些資源,而哪些不希望暴露呢?

當然是有的,我們可以在 library 的 res/values 下面建立一個 public.xml 檔案:

    <!--向 Android Studio 宣告我只希望暴露這個名稱的 string 資源-->
    <public name="mls_hello" type="string" />

這樣依賴,如果你在 app 里面試圖參考 mls_world,Android Studio 就會警告你參考了一個 private 資源,

這個方法的詳細介紹可以看官方檔案:

developer.android.com/studio/proj…

但是不知道為什么,這個方法我在15、16年的時候還是有效的,但是升級到 Android Studio 3.3 + Gradle Plugin 3.1.3 之后我發現 IDE 不會再警告了,也可以通過編譯,不知道這又是什么坑,但官方檔案依舊沒有去掉關于這個用法的描述,估計是插件的一個 bug 吧,

第三方依賴庫

JCenter() 能參考到的,不要打包進你自己里面

本著“不要重復造輪子”的原則,我們在開發第三方庫的時候,自身難免也會依賴一些第三方庫,比如用于決議 json 的 Gson,或者用于加載圖片的 Picasso,這些庫本身都是 jar 檔案的,所以之前會有一些第三方庫的作者在用到這些庫的時候,把對應的 jar 下載到 libs 下面參與編譯,最終編譯到自己的jar或者aar里面,而接入者的專案原可能已經依賴了這些庫,一旦再接入了你的,就會導致錯誤,提示 duplicated class was found

這種做法與 Gradle 的依賴管理機制完全是背道而馳的,正確的原則應該是:

只要第三方應用自己能從 JCenter/MavenCentral 獲取到的庫,如果你的庫也依賴了,請一概使用 compileOnly

舉個例子,比如我的庫里面需要發起網路請求,按照 Google 的推薦,目前最好用的庫應該是 Retrofit 了,這個時候我應該在 library 的 build.gradle 里這樣寫:

    compileOnly "com.squareup.retrofit2:retrofit:2.4.0"

compileOnly 標明后面的庫只會在編譯時有效,但不會你 library 的打包,這么一來,你只需要告訴你的參考者,讓他們在自己 app 模塊的 build.gradle 里加上參考即可,就像這樣:

    implementation "com.squareup.retrofit2:retrofit:$versions.retrofit"

這樣做的好處是,如果參考者的專案本來就已經依賴了 Retrofit,那么皆大歡喜,什么都不用加,并且上面的 $versions.retrofit 意味著參考者可以自己決定他要用哪個版本的 Retrofit,一般來講只要大于等于你編譯庫時用的版本都不會有太大問題,除非 Retrofit 自己大量修改了 API 導致編不過的那種,這么一來就再一次把選擇權交給了你的參考者,既不用擔心沖突,也不用擔心版本跟你用的不匹配,

使用單個檔案統一依賴庫的版本

如果你的專案分了好多模塊,結構比較復雜,我這邊推薦大家使用一個 versions.gradle 檔案來統一所有模塊依賴庫的版本,這一招并不是我原創的,而是 Google 在 architecture-components 的官方 demo 里體現的,這個 demo 的 Project 包含了大量的 module,有 library 有 app,而所有的 module 都需要統一版本的依賴庫,拿 buildToolsVersion 為例,總不能不能你依賴 27.1.1,我依賴 28.0.0 這樣,我把鏈接放在下面,推薦大家都去學習一下這個檔案的寫法,以及它是如何去統一所有 module 的,

github.com/googlesampl…

API 設計

關于 API 設計,由于大家的庫所要實作的功能不一樣,所以沒有辦法具體列舉,但是依然在這里為大家分享一些注意點,其實這些注意點只要能站在接入者的角度去考慮,大多數都能想到,而問題就在于你在寫庫的時候愿不愿意去為你的接入者多考慮一點,

不要在人家的 Application 類里蹦迪

相信暴露一個 init() 方法讓你的呼叫者在 Application 類里做初始化,是很多庫作者喜歡干的事,然而大家反過來想一下,我們都看過很多性能優化的文章,通常第一篇都是讓大家檢查一下自己的 Application 類,有沒有做太多耗時的操作?因為 Application 是你應用起來之后第一個要走的,如果你在里面做了耗時操作了,勢必會推遲 Activity 的加載,然而這一點卻很容易被大家忽略,所以如果你是一個庫的作者,請:

  1. 不要在你的 init() 方法里做任何耗時操作
  2. 更不要提供一個 init() 方法,讓人家放在 Application 類里,還讓人家“最好建議異步”,這跟耍流氓沒區別

統一入口,用一個平臺類去包含所有的功能

這里的平臺類是我自己取的名字,你可以叫 XXXManagerXXXProxyXXXServiceXXXPlatform都可以,把它設計成單例,或者把內部所有的方法寫成靜態方法,不要讓你的呼叫者費勁心思去找應該實體化哪個類,反正所有的方法都在這一個類里面,拿到實體之后呼叫對應的方法即可,這樣統一入口,既降低了維護成本,你的呼叫者也會感謝你,

所有的常量,定義到一個類

if (code == 10012) {
    //do something
}

這個 10012 是什么?是你庫里面定義的回傳碼?那為啥不寫成常量暴露給你的呼叫者呢?

@Keep
class DemoResult private constructor(){

    @Keep
    companion object {
        /**
         * 支付失敗,原因:無法連接網路,請檢查網路設定
         */
        const val CODE_ERROR_CONFIG_ERROR: Int = 10012
        const val MSG_ERROR_CONFIG_ERROR: String = "配置錯誤,請檢查引數"

        ...
    }
}

這樣一寫,你的呼叫者只要點點滑鼠,進來看一下你這個類,就能迅速把錯誤碼跟錯誤提示對應上,懶一點的話,他們甚至可以直接用你定義的這些提示去展現給用戶,而且萬一有一天,服務端的同事告訴你,10012 需要變成別的值,此時你只需要修改你自己的代碼就行,對庫的接入者而言,它依然是 DemoResult.CODE_ERROR_CONFIG_ERROR ,不需要做任何修改,這樣方便接入者的事何樂而不為呢?

幫助接入者檢查傳入引數的合法性

如果你的 API 對傳入的引數有要求,建議在方法執行的第一步就對引數予以檢查,一旦呼叫者傳遞的引數不合法,直接拋例外,有很多開發者覺得拋例外這種行為不能接受,因為畢竟這在 Android 平臺的直接表現就是 app crash,但是于其讓 app 在用戶手里 crash,還不如直接在開發階段 crash 掉讓開發者立刻注意到并且予以修復,

這里以 String 的判空為例,如果你用 Kotlin 來開發,一切都簡單多了,比如我現在有一個物體如下:

data class StudentInfo(val name: String)

一個 StudentInfo 是必須要有一個 name 的,并且我宣告了 name 是不為空的,這個時候如果你在 Kotlin 里面實體化 Student 并且 name 傳空,是直接編譯不過的,而對于 Java 而言,Kotlin 幫我們生成的 class 檔案也已經做好了這一點:

public StudentInfo(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "name");
      super();
      this.name = var1;
   }

繼續看 checkParameterIsNotNull() 方法:

public static void checkParameterIsNotNull(Object value, String paramName) {
        if (value == null) {
            throwParameterIsNullException(paramName);
        }
    }

throwParameterIsNullException()就是一個比較簡單的拋例外了,

private static void throwParameterIsNullException(String paramName) {
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

        // #0 Thread.getStackTrace()
        // #1 Intrinsics.throwParameterIsNullException
        // #2 Intrinsics.checkParameterIsNotNull
        // #3 our caller
        StackTraceElement caller = stackTraceElements[3];
        String className = caller.getClassName();
        String methodName = caller.getMethodName();

        IllegalArgumentException exception =
                new IllegalArgumentException("Parameter specified as non-null is null: " +
                                             "method " + className + "." + methodName +
                                             ", parameter " + paramName);
        throw sanitizeStackTrace(exception);
    }

所以即便你用的是 Java, 試圖直接 Student student = new Student(null),運行時也是會直接 crash 掉并且告訴你 name 不能為空的,聯運 SDK 有大量的引數檢查用了 Kotlin 的這一特性,使得我少些了很多代碼,編譯器編譯后會自動幫我生成,

這里要推薦大家參考一下 android.support.v4.util.Preconditions ,這個里面封裝好了大量的資料型別的情景檢查,原始碼一看就明白,希望大家在寫一個庫的時候,都能做好傳入引數合法性的檢查作業,把問題發現在開發階段,也能確保運行階段不被意外值搞到奔潰,

一些遺憾

到這里,我基本上已經把這次 SDK 開發程序中的經驗與踩過的坑都分享給大家了,當然了,這個世界上沒有完美的事物,目前我們的聯運 SDK 仍然有許多方面的不足,比如:

  1. 沒有發布到 mavenCentral(),需要開發者手動下載 aar 并添加進編譯
  2. SDK 需要依賴 Picasso 來完成圖片加載,這部分功能應該抽象出來,由接入方去用他們自己的方案實作
  3. 我們的 SDK 總共由 7 個 aar 組成,每個 aar 背后都有一個小團隊來專門維護,開發者接入時需要全部復制到一個目錄下,有些冗余跟臃腫

這些不足有些是因為專案初期沒有考慮充分導致,有些是受限于專案架構上的原因導致的,接下來我們會逐一評估,爭取把我們的 SDK 越做越好,同時也歡迎大家在評論區亮出自己在寫 Android Library 時踩過的坑或者分享一些技巧,我會在后面逐步把它更新到文章里來,大家一起努力,造出更多規范的、優秀的輪子,

最后相關資料領取:

點贊+加群免費獲取 Android IOC架構設計

加群 Android IOC架構設計領取獲取往期Android高級架構資料、原始碼、筆記、視頻,高級UI、性能優化、架構師課程、NDK、混合式開發(ReactNative+Weex)微信小程式、Flutter全方面的Android進階實踐技術,群內還有技術大牛一起討論交流解決問題,

最后

最后這里放上我這段時間復習的資料,這個資料也是偶然一位朋友分享給我的,里面包含了騰訊、位元組跳動、阿里、百度2020-2021面試真題決議,并且把每個技術點整理成了視頻和PDF(知識脈絡 + 諸多細節),

還有 高級架構技術進階腦圖、高級進階架構資料 幫助大家學習提升進階,這里我也免費分享給大家也節省大家在網上搜索資料的時間來學習,也可以分享給身邊好友一起學習,

有需要的朋友可以點擊:**Android面試資料**免費領取~

一起互勉~

ive+Weex)微信小程式、Flutter全方面的Android進階實踐技術,群內還有技術大牛一起討論交流解決問題,**

最后

最后這里放上我這段時間復習的資料,這個資料也是偶然一位朋友分享給我的,里面包含了騰訊、位元組跳動、阿里、百度2020-2021面試真題決議,并且把每個技術點整理成了視頻和PDF(知識脈絡 + 諸多細節),

還有 高級架構技術進階腦圖、高級進階架構資料 幫助大家學習提升進階,這里我也免費分享給大家也節省大家在網上搜索資料的時間來學習,也可以分享給身邊好友一起學習,

有需要的朋友可以點擊:**Android面試資料**免費領取~

[外鏈圖片轉存中…(img-pqmri6Vb-1623414771115)]

[外鏈圖片轉存中…(img-FIETe1a2-1623414771116)]

一起互勉~

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/287176.html

標籤:其他

上一篇:Android使用WallpaperService和openGL ES生成的動態圖形設定動態壁紙

下一篇:Android 11.0原始碼系列之IMS(五)InputReader

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more