開發
基本方法
-
View# setFocusable()/android:focusable
設定View是否可以聚焦(注意:設定了View不一定可以拿到焦點 具體看這篇深入理解:View和ViewGroup如何才能獲取焦點) -
View# boolean hasFocus()
View是否有焦點,如果是ViewGroup:自身有焦點或者其子View有焦點回傳true,其他回傳false -
View# boolean hasFocusable()
view是否可以聚焦,如果是ViewGroup:自身可以聚焦或者其子View有可以聚焦的回傳true,其他回傳false -
ViewGroup# View getFocusedChild()
ViewGroup方法,獲取當前有焦點或者包含焦點的子View,獲取到的View不一定是當前獲取焦點的View,無法準確獲取真正有焦點的View,
比如:以下xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fl_container"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.tv.FocusTestActivity">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/test_btn"
android:focusable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
</FrameLayout>
焦點實際上在Button上,如果我們呼叫跟布局的FrameLayout的getFocusedChild方法獲取到的是第二層的FrameLayout,
-
View# View findFocus() 尋找實際獲取焦點的View
View方法,查找當前View和其子View中實際獲取焦點的View,如果我們要查找當前頁面獲取焦點的View,我們最好使用DecorView的findFocus方法 -
Window# View getCurrentFocus()
Window方法獲取當前Window聚焦的方法,內部實際上就是呼叫DecorView的findCocus方法在視圖層級去查找,
監聽
-
View# void setOnFocusChangeListener(OnFocusChangeListener listener)
設定View聚焦監聽, -
View# protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
@Nullable Rect previouslyFocusedRect)
View可以重寫監聽焦點變化的方法,
第一個引數:是否獲取焦點了(只有真正獲取焦點了會回呼,viewGroup的子View獲取焦點ViewGroup此方法不回呼)
第二個引數:焦點聚焦的方向 上、下、左、右用于監控焦點來源方向,一般是系統自動找焦點的時候可以看一下這個值,這個值不一定是真實的,因為方向值我可以亂傳
第三個引數:上一個焦點的位置資訊,不一定有, -
ViewTreeObserver# void addOnGlobalFocusChangeListener(OnGlobalFocusChangeListener listener)
監聽當前頁面View樹焦點的變化,如果你找不到焦點的變化情況可以通過這個方法很好用,回呼結果:上一個聚焦的View和當前聚焦的View
使用:
view.getViewTreeObserver().addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
}
});
請求焦點
- boolean requestFocus()
請求焦點,方向默認往下 - boolean requestFocus(int direction)
指定請求方法,請求焦點,取值View.FOCUS_UP、View.FOCUS_DOWN、View.FOCUS_LEFT、View.FOCUS_RIGHT、View.FOCUS_BACKWARD、VIew.FOCUS_FORWARD - boolean requestFocus(int direction, Rect previouslyFocusedRect)
指定請求方法,并指定上一個焦點所在的View的區域資訊(是一個標記功能,可以不用填),請求焦點
通常情況下我們呼叫第一個就可以了,如果明確指定請求焦點的方向后面有處理使用第二個方法,
焦點查找
-
View# View focusSearch(@FocusRealDirection int direction)
在指定方向去查找下一個最近的可以聚焦的View,找不到就回傳null,通過這個方法我們可以知道一個View的指定方向上是否還有可聚焦的View,用于監聽是否到了頁面邊緣, -
FocusFinder類
Android系統提供的查找可聚焦View的方法,系統自動查找焦點也是通過這個類來實作的,開放的方法不多,我們主要用這個方法:
View findNextFocus(ViewGroup root, View focused, int direction)
第一個引數:指定焦點查找范圍,比如我們如果傳遞DecorView,就是在整個View樹中去查找,如果我們傳遞一個指定的ViewGroup,就在這個ViewGroup內去查找,通過這個方法我們可以監聽一個View或者ViewGroup的是否到達可聚焦的邊緣,做一些邊緣抖動的影片等等
第二個引數:當前聚焦的View
第三個引數:查找方向上、下、左、下、前一個、后一個
基本使用:
View nextFocus = FocusFinder.getInstance()
.findNextFocus((ViewGroup) getWindow().getDecorView(),
getWindow().getCurrentFocus(),
View.FOCUS_DOWN);
- View# 指定下一個可聚焦View的id,對應xml屬性就是foucsxxxId
- void setNextFocusDownId(int nextFocusDownId)
- void setNextFocusForwardId(int nextFocusForwardId)
- void setNextFocusUpId(int nextFocusUpId)
- void setNextFocusLeftId(int nextFocusLeftId)
- void setNextFocusRightId(int nextFocusRightId)
當這個View聚焦之后,如果這個View指定了這些id,那么按上、下、左、右按鍵的時候,就會用你指定的可聚焦的View來聚焦,如果指定的不可聚焦,系統就會自動就近去找,
除錯
adb
-
按鍵模擬
- adb shell input keyevent xxxkeyCode
模擬發送指定的keyCode對應的按鍵,具體的KeyCode在KeyEvent這個類可以看到 - adb shell input text a
模擬輸入字符a
- adb shell input keyevent xxxkeyCode
-
查看盒子解析度和dpi資訊
adb shell dumpsys window displays

第一個是盒子初始解析度
第二個是盒子dpi
第三個是盒子當前解析度 -
修改盒子解析度
adb shell wm size 1920x1080 -
修改盒子dpi
adb shell wm density 320 -
adb 連接
adb connect ip:port -
查看所有已安裝應用包名
adb shell pm list packages -
查看所有已安裝應用包名和對應Apk檔案的路徑
adb shell pm list packages -f -
查看指定apk設備安裝路徑
adb shell pm path 應用包名 -
adb啟動開發者選項Activity
adb shell am start com.android.settings/.DevelopmentSettings -
布局邊界(重啟生效)
啟動布局邊界:adb shell setprop debug.layout true
關閉布局邊界:adb shell setprop debug.layout false -
過度繪制檢查(重啟生效)
啟動:adb shell setprop debug.hwui.overdraw show
關閉:adb shell setprop debug.hwui.overdraw false -
查看當前堆疊頂的Activity
adb shell dumpsys activity | grep “mFocus”
apk安裝常見錯誤
- Failure [INSTALL_FAILED_TEST_ONLY]
解決方法:
adb install -t xxxxx.apk
Android Stuido3.0版本打release包在某些設備上可能導致無法安裝
在
gradle.properties中添加以下屬性可杜絕release包無法升級的問題
android.injected.testOnly=false
- Failure [INSTALL_FAILED_ALREADY_EXISTS]
apk包存在導致的問題
解決方法:
adb install -r apk包名
或者
adb uninstall 包名
adb install apk
- Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE]
安裝包版本兼容問題
解決辦法:
adb uninstall 包名
adb install apk
- [INSTALL_FAILED_CONFLICTING_PROVIDER]
手機上存在provider的authorities 相同

應用內換authorities的值,和其他應用沖突只能換authorities值了
其他問題
- 如何替換系統應用
1、使系統可以掛載
adb root
adb remount //使系統可掛載
2、查找系統參考
adb shell
cd system/app 或者 system/priv-app下查找apk
3、洗掉系統應用和應用資料
rm -rf xxxx
rm -rf data/data/應用包名
4、推入我們新的應用
adb push xxxx.apk /system/app 或者 system/priv-app
5、重啟設備生效
adb reboot
不重啟直接安裝會報 Failure [INSTALL_FAILED_ALREADY_EXISTS] 錯誤
- 如何測驗APK是否設定android:debuggable="false"
-
aapt list -v -a apk檔案名 | grep debuggable
得到如下輸出:
A: android:debuggable(0x0101000f)=(type 0x12)0x0
這表示 android:debuggable=”false”aapt命令在sdk/build-tools/版本/xxx
-
Android Studio反編譯打好的apk直接看manifest檔案

-
開發中遇到的坑
- VideoView播放的時候會搶焦點
默認不呼叫requestFocus方法的時候,如果有VideoView,系統會給VideoView焦點,VideoView設定setFocusable(false)是沒有的,解決方法就是給頁面其他可聚焦元素主動呼叫requestFocus方法就可以了,
- 對ViewGroup手動呼叫dispatchKeyEvent方法其中的子View的dispatchKeyEvent方法不觸發
如果ViewGroup不包含焦點,呼叫dispatchKeyEvent不會往子View分發的,解決辦法就是呼叫ViewGroup的requestFocus方法或者呼叫某個子View的requestFocus方法,讓ViewGroup獲得或者包含焦點
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/210043.html
標籤:java
