android开发之代理Window.Callback
当window接收到外界状态改变的通知时,就会回调其中的相应方法。比如,当用户点击某个控件时,就会回调Window.Callback中的dispatchTouchEvent方法。这个方法可以用来实现全埋点,通过activity.getWindow方法拿到这个activity对应的window对象,再通过window.getCallback方法就可以拿到当前对应的Callback对象,然后我们在代理
·
Window.Callback是window类的一个内部接口。该接口包含了一系列类似于dispatchXXX和onXXX的接口。当window接收到外界状态改变的通知时,就会回调其中的相应方法。比如,当用户点击某个控件时,就会回调Window.Callback中的dispatchTouchEvent方法。
- window.Callback的定义如下:
public interface Callback {
boolean dispatchKeyEvent(KeyEvent var1);
boolean dispatchKeyShortcutEvent(KeyEvent var1);
boolean dispatchTouchEvent(MotionEvent var1);
boolean dispatchTrackballEvent(MotionEvent var1);
boolean dispatchGenericMotionEvent(MotionEvent var1);
boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent var1);
@Nullable
View onCreatePanelView(int var1);
boolean onCreatePanelMenu(int var1, @NonNull Menu var2);
boolean onPreparePanel(int var1, @Nullable View var2, @NonNull Menu var3);
boolean onMenuOpened(int var1, @NonNull Menu var2);
boolean onMenuItemSelected(int var1, @NonNull MenuItem var2);
void onWindowAttributesChanged(LayoutParams var1);
void onContentChanged();
void onWindowFocusChanged(boolean var1);
void onAttachedToWindow();
void onDetachedFromWindow();
void onPanelClosed(int var1, @NonNull Menu var2);
boolean onSearchRequested();
boolean onSearchRequested(SearchEvent var1);
@Nullable
ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback var1);
@Nullable
ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback var1, int var2);
void onActionModeStarted(ActionMode var1);
void onActionModeFinished(ActionMode var1);
default void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) {
throw new RuntimeException("Stub!");
}
default void onPointerCaptureChanged(boolean hasCapture) {
throw new RuntimeException("Stub!");
}
}
-
这个方法可以用来实现全埋点,通过activity.getWindow方法拿到这个activity对应的window对象,再通过window.getCallback方法就可以拿到当前对应的Callback对象,然后我们在代理这个callback对象就可以找到被点击的view对象,并插入埋点代码。
-
案例如下:
package com.mvp.myapplication
import android.annotation.TargetApi
import android.app.Activity
import android.graphics.Rect
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.Window.Callback
import android.view.accessibility.AccessibilityEvent
import android.widget.AdapterView
import android.widget.TextView
import androidx.annotation.Nullable
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private lateinit var tv:TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
this.window.callback = WrapperWindowCallback(this, window.callback)
tv = findViewById(R.id.tv)
tv.setOnClickListener {
Log.e("MainActivity","原始数据")
}
}
}
class WrapperWindowCallback : Window.Callback {
private var callback: Window.Callback? = null
private var activity: Activity? = null
constructor() {}
public constructor(activity: Activity, callback: Callback) : this() {
this.callback = callback
this.activity = activity
}
override fun dispatchKeyEvent(p0: KeyEvent?): Boolean {
return this.callback!!.dispatchKeyEvent(p0)
}
override fun dispatchKeyShortcutEvent(p0: KeyEvent?): Boolean {
return this.callback!!.dispatchKeyShortcutEvent(p0)
}
override fun dispatchTouchEvent(p0: MotionEvent?): Boolean {
dispatchTouchEvent(activity!!, p0!!)
return this.callback!!.dispatchTouchEvent(p0)
}
override fun dispatchTrackballEvent(p0: MotionEvent?): Boolean {
return this.callback!!.dispatchTrackballEvent(p0)
}
override fun dispatchGenericMotionEvent(p0: MotionEvent?): Boolean {
return this.callback!!.dispatchGenericMotionEvent(p0)
}
override fun dispatchPopulateAccessibilityEvent(p0: AccessibilityEvent?): Boolean {
return this.callback!!.dispatchPopulateAccessibilityEvent(p0)
}
override fun onCreatePanelView(p0: Int): View? {
return this.callback!!.onCreatePanelView(p0)
}
override fun onCreatePanelMenu(p0: Int, p1: Menu): Boolean {
return this.callback!!.onCreatePanelMenu(p0, p1)
}
override fun onPreparePanel(p0: Int, p1: View?, p2: Menu): Boolean {
return this.callback!!.onPreparePanel(p0, p1, p2)
}
override fun onMenuOpened(p0: Int, p1: Menu): Boolean {
return this.callback!!.onMenuOpened(p0, p1)
}
override fun onMenuItemSelected(p0: Int, p1: MenuItem): Boolean {
return this.callback!!.onMenuItemSelected(p0, p1)
}
override fun onWindowAttributesChanged(p0: WindowManager.LayoutParams?) {
this.callback!!.onWindowAttributesChanged(p0)
}
override fun onContentChanged() {
this.callback!!.onContentChanged()
}
override fun onWindowFocusChanged(p0: Boolean) {
this.callback!!.onWindowFocusChanged(p0)
}
override fun onAttachedToWindow() {
this.callback!!.onAttachedToWindow()
}
override fun onDetachedFromWindow() {
this.callback!!.onDetachedFromWindow()
}
override fun onPanelClosed(p0: Int, p1: Menu) {
this.callback!!.onPanelClosed(p0, p1)
}
override fun onSearchRequested(): Boolean {
return this.callback!!.onSearchRequested()
}
@Nullable
@TargetApi(23)
override fun onSearchRequested(p0: SearchEvent?): Boolean {
return this.callback!!.onSearchRequested(p0)
}
override fun onWindowStartingActionMode(p0: ActionMode.Callback?): ActionMode? {
return this.callback!!.onWindowStartingActionMode(p0)
}
@Nullable
@TargetApi(23)
override fun onWindowStartingActionMode(p0: ActionMode.Callback?, p1: Int): ActionMode? {
return this.callback!!.onWindowStartingActionMode(p0, p1)
}
override fun onActionModeStarted(p0: ActionMode?) {
this.callback!!.onActionModeStarted(p0)
}
override fun onActionModeFinished(p0: ActionMode?) {
this.callback!!.onActionModeFinished(p0)
}
private fun dispatchTouchEvent(activity: Activity, event: MotionEvent) {
if (event.action == MotionEvent.ACTION_UP) {
val rootView = activity.window.decorView as ViewGroup
val targetVies = getTargetViews(rootView, event) ?: return
for (view in targetVies) {
if (view == null) {
continue
}
Log.e("MainActivity", "埋点数据")
}
}
}
private fun getTargetViewsInGroup(
parent: ViewGroup,
event: MotionEvent,
hitViews: ArrayList<View>
) {
try {
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
val hitChildren: ArrayList<View> = getTargetViews(child, event)
if (hitChildren.isNotEmpty()) {
hitViews.addAll(hitChildren)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun getTargetViews(parent: View, event: MotionEvent): ArrayList<View> {
val targetViews: ArrayList<View> = ArrayList()
try {
if (isVisible(parent) && isContainView(parent, event)) {
if (parent is AdapterView<*>) {
targetViews.add(parent)
getTargetViewsInGroup((parent as ViewGroup), event, targetViews)
} else if (parent.isClickable) {
targetViews.add(parent)
} else if (parent is ViewGroup) {
getTargetViewsInGroup(parent, event, targetViews)
}
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return targetViews
}
private fun isVisible(view: View): Boolean {
return view.visibility == View.VISIBLE
}
private fun isContainView(view: View, event: MotionEvent): Boolean {
val x = event.rawX.toDouble()
val y = event.rawY.toDouble()
val outRect = Rect()
view.getGlobalVisibleRect(outRect)
return outRect.contains(x.toInt(), y.toInt())
}
}
- 缺点
更多推荐
已为社区贡献3条内容
所有评论(0)