最近一个小伙伴离职,我接手那个他之前负责的App,这是一个很久很久之前的项目了,连那个小伙伴都是半途接手,可想而知代码是多么悠久醇香。最可怕的是产品也是新接手的,时常来问我一些页面上的问题。为了更快低了解整个代码结构以及解决产品的问题,就很有必要很快的定位到每个activity。所以就写了个简单的类:
public class ShowActivityNameCallbacks implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityStarted(Activity activity) {
if (activity == null) {
return;
}
if (activity.getWindow() == null) {
return;
}
if (activity.getWindow().getDecorView() == null) {
return;
}
View decorView = activity.getWindow().getDecorView();
FrameLayout fl = decorView.findViewById(android.R.id.content);
String activityName = activity.getClass().getSimpleName();
DragTextView textView = new DragTextView(activity, null);
textView.setText(activityName);
textView.setTextSize(13);
textView.setTextColor(Color.parseColor("#00A443"));
textView.setPadding(20, 20, 0, 0);
textView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
fl.addView(textView);
}
...
}
效果如下:
展示页面类名功能很简单,就是当每个类启动时,在左上角添加一个textview展示出类名。为了防止挡住UI细节,就让这个textview可以拖动。
View decorView = activity.getWindow().getDecorView();
FrameLayout fl = decorView.findViewById(android.R.id.content);
从这里我们可以看到Activity中DecorView和PhoneWindow的层级关系
- Window 类 位于 /frameworks/base/core/java/android/view/Window.java。该类是一个抽象类,提供了绘制窗口的一组通用API。可以将之理解为一个载体,各种View在这个载体上显示。
- PhoneWindow类 位于/frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindow.java。该类继承于Window类,是Window类的具体实现,即我们可以通过该类具体去绘制窗口。并且,该类内部包含了一个DecorView对象,该DectorView对象是所有应用窗口(Activity界面)的根View。 简而言之,PhoneWindow类是把一个FrameLayout类即DecorView对象进行一定的包装,将它作为应用窗口的根View,并提供一组通用的窗口操作接口。
- DecorView类 该类是PhoneWindow类的内部类。该类是一个FrameLayout的子类,并且是PhoneWindow的子类,该类就是对普通的FrameLayout进行功能的扩展,更确切点可以说是修饰(Decor的英文全称是Decoration,即“修饰”的意思),比如说添加TitleBar(标题栏),以及TitleBar上的滚动条等 。最重要的一点是,它是所有应用窗口的根View 。
想起之前的一个自定义view,在一个页面上加一个对话框蒙层。
fun show(time: Long) {
this.listener = listener
// 解决崩溃问题
if (this.parent != null) {
(this.parent as ViewGroup).removeView(this)
}
// 在当前Activity加入本View
val layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
activity.addContentView(this, layoutParams)
mAnimationView = this@H5LoadingDialog
this.visibility = View.VISIBLE
// 解决点击穿透的问题
this.isClickable = true
...
关键是这一句:
activity.addContentView(this, layoutParams)
其实与上面这两句一样的效果
View decorView = activity.getWindow().getDecorView();
FrameLayout fl = decorView.findViewById(android.R.id.content);
所有上面的代码还可以这样写:
@Override
public void onActivityStarted(Activity activity) {
if (activity == null) {
return;
}
if (activity.getWindow() == null) {
return;
}
if (activity.getWindow().getDecorView() == null) {
return;
}
String activityName = activity.getClass().getSimpleName();
DragTextView textView = new DragTextView(activity, null);
textView.setText(activityName);
textView.setTextSize(13);
textView.setTextColor(Color.parseColor("#00A443"));
textView.setPadding(20, 20, 0, 0);
activity.addContentView(textView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
所有他们的层级关系如下:
层级关系
比如这个:
public abstract class BaseCardView extends FrameLayout {
...
private void inflate() {
rootV = LayoutInflater.from(ctx).inflate(initCardLayout(), this,false);
this.removeAllViews();
this.addView(new CardPlaceHolder(ctx, null));
}
...
网友评论