Android中view的更新全部由WindowManager负责。
(1)WindowManager.addView的简单使用:
当我们需要弹出一个全局的Telop是就需要用到WindowManager的addView方法。
mWindowManager =
getSystemService(Context.WINDOW_SERVICE) as WindowManager
mView = View.inflate(this, R.layout.full_layout, null)
mParams.format = PixelFormat.RGBA_8888
mParams.type = Config.WINDOW_TYPE
mParams.flags = (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
or WindowManager.LayoutParams.FLAG_FULLSCREEN
or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
mParams.gravity = Gravity.TOP or Gravity.START
mParams.width = 100
mParams.height = 100
mWindowManager.addView(mView, mParams)
使用此方法需要配合权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
此部分需要用户自动同意允许弹出的Telop浮在其他应用上方。
if (!Settings.canDrawOverlays(this)) {
startActivityForResult(new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName())
), 1);
}
并且非系统级的应用type只能指定。
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
(2)WindowManager.updateViewLayout的简单使用:
根据名称其实现原理就是针对当前View的ViewGroup.LayoutParams进行更新操作。
此部分为同步操作,不建议频繁调用此方法。
aosp源码实现如下:
@Override
public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyTokens(params);
mGlobal.updateViewLayout(view, params);
}
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (mLock) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);
mParams.remove(index);
mParams.add(index, wparams);
root.setLayoutParams(wparams, false);
}
}
(3)removeView与removeViewImmediate的区别:
当我们执行了addView之后Telop执行完毕其功能之后需要消去,此时需要调用WindowManager的消去方法
aosp中提供了removeView与removeViewImmediate两种方法。
其中removeView为异步方法,
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
removeViewImmediate为同步方法。
@Override
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}
ViewImpl的具体实现:
当调用removeView方法时是调用handler的队列进行移除view操作。
当调用removeViewImmediate方法时是直接做移除View操作。
/**
* @param immediate True, do now if not in traversal. False, put on queue and do later.
* @return True, request has been queued. False, request has been completed.
*/
boolean die(boolean immediate) {
// Make sure we do execute immediately if we are in the middle of a traversal or the damage
// done by dispatchDetachedFromWindow will cause havoc on return.
if (immediate && !mIsInTraversal) {
doDie();
return false;
}
if (!mIsDrawing) {
destroyHardwareRenderer();
} else {
Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
" window=" + this + ", title=" + mWindowAttributes.getTitle());
}
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
PS:针对removeViewImmediate API官方提醒:
/**
* Special variation of {@link #removeView} that immediately invokes
* the given view hierarchy's {@link View#onDetachedFromWindow()
* View.onDetachedFromWindow()} methods before returning. This is not
* for normal applications; using it correctly requires great care.
*
* @param view The view to be removed.
*/
public void removeViewImmediate(View view);