SystemUI之快捷設定區域載入過程分析
阿新 • • 發佈:2018-12-30
佈局構成
- 詳細說明,快捷設定區域的佈局是由 StatusBar.java的 makeStatusBarView ()統一載入,通過方法 inflateStatusBarWindow 方法載入佈局 super_status_bar.xml 。
protected void makeStatusBarView() { ...... inflateStatusBarWindow(context);//載入佈局的方法 ...... } protected void inflateStatusBarWindow(Context context) { mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar, null); }
- super_status_bar.xml 中包含 status_bar_expanded.xml
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
- status_bar_expanded.xml 中包含 qs_panel.xml
<FrameLayout android:id="@+id/qs_frame" android:layout="@layout/qs_panel" ...... />
- qs_panel.xml 中 id 為 quick_settings_panel 即為我們所找的那個 SystemUI 上的快捷設定區域控制元件的 id
<com.android.systemui.qs.QSContainerImpl ...... <com.android.systemui.qs.QSPanel android:id="@+id/quick_settings_panel" android:layout_marginTop="@dimen/qs_panel_margin_top" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="0dp" /> ...... </com.android.systemui.qs.QSContainerImpl>
類說明
- QSTileHost : Host的實現,管理 Tile 狀態的變化。用來建立和監聽 Tile 。
- Tunable : 介面,配置變化的回撥。QSTileHost 實現這個介面。
- TunerService :用來監聽各種配置變化。
程式碼控制流程
- 仍然是從 StatusBar.java的makeStatusBarView() 方法開始
protected void makeStatusBarView() {
......
// Set up the quick settings tile panel
View container = mStatusBarWindow.findViewById(R.id.qs_frame);//獲取檢視物件
......
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mIconController);//建立並初始化QSTileHost物件
......
if (qs instanceof QSFragment) {
((QSFragment) qs).setHost(qsh);//給QSFragment(QSPanel)設定QSTileHost物件
mQSPanel = ((QSFragment) qs).getQsPanel();
}
......
}
- 一步步分析,首先先例項化一個 View ( qs_frame 包含一個 QSPanel 檢視)物件,然後再去建立 QSTileHost 物件,然後將 QSTileHost 物件與 QSPanel 檢視物件進行繫結,看一下 QSTileHost 的構造方法。
QSTileHost.java
public QSTileHost(Context context, StatusBar statusBar,
StatusBarIconController iconController) {
mIconController = iconController;
mContext = context;
mStatusBar = statusBar;
......
Dependency.get(TunerService.class).addTunable(this, TILES_SETTING);//使用TunerService去Settings中查詢key為TILES_SETTING的值,即查詢快捷設定選單項
......
}
- 關鍵 Dependency.get(TunerService.class).addTunable(this, TILES_SETTING) ,使用 TunerService 去 Settings 中查詢 key 為 TILES_SETTING 的值,即查詢快捷設定選單項,查詢到的結果通過 onTuningChanged ()方法回撥返回,TunerService 的實現類是 TunerServiceImpl 。
TunerServiceImpl.java
private void addTunable(Tunable tunable, String key) {
......
Uri uri = Settings.Secure.getUriFor(key);
if (!mListeningUris.containsKey(uri)) {
mListeningUris.put(uri, key);
mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
}
// Send the first state.
String value = Settings.Secure.getStringForUser(mContentResolver, key, mCurrentUser);
tunable.onTuningChanged(key, value);//查詢到的結果通過onTuningChanged()方法回撥返回
}
- onTuningChanged 方法的實現在 QSTileHost 中,通過方法 loadTileSpecs 方法將 config.xml 中定義的標籤內容 load 進來,通過 createTile 方法依次根據 xml中 的 String 生成對應的 Tile ,並將 Tile 儲存在成員變數的 mTiles 集合中,最後回撥 onTilesChanged ()方法,通知 QSPanel.java 對快捷設定選項顯示更新。
@Override
public void onTuningChanged(String key, String newValue) {
......
final List<String> tileSpecs = loadTileSpecs(mContext, newValue);//呼叫loadTileSpecs方法將config.xml的內容load進來
......
tile = createTile(tileSpec);//在這裡根據String生成Tile
......
newTiles.put(tileSpec,tile);
......
mTiles.putAll(newTiles);
......
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onTilesChanged();//這裡回撥onTilesChanged()方法,通知StatusBar.java對快捷設定選項顯示更新
}
}
- onTilesChanged ()方法的實現是在 QSPanel.java 中重寫的, setTiles 方法是對 Tile 進行設定和重新整理的重要方法,下面會詳細說明。
@Override
public void onTilesChanged() {
setTiles(mHost.getTiles());//該方法的作用下面會詳細說明
}
- 至此 QSTileHost.java 的構造方法分析完成,然後再回到呼叫處 StatusBar.java 的 makeStatusBarView ()方法繼續分析,其中有一個檢視繫結內容(QSTileHost)的語句(( QSFragment ) qs ). setHost ( qsh ),分析完其中的 qsh ,我們繼續分析檢視 qs 。
QSFragment.java
public void setHost(QSTileHost qsh) {
mQSPanel.setHost(qsh, mQSCustomizer);//實質是將QSPanel和qsh繫結
}
QSPanel.java
public void setHost(QSTileHost host, QSCustomizer customizer) {
mHost = host;
mHost.addCallback(this);
setTiles(mHost.getTiles());
}
- 而其中的 setTiles ()方法是不是很熟悉?它就是之前說到的對 Tile 進行設定和重新整理的重要方法,該方法會先 remove 掉所有的 TileRecord 記錄並移除所有的 tileView ,然後再重新呼叫 addTile ()建立 TileRecord 物件並賦值繫結相應的回撥和點選事件(點選、雙擊、長按)介面,再將其儲存到 ArrayList mRecords 集合中,然後再去 addView ()。
public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {
for (TileRecord record : mRecords) {
mTileLayout.removeTile(record);
record.tile.removeCallback(record.callback);
}
mRecords.clear();
for (QSTile tile : tiles) {
addTile(tile, collapsedView);
}
}
- 重新呼叫 addTile ()建立 TileRecord 物件並賦值繫結相應的回撥和點選事件(點選、雙擊、長按)介面
protected TileRecord addTile(final QSTile tile, boolean collapsedView) {
final TileRecord r = new TileRecord();
r.tile = tile;
r.tileView = createTileView(tile, collapsedView);
final QSTile.Callback callback = new QSTile.Callback() {
@Override
public void onStateChanged(QSTile.State state) {
drawTile(r, state);
}
@Override
public void onShowDetail(boolean show) {
}
@Override
public void onToggleStateChanged(boolean state) {
}
@Override
public void onScanStateChanged(boolean state) {
}
@Override
public void onAnnouncementRequested(CharSequence announcement) {
}
};
r.tile.addCallback(callback);
r.callback = callback;
r.tileView.init(r.tile);
r.tile.refreshState();
mRecords.add(r);
if (mTileLayout != null) {
mTileLayout.addTile(r);//mTileLayout是layout檢視物件
}
return r;
}
- 將添加了Tile的檢視物件新增到總檢視中
protected void setupTileLayout() {
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
R.layout.qs_paged_tile_layout, this, false);
mTileLayout.setListening(mListening);
addView((View) mTileLayout);//把檢視加入view
}
- 至此就完成快捷區域載入顯示的大致流程分析。