子曰: “學而時習之,不亦說乎?”
1. YYYY 和 yyyy 不一樣
以 2019年12月31日 舉例:
yyyy-MM-dd :2019-12-31
YYYY-MM-dd :2020-12-31
相信這個你已經知道了,很多大佬都寫過詳細的講解文章,也可直接看官方說明SimpleDateFormat 。
簡言之:Y 指的是 Week year,表示的是這個周所屬的年份;y 表示的纔是我們日常使用的年份。
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
2. getReadableDatabase 不是以只讀方式打開數據庫
Android 中 getWritableDatabase()
和 getReadableDatabase()
方法都可以獲取到 SQLiteDatabase 實例。
但getReadableDatabase()
並不是以只讀方式打開數據庫,而是先執行getWritableDatabase()
,失敗的情況下才以只讀方式打開數據庫.。
源碼如下:
public synchronized SQLiteDatabase getReadableDatabase() {
// ...
try {
// 執行 getWritableDatabase() , 若出現異常,以只讀方式打開數據庫
return getWritableDatabase();
} catch (SQLiteException e) {
if (mName == null) throw e;
}
SQLiteDatabase db = null;
try {
// ...
// 以只讀方式打開數據庫
db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);
// ...
mDatabase = db;
return mDatabase;
} finally {
// ...
}
}
3. 子線程未必不能更新UI
Android的UI訪問是沒有加鎖的,多線程訪問時並不安全。所以規定只能在UI線程中訪問UI。
負責檢查線程的就是 ViewRootImpl
的 checkThread()
方法:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
然而 ViewRootImpl
的創建在 onResume()
回調之後。那麼在 onResume()
之前,子線程裏也是可以更新 UI 的 。
即使是 ViewRootImpl 創建後,只要不調用 checkThread()
,子線程裏更新也並不會報錯。
然而,大家開發的時候還是不要在子線程更新UI。
4. 代碼 new 的 View 沒有id
Android佈局文件中通過 @+id 的方式,可以在 R文件 中生成對應的一個Int值,用於在運行時保證資源唯一性,但動態在代碼中 new 的 View 沒有 id 。
如果你有需求使用它的id,可以調用 View 的 generateViewId()
方法來生成 id(API17+) ,而非用隨機數產生或手寫一個具體的值。
5. View 的 getContext 返回的未必是Activity
Activity中setContentView時一定是Activity;
通過 new View、View.inflate、LayoutInflater.inflate 這幾種方式添加View,我們傳參時傳的是什麼context, View中的就是什麼Context.
在5.0系統版本以下的手機,且 Activity 是繼承自 AppCompatActivity 的,那麼View的getConext方法,返回的就不是Activity而是TintContextWrapper。
參考博文:https://mp.weixin.qq.com/s/5Xj6O9wV_EnynpdnB5mJ5A (南塵)
6. RemoteViews 和 View 沒啥關係
RemoteViews 提供了一組基礎的操作用於跨進程更新,主要用於通知欄和桌面小部件的開發。從名稱來看,感覺應該是一種遠程的View。其實不然,源碼如下:
public class RemoteViews implements Parcelable, Filter {
// ...
}
總而言之,RemoteViews 就是爲跨進程操作控件而提供一系列方法的一個類。
7. boolean 類型佔幾個字節
Java中 boolean 表示的實際信息是一位:1表示true,0表示false。但是,Java規範 數據類型文檔 沒有精確定義內存中布爾變量的實際大小。
其大小與虛擬機相關,可以肯定的是,不會是 1 個 bit 。 Java 虛擬機的建議如下:
1.boolean 類型被編譯成 int 類型來使用,佔 4 個 byte 。
2.boolean 數組被編譯成 byte 數組類型,每個 boolean 數組成員佔 1 個 byte
參考博文:https://binkery.com/archives/346.html
8. RecyclerView 佈局文件可指定layoutManager跟spanCount
RecyclerView 佈局文件可指定layoutManager跟spanCount
<declare-styleable name="RecyclerView">
<attr name="layoutManager" format="string" />
<attr name="android:orientation" />
<attr name="spanCount" format="integer"/>
<attr name="reverseLayout" format="boolean" />
<attr name="stackFromEnd" format="boolean" />
</declare-styleable>
它的屬性attr裏面可以指定layoutManager,spanCount,orientation的。不必我們在代碼裏設置。
9. 9-patch 圖片是有 padding 的
NinePatchDrawable 圖形是一種可拉伸的位圖,可用作視圖的背景。Android 會自動調整圖形的大小以適應視圖的內容。包含一個額外的 1 像素邊框,必須使用 9.png 擴展名將其保存在項目的 res/drawable/ 目錄下。
線的作用:
左,上:定義允許複製圖片的哪些像素來拉伸圖片。
右,下:定義圖片中允許放置視圖內容的相對區域。
因此,9-patch 圖片可能帶有 padding,如果控件沒有明確設置,圖片的 padding 會作爲控件的 padding 。
所以,有時候,android:padding="0dp"
該寫也是得寫的。
https://developer.android.com/guide/topics/graphics/drawables#nine-patch
10. 硬件加速不是哪裏都能開關
硬件加速,直觀上說就是依賴GPU實現圖形繪製加速。由於 GPU 的引入不僅提高了繪製效率,還由於繪製機制的改變,極大地提高了界面內容改變時的刷新效率。
在 Android4.0 開始默認開啓硬件加速,也可以手動控制打開關閉:
需要注意的是:
硬件加速在Window級只能開不能關;View級只能關不能開。
Application 和 Activity 控制
在 AndroidManifest 文件中 Application 或 Activity 節點添加
android:hardwareAccelerated="true"
Window控制
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
View控制
view.setLayerType(View.LAYER_TYPE_SOFTWARE,null);
查詢是否開啓硬件加速
View.isHardwareAccelerated()
Canvas.isHardwareAccelerated()
參考博文:https://www.jianshu.com/p/9cd7097a4fcf
11. 用 getVisibility() 判斷用戶是否能看見並不好
getVisibility()只判斷它自身是否是顯示狀態。但是如果它的父級不可見呢?
用 isShown()
方法更合適些,會先判斷當前 View 的flag, 然後循環拿到父View,判斷是不是可見。只要有一個是不可見的,就返回false。
源碼如下:
public boolean isShown() {
View current = this;
//noinspection ConstantConditions
do {
if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) {
return false;
}
ViewParent parent = current.mParent;
if (parent == null) {
return false; // We are not attached to the view root
}
if (!(parent instanceof View)) {
return true;
}
current = (View) parent;
} while (current != null);
return false;
}
很多知識點都來自於網上大佬們的博客,有些已經忘記從哪裏看到的了,在此向大佬們致敬!
如果本文對你有所幫助,還望可以點個贊哈~~