Android開發(fā)隨手記
本文是作者在Android開發(fā)實踐中的隨手速記,記錄一些小問題的解決方案和注意事項,持續(xù)更新。
以下是速記內容,若有不嚴謹的地方,望小伙伴們指出。
1.Module 不生成R文件,可嘗試取消對該Module的引用,
取消后AS會再次編譯工程,看看此時能否生成R。
2.Activity theme設置錯誤時,會出現:
java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams
cannot be cast to com.android.internal.widget.ActionBarOverlayLayout$LayoutParams
此時,需要為Activity/Application指定帶ActionBar的系統(tǒng)樣式,或讓自定義的Theme集成自帶ActionBar
的系統(tǒng)樣式,當然也可以改用普通Activity類,而非使用Actionbar的Activity子類。
3.java.lang.IllegalArgumentException: NaN is not a valid double value as per JSON
specification. To override this behavior, use GsonBuilder.
serializeSpecialFloatingPointValues() method.
4.AndroidStudio中引用Module時,Module中同名的資源會被App中的資源替換,
利用這一點可以實現自定義資源而不修改Module。目前只試過String.
5.Dagger 環(huán)境配置(可解決不能生成Dagger類的情況):http://www.itnose.net/detail/6353446.html
http://stackoverflow.com/questions/29562347/how-do-i-configure-intellij-gradle-to-use-dagger-2-0
6.Android TouchDelegate 只能擴展同一個ViewGroup中的一個View的響應范圍。
7.Baidu Map V3.7 MKOfflineMap 下載完成后不可調用destroy方法(也許下載完成后百度在做一些善后事宜),
否則離線地圖可能無法正常使用。另外此版本的MKOLUpdateElement.status永遠為1,不可靠~
8.ART JNI、GC http://developer.android.com/guide/practices/verifying-apps-art.html
9.IDEA更新JDK至1.8(From1.7),編譯代碼時出現:
Error:(18, 6) java: -source 1.3 中不支持注釋
(請使用 -source 5 或更高版本以啟用注釋)
打開Project Structure,在Project欄中找到Project language level,修改成1.3以上版本即可。
10.當為Activity寫了Portrait和LandScape兩種布局時,在布局文件根節(jié)點上添加Tag值,在運行時讀取可區(qū)分Portrait和LandScape。
11.打開應用,使用adb shell dumpsys activity top,可以查看應用Activity的信息,也可以獲取包名。
12.啟動Activity的時候,設置Flag,Intent.setFlags(Intent.Flag_Activity_New_Task|Intent.Flag_Activity_Clear_Task)可以清空BackStack。
13.Context.createPackageContext(pkgName,flags)可以根據包名創(chuàng)建另一個Application的context,前提是二者的shareUserId和Signature要相同,這樣就
兩個應用就會運行在同一個Process中,主應用就可以訪問附屬應用的Resources和Classloader(context.getClassloader.load(className)).安裝在設備中的每一個apk程序,Android系統(tǒng)會給其
分配一個單獨的用戶空間,其中android:shareUserId就是對應一個Linux用戶ID,并且為它創(chuàng)建一個沙箱,以防止與其它應用程序產生影響。用戶ID
在應用程序被安裝到設備中時分配。通過SharedUserid,擁有同一個Userid的多個APK可以配置成運行在同一個進程中,所以默認就是可以互相訪問任
意數據,也可以配置成運行在不同的進程中, 同時可以訪問其APK的數據目錄下的資源(圖片,數據庫和文件),就像訪問本程序的數據一樣。
14.Activity View 層級:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0331/1608.html
15.動態(tài)加載機制:http://blog.csdn.net/jiangwei0910410003/article/details/17679823
16.繼承的壞處:Super方法里引用了可被子類復寫的方法時,該方法也會被子類改寫(調用Super.method也無效)。
17.Android 6.0 File.mkdirs()無效,是因為權限控制,可動態(tài)申請權限:http://stackoverflow.com/questions/32225506/android-6m-permission-issue-create-directory-not-working
18.為一個Resources創(chuàng)建LayoutInflater用于inflate該Resource中的layout,需要Extend ContextThemeWrapper實現一個ResourcesContext,
然后使用 LayoutInflater.from(Context).cloneInContext(ResourceContext);
19.ListView Item中的可點擊控件
20.使用Navigator來導航可以避免Activity相互引用,在Activity中寫獲取啟動它的Intent的方法可以避免對外定義傳參Key。
21.使用android.R.id.content可以獲取Activity的根元素。
22.Java包內外層需要互相引用,沒有內層可以直接使用外層或者外層可以直接使用內層之說。
23.在Java7之前,switch只能支持 byte、short、char、int或者其對應的封裝類以及Enum類型。在Java7中,支持了String。
24.解決動態(tài)加載SurfaceView閃屏問題的兩種方式:一,getWindow().setFormat(PixelFormat.TRANSLUCENT); 二,在布局中添加一個
不可見的SurfaceView。
25.使用Fragment.onActivityCreated()來retrieve view和restore view state。
26.Android 通過Intent.setComponent(new ComponentName(PkgName,ClassName))可以啟動另一個Apk的Activity;通過new
DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)可加載執(zhí)行Jar/Apk中的代碼。
27.ScrollView中內容不足以填充到全屏時,需要添加android:fillViewport="true"來讓ScrollView填滿全屏。
28.Apk的Resource ID信息沒有放在classes.dex中,放在Resources.arsc中?? See:http://blog.csdn.net/luoshengyang/article/details/8744683
和http://blog.csdn.net/luoshengyang/article/details/8806798
29.Android浮點運算:嵌入式處理器通常沒有支持浮點運算,所有對"float"和"double"的運算都是通過軟件
實現的。一些基本的浮點運算,甚至需要毫秒級的時間才能完成。甚至是整數,一些芯片有對乘法的硬件支
持而缺少對除法的支持。這種情況下,整數的除法和取模運算也是由軟件來完成的。所以當你在使用哈希表
或者做大量數學運算時一定要小心謹慎。
30.Git 只clone一個分支:git clone -b <branch> <repo>
31.Java 1.5開始支持靜態(tài)引用,可以直接引用靜態(tài)方法,省略調用靜態(tài)方法時需要寫類名的工作。使用 import static <class>.* 可引入所有靜態(tài)方法。
32.Android Activity中 getApplicationContext!=getBaseContext(),后者是為每個Activity重新創(chuàng)建的一個ContextImpl,Activity本身是一個
ContextThemeWrapper,它依靠ContextImpl來完成實際的工作。
33.Thread的looper和MainThread的MainLooper都是直接new出來的,本質上沒有區(qū)別,啟用了Looper的Thread創(chuàng)建的Handler可以執(zhí)行UI操作
,但是這里的操作如果耗時太久的話(如sleep>100ms),容易崩潰(待驗證,當耗時操作在前易崩潰)。
34.ActivityManager.getRunningTasks(1).get(0).topActivity()可獲取前臺應用的Activity componentName。
35.如果使用Application的Context來bindService,Service就會跟Application的生命周期一樣,而不會受Activity的生命周期影響。如果是用某個
Activity的Context來綁定Service,這個Service的生命周期就受到這個Activity(而非App的其他Activity)的生命周期影響,并且無需調用UnbindService。
36.Exception raised during rendering: com/android/util/PropertiesMap (Details),在渲染預覽界面更改渲染工具版本即可。
37.AndroidStudio Ignore Files:
.idea
.gradle
build/
local.properties
*.iml
38.Android 切圖中不規(guī)則的圖片(兩頭純圓按鈕)或純規(guī)則圖片(純圓,正方形?)無法做.9拉伸,做成Bitmapdrawable(<bitamp/>)可以解決。
39.Android添加懸浮窗顯示,需要使用Application的Context,如若不能顯示在所有應用上層,則需使用Service?
40.SurfaceView黑屏:(1)getWindow().setFormat(PixelFormat.TRANSLUCENT);
41.Gson序列化時排除字段:http://www.tuicool.com/articles/v2eIrqz
42.引入關聯(lián)表來關聯(lián)兩個表之間的關系。
43.Gson 轉換List<T>時,需要使用new TypeToken<List<String>>(){}.getType(),特別注意TypeToken后面的大括號。
44.以文件夾方式隔離用戶數據,將用戶數據(包括數據庫)都放到帶用戶信息的文件夾下面。
45.Android 無法實現不影響后面操作的懸浮操作?
46.使用wait()和notify()時一般是為了同步線程,但是要注意,如果所調用的方法沒有開啟異步線程,可能會直接返回,這時候在方法調用之后
使用的wait()就會一直等待異步回調來notify,然而回調其實早就已經在方法棧中發(fā)生,這樣就會導致線程一直等待。如果開啟了異步線程,那wait()一定會等到notify的到來。
47.Java 使用泛型時,支持自動以泛型的具體類型來命名參數,只要讓泛型對應的參數名與泛型名一樣(不區(qū)分大小寫)就可以做到。
48.Sqlite 查詢?yōu)榭盏淖侄? Field IS NULL, 查詢不為空的字段 Field IS NOT NULL。
49.ImageView tint in xml and setColorFilter 可以對圖片進行著色,可用于改變圖標的顏色,使用PorterDuff.Mode.CLEAR時,還可以隱藏繪制內容。
50.FileOutputStream.getChannel().lock() 可以獲得一個FileLock以鎖定文件。
51.解決Gradle DSL method not found: ‘android()’:刪除Project的build.gradle文件中的:android{}即可。See:http://www.hloong.com/?p=100
52.ListView 的Item中有可點擊元素時,需將可點擊元素的Focusable和FocusableInTouchMode屬性設置為false,并為ListView設置android:descendantFocusability="blocksDescendants"
這樣按鈕和Item都可以點擊。
53.Root 原理:http://www.myhack58.com/Article/html/3/92/2013/36574.htm
54.requestWindowFeature()用來動態(tài)的決定Window的特性,而這個行為發(fā)生在setContentView之前,所以必須要在setContentView之前設置。如request
WindowFeature(Window.FEATURE_NO_TITLE)之后,Window中的DecorView就不會生成TitleView部分,而只生成ContentView部分。
55.Android Style中使用自定義View屬性時,不用加任何命名空間(如android:xxx),直接使用屬性名即可
56.PopupWindow點擊外部消失,只需設置background即可: setBackgroundDrawable(new BitmapDrawable())
57.Sqlite不可在事務中開啟另一個事務,否則這個事務操作無效。
58.new SimpleDateFormat("yyyy-M-d hh:mm").format(date)可以去0。
59.View 在綁定后,從View樹中移除后再添加,綁定的數據依然有效。
60.EditText設置inputType="numberSigned"時可以輸入負數。
61. <item name="android:imeOptions">flagNoExtractUi</item>可禁止輸入法開新界面全屏輸入
62.Sqlite 關聯(lián)查詢:SELECT A.*,B.name FROM Task AS A ,Project AS B WHERE A.Status<='2'
63.Adapter.getItemViewType()返回的Type范圍應該是(0,ItemViewTypeCount]
64.Fatal signal 11 (SIGSEGV), code 0, fault addr 0x61b6 in tid 25110 (RenderThread) 跟硬件加速有關,避免設置
View.setLayerType(View.LAYER_TYPE_HARDWARE, null),出現問題時可在Manifest中禁用硬件加速:<android:hardwareAccelerated="false">
65.NDK_PROJECT_PATH=null,在app/build.gradle的android{}中添加
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir 'src/main/libs'
}
即可解決。
66.計算大數值時容易溢出,最好轉換為大數值類型計算:如long EXPIRE_LOGIN =90* 24 * 60 * 60 * 1000 結果為負數,應改為:
long EXPIRE_LOGIN =90L* 24 * 60 * 60 * 1000;
67.fitsSystemWindows實現沉浸式:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/1122/3712.html
68.app:layout_behavior="@string/bottom_sheet_behavior"
69.Application 中的OnTrimMemory用于系統(tǒng)恢復內存,此時可將一些不重要的內存緩存釋放掉。
70.ImageView adjust to Image,user adjustViewBounds=true and maxWidth/maxHeight of ImageView.
71.<item name="android:windowDrawsSystemBarBackgrounds">false</item> 控制內容是否渲染到底部欄下面
72.Sqlite DISK IOERROR WRITE,是因為臨時目錄問題,可以通過設置之解決問題:
http://blog.csdn.net/u011453773/article/details/50731331
73.Android 調用系統(tǒng)分享:http://stackoverflow.com/questions/30518321/on-android-m-how-to-configure-the-direct-share-capabilities-image-text-an/30721038#30721038
74.獲取Android 的ContentView的容器可以通過它的ID: Window.ID_ANDROID_CONTENT。
75.Java中Object的hashcode返回一個int的hash值。默認情況下,Object中
的hashCode() 返回對象的32位jvm內存地址。也就是說如果對象不重寫該方
法,則返回相應對象的32為JVM內存地址。equals方法返回true的兩個Objec
t應該返回相同的hashcode。所以一般Object的子類在是想equals方法和hashcode
方法的時候,要么同時實現,要么都不實現。這對于鍵值對使用時應該很關
鍵。重寫equals和hashcode時,可以使用IDE提供的方法,安全高效。參考:
https://www.oschina.net/question/82993_75533 同時注意ORM的情況。
76.Collections.synchronizedXXX(),是對所有的傳入對象加了同步鎖。
77.HashMap 操作都是通過數組找鏈表頭結點,key用于hash后找到數組index。
它的containskey也會通過key的hash找到對應鏈表頭結點,然后遍歷,但是containsValue因為不知道
key,無法hash找到index,所以是按數組順序依次遍歷每一個鏈表查找,效率較低。
78.AndroidStudio 編譯報錯: Error:java.lang.NullPointerException
(no error message),刪除工程目錄下.gradle文件,重啟就好。
79.GreenDao局限性:不能兼容模型的繼承關系,無法將父類的字段生成數據庫字段,如果父類和子類都有
都建了表,Dao之間沒有繼承關系。此時可能考慮合并連個表。
80.serialVersionUID 的意義:http://lenjey.iteye.com/blog/513736
81.ScrollView 嵌套GridView或者ListView,可以重寫onMeasure方法,設置
測量高度為最大值,測量模式為AT_MOST,實現跟隨ScrollView滾動。此時如果
遇到布局自動滾動到GridView所在位置,禁用GridView focus即可。
82.HttpUrlConnection 出現EOFException,據說是當響應的InputStream 是 GZIPInputStream時,會造成 HTTP HEAD 的沖突,此處應該是個Bug,原因可以參考以下網址:
https://code.google.com/p/android/issues/detail?id=24672 , 可以通過設置 connection.setRequestProperty( "Accept-Encoding", "" )解決.
83.RecyclerView的Item布局中不能直接使用View,需使用具體的View。否則可能會報CreateViewFromTag Nullpointer。
84.在返回集合的方法中,不建議返回null,而是返回Collections.emptyxxx。
85.List泛型參數的子類和父類的轉化,可以先將待轉換的類轉換為泛型集合,然后賦值給接收者,如A和B ,
其中 B extends A,需要list<B> 轉換為list<A>時 , 可以這樣:
List list=list<b>;
List<A> receiver=list;
也可以直接
用List.class.cast()方法,如:
List<A> receiver=List.class.cast(list<B>);
86.Seekbar滑塊偏上時,同時加上maxHeight和minHeight可以解決,他們是用來指定進度背景高度的。
87.AdapterView中View的狀態(tài)不變化時(應用selector),和處理點擊控件一樣處理即可,關閉focusablity,加上FocusblockDesendants.
88.PNG使用Bitmap.compress壓縮質量時會忽略quality,建議使用webp。
89.四種方式設置Activity跳轉動畫:http://blog.csdn.net/qq_23547831/article/details/51821159
90.XListView 需要設置Adapter才能顯示Header,Footer和上下拉動
91. Dex cannot parse version 52 byte code,需要在App gradle 的android{...}中添加:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
如果有Jack錯誤,還需要在defaultConfig{...}中添加 jackOptions { enabled true }
92.Collections.synchronizedList中所有方法都加了synchronize(mutex){...}同步,除了訪問iterater的方法,需要手動加鎖,請看他們的實現如下:
public ListIterator<E> listIterator() { return list.listIterator(); // Must be manually synched by user } public ListIterator<E> listIterator(int index) { return list.listIterator(index); // Must be manually synched by user }
93.用Gradle為UMeng渠道打包首先你必須在AndroidManifest.xml中的meta-data修改以下的樣子:
<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}" />
然后再App的build.gradle的android{}中添加productFlavors {
YingYongBao {} HuaWei{} productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } }
注意其中渠道名不能以數字開頭。也可以使用第三方PackNG打包,不過它的渠道沒有寫到Manifest中,如果二次簽名會導致丟失。
也可以參考其他不錯的多渠道打包工具,如騰訊企鵝電競開源的Vasdolly,美團的Walle。
94.Gradle讀取local.properties文件,如下讀取簽名配置信息
Properties properties = new Properties() InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream() ; properties.load( inputStream ) //讀取文件 def sdkDir = properties.getProperty('key.file') storeFile file( sdkDir ) //讀取字段 def key_keyAlias = properties.getProperty( 'keyAlias' ) def key_keyPassword = properties.getProperty( 'keyPassword' ) ; def key_storePassword = properties.getProperty( 'storePassword' ) ; storePassword key_storePassword keyAlias key_keyAlias keyPassword key_keyPassword
95.LinearLayout比例布局時,不包含0的weight時,使用0dp才會準確。
96.出現 Bitmap too large to be uploaded into a texture錯誤時,是因為啟用硬件加速后,無法顯示較大的圖片,解決方案三種:
(1)Android:hardwareAccelerated="false"關閉加速
(2)加載圖片時進行壓縮
(3)把大圖分割成小塊加載顯示圖片切片
97.Java 修改常量值,對于基本類型的常量會失效,因為Java編譯優(yōu)化,對于基本類型的靜態(tài)常量,JAVA在編譯的時候就會把代碼中對此常量中引用的地方替換成相應常量值。
98.Android 錄屏命令:adb shell screenrecord /sdcard/demo.mp4
99.synchronized不能用在接口方法和抽象方法的聲明上,但是可以用在實現上。
100.Realm跨平臺的高效數據庫方案。
101.CAS(Compare And Swap):一種在多線程環(huán)境中實現同步的CPU原子指令。它在向內存區(qū)域寫入值時,會先比較該內存區(qū)域現有值,如果值和原先讀到的值不同,
則寫入失敗。這是通過一個原子操作來完成的。原子性保證了值的時效性(最新)。 如果這個值已經被另一個線程更新,那么寫入將會失敗。這個操作必須表明值替換
是否成功:要么用一個Bool表示,要么返回內存區(qū)域現有值(有點兒像樂觀鎖)
102.子線程也可以更新UI:http://www.rzrgm.cn/lao-liang/p/5108745.html
103.git初始化沒有branch時,可以先創(chuàng)建一個文件并commit,然后就會在本地生成master分支,此時push上去就好了。
104.Android style中設置版本兼容的屬性時,需要去掉android:前綴,否則可能無效。
105.Java中遍歷訪問,for是最快的,其次是foreach,再次是Iterator。有趣的是,使用Iterator時,編譯后的class是for循環(huán),例如:
for(Iterator iterator = collection.iterator(); iterator.hasNext(); iterator.remove()) { ... }
106.將WebView嵌套在LinearLayout中使用,有可能加載不了使用Angular或者Vue寫的頁面,最好使用RelativeLayout作為容器.
107.Android M及以上版本,可以使用Settings.canDrawOverlay()判斷是否有懸浮窗權限:
private void checkOverlayPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE); } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == OVERLAY_PERMISSION_REQ_CODE) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { // SYSTEM_ALERT_WINDOW permission not granted... } } } }
108.編譯時出現 ...NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin...等NDK過時等錯誤時,需在
gradle.properties中添加
android.useDeprecatedNdk=true
109.應用在64位手機上加載.so報缺少庫錯誤或者....so is 32-bit instead of 64-bit時(在已有Android項目集成react native也會出現該異常),是因為項目中64位庫不完整,此時需要排除64位庫,讓應用全部加載32位庫即可。過濾庫
需要在app/build.gradle中添加:
ndk { // 此處添加要保留的ABI abiFilters "armeabi-v7a", "x86", 'armeabi' } packagingOptions { // 此處排除掉64的庫 exclude "lib/arm64-v8a/libxxx.so" }
110.TextView 粗體切換:
//android中為textview動態(tài)設置字體為粗體 TextView textView = (TextView)findViewById(R.id.textView); textView .setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); //設置不為加粗 textView.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
111.Gradle全局統(tǒng)一管理依賴,在項目根目錄創(chuàng)建config.gradle文件,在ext中定義依賴和版本:
ext{ android=[ ... compileSdkVersion:23 ... ] dependencies=[ ... "support-v4":'com.android.support:support-v4:23.1.1' ... ] }
然后在項目的build.gradle中添加apply from :“config.gradle”,在app的build.gradle中即可引用配置:
... compileSdkVersion rootProject.ext.android.compileSdkVersion compile rootProject.ext.dependencies["support-v4"] ...
也可以在app的build.gradle中通過ext定義相關配置,然后引用,相當方便。
112.IDA Pro 可將.so反編譯為匯編,如果配上F5插件,選中方法后按F5可以查看對應方法的C/C++源碼。
113.AndroidStudio3.0以下(Gradle3.0以下)中做JNI開發(fā),gradle.properties中添加android.useDeprecatedNdk=true,不需要寫MakeFile,而是直接在build.gradle中配置,如配置引用log庫:
defaultConfig { ndk { ldLibs "log" moduleName "myLib" //生成的so名字 abiFilters "armeabi", "armeabi-v7a", "x86" //輸出指定三種abi體系結構下的so庫。 } }
AS3.0(Gradle3.0)以上,android.useDeprecatedNdk=true已被棄用。需要使用CMake,在CMakeLists.txt中配置(CMakeLists.txt相當于MakeFile),在Build.gradle中:
defaultConfig{ // 使用Cmake工具 externalNativeBuild { cmake { cppFlags "" //生成多個版本的so文件 abiFilters 'arm64-v8a','armeabi-v7a','x86','x86_64' } } }
還需要在android節(jié)點中配置使用CMakeLists.txt:
// 配置CMakeLists.txt路徑 externalNativeBuild { cmake { path "CMakeLists.txt" // 設置所要編寫的c源碼位置,以及編譯后so文件的名字 } }
詳見:http://www.jb51.net/article/129667.htm
114.查看設備支持的ABI,需要使用adb shell 然后從屬性中讀取:
getprop | grep abilist //查看APK支持的ABI,使用aapt: ~ aapt dump badging sample.apk | grep abi //代碼中通過Build.SUPPORTED_ABIS或者手工讀取設備屬性也可以查看設備支持的ABI。
115.AndroidStudio下載SDK源碼后無法關聯(lián),需要在 用戶/用戶名/.AndroidStudio版本號/config/options/jdk.table.xml中編輯對應SDK版本的sourcePath
屬性,指向源碼路徑,然后重啟AS即可。
116.Android JNI內存分配不受系統(tǒng)對單個應用的內存限制制約,可以考慮通過JNI來做需要臨時申請大內存的事情。如加載大圖片。
117.當我們從Launcher啟動一個應用程序時,實際的是在這個應用程序中Action和Category分別被配置為MAIN和LAUNCHER的Activity。
這個Activity最終由ActivityManagerService通知其所在的進程進行啟動工作的,也就是通過ApplicationThread類的成員函數scheduleLaunchActivity開始執(zhí)行
啟動工作的。其它類型的組件的啟動過程也是類似的。
118.Result不能跨Task返回。
119.Application,Activity,Service都直接或間接繼承自ContextWrapper,都會創(chuàng)建自己的Base Context,所以他們的Activity、Service與Application的BaseContext
是不同的,不過 getApplication()==getApplicationContext();
120.Android 5.0啟動或bind服務的Intent只支持顯式聲明了,即依然支持用類名聲明,但是使用Action聲明時,一定要配上PackageName,否則報IllegalArgumentException。
121.正如在Logcat中所見,Android中的進程是以包名命名的,子進程則會追加process指定的名字。判斷進程是否是主進程就可以根據進程名判斷:
public static String getProcessName(Context context, int processId) { ActivityManager manager = (ActivityManager)context.getSystemService("activity"); List<RunningAppProcessInfo> processList = manager.getRunningAppProcesses(); if(processList != null && processList.size() > 0) { Iterator var4 = manager.getRunningAppProcesses().iterator(); while(var4.hasNext()) { RunningAppProcessInfo process = (RunningAppProcessInfo)var4.next(); if(process.pid == processId) { return process.processName; } } } return ""; }
122.Android HoneyComb(3.2)以下對SharedPreferences支持的Context.MODE_MULTI_PROCESS是通過監(jiān)測文件變化重新加載實現的:
if ((mode & Context.MODE_MULTI_PROCESS) != 0 || getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) { // If somebody else (some other process) changed the prefs // file behind our back, we reload it. This has been the // historical (if undocumented) behavior. sp.startReloadIfChangedUnexpectedly(); }
123.J2ME中的getClass().getResourceAsStream在Android中同樣適用,但是需要注意資源存放路徑必須同類文件在一起(也即常用的SRC目錄下。原理相當于類文件加載)。
Bitmap bitmap = BitmapFactory.decodeStream(getClass().getResourceAsStream("/res/drawable/ic_launcher.png"));
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
//但是不能加載drawable-xhdpi這樣的目錄下的資源。
124.實現View的拖動,可以在OnTouchEvent中改變View的LayoutParams,或者調用View的layout方法,還可以使用ViewDragHelper幫助類。
125.Android WakeLock支持四種模式:
//Flag Value CPU Screen Keyboard PARTIAL_WAKE_LOCK On* Off Off SCREEN_DIM_WAKE_LOCK On Dim Off SCREEN_BRIGHT_WAKE_LOCK On Bright Off FULL_WAKE_LOCK On Bright Bright PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TimerService.class.getName()); wakeLock.acquire();
126.華為系列手機上對未在白名單中的應用限制最大廣播注冊數500,超過則報錯java.lang.AssertionError:Register too many Broadcast Receivers,
可通過反射將報名加入到其白名單中。See:https://blog.csdn.net/llew2011/article/details/79054457
127.自定義Gradle plugin,使用Javassist(一個面向Java API編程的字節(jié)碼操作庫)修復第三方SDK代碼問題:https://blog.csdn.net/llew2011/article/details/78540911
128.ThreadLocal的神奇之處在于,它會自動依附于創(chuàng)建它的線程,就算是聲明為靜態(tài)的,依然不會被類共享或者說覆蓋,每個線程訪問到的依然是自己的
定義,這也是它最大的作用――通過它,每個線程訪問同一個ThreadLocal變量得到的是自己的定義。比如Looper的實現中,通過它為每個線程定義了
Looper引用:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
129.Library中使用ButterKnife,需要在項目的Build.gradle中添加
buildscript { repositories { jcenter() mavenCentral() } dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0' } } //同時在Library的Build.gradle中添加 dependencies { compile 'com.jakewharton:butterknife:8.4.0' apt 'com.jakewharton:butterknife-compiler:8.4.0' }
然后在Library的注解中引用id時,要使用R2.id.xx 而非R.id.xx,當然代碼中使用時還得用R.id.xx
130.排除第三方庫中的庫引用:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") { exclude module: 'support-v4'//根據組件名排除 exclude group: 'android.support.v4'//根據包名排除 } }
131.Gradle upload task
ext { PUBLISH_GROUP_ID = 'cn.dev' PUBLISH_ARTIFACT_ID = 'core' PUBLISH_VERSION = android.defaultConfig.versionName } uploadArchives { repositories.mavenDeployer { def deployPath = file(getProperty('aar.deployPath')) repository(url: "file://${deployPath.absolutePath}") pom.project { groupId project.PUBLISH_GROUP_ID artifactId project.PUBLISH_ARTIFACT_ID version project.PUBLISH_VERSION } } }
132.IDEA Project Structer沒有添加NDK Path的地方,直接在local.properties中添加NDK路徑即可。
133.View 不能設置顏色selector為background,否則運行時會報Error inflating錯誤。設置單個顏色為background沒有問題。
134.(實際驗證在xml Preview時生效,在設備上無效,layer-list不能達到縮小icon的目的)通過layer-list可以將已有Icon縮小到指定尺寸,如果有大版本的Icon,需要小Icon時就不用切圖占用空間了,用來在TextView上設置圖標時很有用。
135.RelativeLayout,ConstraintLayout等Flat布局容器在引用依賴anchor時,根據child index遞增不能倒序依賴未聲明的id,即不能使用@id/xx,但是可以使用@+id/xx,否則編譯不過。
136.自定義屬性時,attrs中可以定義取值類型為enum和flags,二者區(qū)別在于enum取值唯一,flags則可以按位或,設置多個值。
137.Merge可以作用于任意的布局(而不僅限于FrameLayout),用于減少多余的相同的容器。
138.不同的編譯版本使用不同的資源,可以分別為不同版本在src中建立文件目錄。默認已有src/main,可以建立src/debug對應debug編譯版本。(驗證代碼、applicationid)
139.使用CardView可以對(圓角)矩形背景增加陰影效果
140.MD 按鈕點擊效果,即波紋效果,將View的背景設置為"?android:attr/selectableItemBackground"或者"?android:attr/selectableItemBackgroundBorderless"即可。也可以使用ripple節(jié)點自定義drawable作為背景實現該效果。
141.View 縮放后原點(即左上角的坐標點)會發(fā)生變化,計算新的原點應該偏移掉縮小的部分的二分之一(比例應該根據動畫中心點計算)。
142.RecyclerView利用payload可以對一個Item做局部刷新,payload用開發(fā)者自己定義,指定不同的payload應該更新的部分,然后在onBindViewHolder(ViewHolderholder, int position, List<Object> payloads)中處理:
@Override public void onBindViewHolder(ViewHolderholder, int position, List<Object> payloads) { if (payloads.isEmpty()) { // payloads 為 空,說明是更新整個 ViewHolder onBindViewHolder(holder, position); } else { int type= (int) payloads.get(0);// 刷新哪個部分 標志位 switch(type){ case 0: contact.userName.setText(mList.get(position).getName());//只刷新userName break; case 1: contact.userId.setText(mList.get(position).getId());//只刷新userId break; case 2: contact.userImg.setImageResources(mList.get(position).getImg());//只刷新userImg break; } } }
143.在onTouch(View v, MotionEvent event)中,event的getX()和get()容易受AXIS_X(Touch中心的屏幕X坐標位置)和AXIS_Y(Touch中心得屏幕Y坐標位置)的影響發(fā)生抖動,特別在平移和縮放View時容易出現,此時使用getRawX()和getRawY()可以避免。
144.TransitionDrawable 可以快捷實現兩張圖片的漸變顯示:第一張圖片漸隱,第二張圖片漸顯,不需要在最后同時顯示時,設置setCrossFadeEnabled(true)即可。
145.FragmentManager保存狀態(tài),View/Fragment保存狀態(tài)(OnSaveInstanceState())。
(1)Activity會在容易被銷毀時調用OnSaveInstanceState(),如應用退回到后臺,Activity啟動了新的Activity,橫豎屏切換等;
(2)使用RatainedFragment,即在Fragment的onCreate()中調用setRetainInstance(true),可以保存Fragment,避免在ConfigChanged過程中重建,跳過onCreate()和onDestroy()。同時還可以用一個NonUI的Fragment來
保存如緩存、線程等無需重建的數據或資源。(See:http://www.rzrgm.cn/kissazi2/p/4116456.html)
(3)View.onSaveInstanceState()可以用來保存View的臨時狀態(tài),如TextView的當前光標位置,ListView的select position等。
146.Sqlite attach 將其他數據庫附加到當前數據庫鏈接,可實現跨庫訪問和操作:http://www.sqlitetutorial.net/sqlite-attach-database/
db.execSQL("ATTACH DATABASE '" + DB_PATH + "' AS " + DB_ALIAS);
newDB.execSQL("DETACH DATABASE " + DB_ALIAS);
147.Sql語句中,REPLACE INTO 實現 insert or update 功能。
148.PRAGMA table_info(TABLE_NAME) 可以返回表結構,官文描述;
// This pragma returns one row for each column in the named table. Columns in the result set include the column name, data type, whether or not the column can be NULL, and the default value for the column. The "pk" column in the result set is zero for columns that are not part of the primary key, and is the index of the column in the primary key for columns that are part of the primary key.
//
// The table named in the table_info pragma can also be a view.
對于Attach的數據庫,需要這樣調用:
PRAGMA DB_ALIAS.table_info(TABLE_NAME)
149.GreenDao支持自定義類型轉換,表中可定義自定義類型的Column,添加并實現Converter轉換成Sqlite類型即可,可參考:http://greenrobot.org/greendao/documentation/custom-types/
@Convert(converter = RoleConverter.class, columnType = String.class) private Role role;
150.View.getHitRect()可以返回View相對于Parent的響應區(qū)域,可用于判斷MotionEvent是否發(fā)生在指定的View上。
151.Glide返回的Bitmap是Immutable bitmap,不能隨意釋放,也不能用于做高斯模糊,如果需要,可以創(chuàng)建一個圖片副本再做效果。
152.GreenDao中StringCondition用來支持更為復雜的查詢,如比較兩個字段的值,下面的例子比較消息讀取時間和消息接收時間:
queryBuilder.where(new WhereCondition.StringCondition(ConversationDao.Properties.LastReadAt.columnName + " < " + ConversationDao.Properties.LastRecvAt.columnName));
153.AsyncTask的任務隊列最多支持128個任務:
private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128);
154.android:process作用于application時,可以為應用(的所有組件)指定一個進程來運行。作用于四大組件時,組件會在指定的進程中運行。它的取值也需要注意,當以":"開頭時,應用將會為指定的組件創(chuàng)建私有進程;當以一個小寫字母開頭時,將會使用以這個命名的全局進程來運行對應的組件,這樣可以允許多個應用使用同一個進程已達到減少資源使用的效果(前提是這些應用共享相同的 Linux 用戶 ID 并使用相同的證書進行簽署)。適用于SDK開發(fā)時使用。
155.android:multiprocess,可作用于activity和provider,用于賦予組件在使用到它的其他進程創(chuàng)建實例的能力。通常用于provider,使得在使用到的進程創(chuàng)建Provider實例而避免IPC操作。
156.ViewPager remove item 或者改變Item內部狀態(tài)后因為View緩存不會實時更新設置顯示異常,最好的辦法是重寫PagerAdapter的getItemPosition方法,對于需要更新的
Item返回PagerAdapter.POSITION_NONE,會促使ViewPager在notifyDatasetChange時為該元素重新生成View,其他元素返回其更新后的位置,為了對效率進行優(yōu)化,可以在Item數據中緩存position,并在改變是更新,這樣在getItemPosition中就可以直接進行返回。對于動態(tài)內容,如媒體播放,在remove后需要重新觸發(fā)一次播放。(如果Remove發(fā)生在PageChange一秒之內,頁面可能體驗不好,可以用Delay來修復)Snippet:
private void removeModel(final BaseMomentPlayModel model) { ... List<BaseMomentPlayModel> list = mMomentList; list.remove(model); int size = list.size(); int position = model.position; for (; position < size; position++) { //Update position. list.get(position).position = position; } //Mark as changed. model.position = PagerAdapter.POSITION_NONE; if (mMoment == model) { mMoment = null; mViewPager.post(new Runnable() { @Override public void run() { //Restart playback setCurrentPage(mViewPager.getCurrentItem(), false); } }); } reattachAdapter(); } @Override public int getItemPosition(@NonNull Object object) { View view = (View) object; BaseMomentPlayModel model = (BaseMomentPlayModel) view.getTag(); return model.position; }
157.用MessageQueue可以實現懶加載方式,封裝需要懶執(zhí)行的任務到IdleHandler,添加到MessageQueue,在空閑的時候便會執(zhí)行
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { //Do something to be lazily done. return false; } });

浙公網安備 33010602011771號