进阶必备-Android Click事件是如何触发的?

安卓逆向实战:小说App广告去除与VIP功能解锁全流程解析 在Android应用开发与安全领域,逆向工程是深入理解应用内部机制、安全防护与商业化策略的核心技术。其原理在于通过静态与动态分析技术,解析APK文件结构、反编译字节码、监控运行时行为,从而洞察应用逻辑。这项技术的价值不仅在于安全评估与漏洞挖掘,更能帮助开发者强化应用防护,并为技术爱好者提供深入系统底层的学习路径。典型的应用场景包括分析广告集成SDK的实现逻辑、研究应用内购与会员验证机制,以及学习代码混淆与反调试等防护策略。本文以一款流行小说阅读App为例,系统演示了从APK解包、反编译、资源分析到动态调试的 阅读详情

一、背景

阅读本篇文章前,假设你已经阅读前一篇文章。
由于有同学问到onClick和touch事件的关系,这里就从源码的角度分析下onClick和onLongClick与onTouchEvent事件是怎么关联的。本文将通过View.java、TextView.java、Button.java的源码作为例子分析。

二、源码解读

首先我们知道View、TextView、Button三者的关系,即:Button继承自与TextView,TextView继承自View。
在默认我们不做任何特殊设置时,三者能响应click事件的只有Button。这是什么原因呢?

首先我们看到View的源码中onTouchEvent方法中:

final int viewFlags = mViewFlags;

final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
         || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
         || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;

在onTouchEvent方法的一开始,通过viewFlags去判断当前View的CLICKABLE或者LONG_CLICKABLE位是否可以点击或者长按。默认情况下,在View初始化的时候会从xml读clickable属性或者longclickable属性。所以如果不在xml中设置,View和TextView是不会响应点击事件的,那么我们翻开Button的源码看下为什么唯独它是响应的呢?

public Button(Context context, AttributeSet attrs) {
    this(context, attrs, com.android.internal.R.attr.buttonStyle);
}

可以看到在Button初始化的时候,设置了Button的style,我们翻开Styles.xml中找到Button:

    <style name="Widget.Button">
        <item name="background">@drawable/btn_default</item>
        <item name="focusable">true</item>
        <item name="clickable">true</item>
        <item name="textAppearance">?attr/textAppearanceSmallInverse</item>
        <item name="textColor">@color/primary_text_light</item>
        <item name="gravity">center_vertical|center_horizontal</item>
    </style>

没错,Button在默认的Style中就将clickable设置为true了。所以在默认情况下Button的clickable=true。通过下面这行代码(View.java的13743行)就可以知道,当clickable=true时,

if (clickable || (viewFlags & TOOLTIP) == TOOLTIP){
	// 处理逻辑
}

就可以进入if当中继续处理,因为我们响应click事件一般是在我们手按下再抬起后进行。所以,我们猜测是在MotionEvent.ACTION_UP事件后触发click的。所以我们直接看if条件中的ACTION_UP中的逻辑:

    if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
        // This is a tap, so remove the longpress check
        removeLongPressCallback();

        // Only perform take click actions if we were in the pressed state
        if (!focusTaken) {
            // Use a Runnable and post this rather than calling
            // performClick directly. This lets other visual state
            // of the view update before click actions start.
            if (mPerformClick == null) {
                mPerformClick = new PerformClick();
            }
            if (!post(mPerformClick)) {
                performClickInternal();
            }
        }
    }  

在进入处理click之前,会先判断是否已经被长按做了处理,并且此次的ACTION_UP事件没有被忽略掉。当这些条件都满足后,首先会将长按的callback remove。然后会通过Post Runable的方式将PerformClick的实例post到队列中等待处理,不直接去处理click事件而是使用post的方式是确保如果有视图相关的更新操作完成后再触发performClickInternal()。我们先看下PerformClick类是干什么的?

    private final class PerformClick implements Runnable {
        @Override
        public void run() {
            performClickInternal();
        }
    }

很显然就是Runable对象,其中就是调用了performClickInternal()方法,而此方法中调用的是performClick方法:

    public boolean performClick() {
        // We still need to call this method to handle the cases where performClick() was called
        // externally, instead of through performClickInternal()
        notifyAutofillManagerOnClick();

        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

        notifyEnterOrExitForAutoFillIfNeeded(true);

        return result;
    }

可以看到,最后是直接同过ListenerInfo中的mOnClickListener对象调用onClick方法。而ListenerInfo中的mOnClickListener对象就是我们通常使用view.setOnclickListener()方法设置赋值的:

    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        // 赋值操作
        getListenerInfo().mOnClickListener = l;
    }

至此,onClick事件是如何从onTouchEvent中触发的就可以完全看出来了。
同理,onLongClick类似,笔者这里就不做详细分析了。留给读者自己去详细的看下源码,这里简单的介绍下。
onLongClick事件是如何处理的呢?因为onCLick事件是在手指抬起后触发的,所以我们选择分析的是ACTION_UP事件,但是长按事件是在我们长按某个View的时候触发的,所以并没有将手指抬起来。所以我们肯定是在分析处理ACTION_DOWN中处理的。我们查看ACTION_DOWN事件下调用的checkForLongClick方法:

    private void checkForLongClick(int delayOffset, float x, float y) {
        if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) {
            mHasPerformedLongPress = false;

            if (mPendingCheckForLongPress == null) {
                mPendingCheckForLongPress = new CheckForLongPress();
            }
            mPendingCheckForLongPress.setAnchor(x, y);
            mPendingCheckForLongPress.rememberWindowAttachCount();
            mPendingCheckForLongPress.rememberPressedState();
            postDelayed(mPendingCheckForLongPress,
                    ViewConfiguration.getLongPressTimeout() - delayOffset);
        }
    }

我们看到onTouchEvent中的checkForLongClick中在最后一行通过postDelayed延迟发送了一个Runable对象:mPendingCheckForLongPress。延时时间是ViewConfiguration.getLongPressTimeout() - delayOffset的时间差。综上,简单来说,当我们按下屏幕的时候发送了一个延时的Runable,然后等到Runable被执行的时候,在通过一些标志位判断当前是否还满足长按被执行的条件,如果满足,回调listener中的onLongClick。 细节请读者自行对着源码看哦。

三、总结

对于一般的View来讲,onTouchEvent中处理的无非是对View的一个点击事件的处理、按下状态的处理、长按的处理。读者可以对类似于ScrollView这种带滑动的控件的onTouchEvent分析一下,对比于此文中的实现也不太一样哦。

微信搜索公众号:南京Android部落,你想知道的知识点后台回复,我会拿出来一起分析探讨。

Android Jetpack Compose 入门实战:从声明式UI到列表刷新加载 声明式UI是一种现代前端开发范式,它通过描述UI在不同状态下的外观,而非一步步命令式地操作视图对象,来实现界面构建。其核心原理是状态驱动:当应用数据(状态)发生变化时,框架会自动比较新旧UI描述,并高效地更新屏幕上的实际元素,这一过程称为重组。这种模式极大地简化了UI与数据的同步逻辑,减少了因手动更新视图而产生的错误,提升了开发效率和代码可维护性。在Android开发领域,Jetpack Compose 是Google官方推出的现代声明式UI工具包,它基于Kotlin,专为构建原生Android界面而设计。 阅读详情

相关推荐

Android无障碍服务深度解析:从自动化原理到保活实战

在Android系统开发中,自动化测试与系统级交互是提升应用质量和用户体验的关键技术。其核心原理在于通过系统提供的框架接口,实现对UI事件的监听与模拟操作,从而完成预设的自动化流程。这项技术的核心价值在于能够大幅提升测试效率、实现复杂业务流程自动化,并辅助开发无障碍功能应用。在实际应用场景中,它常被用于自动化测试脚本、效率工具开发以及特定场景的流程自动化。本文聚焦于Android系统的AccessibilityService框架,深入探讨其事件监听、节点操作等核心机制,并针对自动化测试中常见的稳定性问题,如

weixin_33938733的博客 391

一文带你了解各种方式实现Android的点击事件

Android中获取到按钮后,我们一般会为其添加点击事件,而android中的点击事件共有四种写法,下面我们通过代码一一去实现。

程序羊的博客 4842

Godot音效管理插件Resonate:事件驱动与对象池技术实战

在游戏开发中,音频系统是提升玩家沉浸感的关键组件。其核心原理是通过高效的资源管理与播放调度,将音频文件转化为实时声波输出。从技术价值看,一个专业的音频管理系统能显著提升游戏性能与可维护性,避免因音频资源加载、播放器实例化带来的卡顿与内存问题。在应用场景上,无论是2D/3D游戏、移动端还是PC平台,都需要应对音效并发播放、分组控制、空间音效等需求。本文以Godot引擎的Resonate插件为例,深入解析如何通过事件驱动架构和对象池技术,构建一个高性能、易扩展的音效管理系统,实现音效播放与游戏逻辑的彻底解耦,并

weixin_34413103的博客 1812

Android自学笔记-5-click事件的四种写法

简单介绍一下Android中click事件的四种写法,使用的工程是上一篇文章修改的,代码如下: [java] view plain copy package com.mxy.dail;    import android.app.Activity;  import android.content.Intent;  import android.net.Uri;  im

tasty 470

机器学习 -- 信用卡评分模型 -- 互联网金融风控

互联网金融主要分为资金类和资产类。资金类主要是理财产品,吸储,主要指标是用户转化、留存和复投,重在客户运营。资产类主要是贷款,包括消费金融和现金贷,小额贷款属于此类,主要目的是用户转化,还款和风险控制,信用卡评分模型就属于风险控制。 信用评分作用是对贷款申请人(信用卡申请人)做风险评估分值的方法。 信用卡评分是以大量数据的统计结果为基础,根据客户提供的资料和历史数据对客户的信用进行评估,评分卡模型...

XiaoMaEr66的博客 2420

【VeriStand】从零构建HIL测试平台:核心概念、硬件选型与实战配置指南

本文详细介绍了如何从零构建HIL测试平台,涵盖核心概念、硬件选型与实战配置指南。重点解析了VeriStand生态系统的优势,包括开箱即用特性、与LabVIEW的黄金搭档配合及Python支持。通过实战案例和硬件选型建议,帮助工程师高效搭建可靠的HIL测试平台,提升测试效率与安全性。

weixin_29250573的博客 329

Android源码分析-点击事件派发机制

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17339857 概述 一直想写篇关于Android事件派发机制的文章,却一直没写,这两天刚好是周末,有时间了,想想写一篇吧,不然总是只停留在会用的层次上但是无法了解其内部机制。我用的是4.4源码,打开看看,挺复杂的,尤其是事件是怎么从Activity派发出来的,太费解了。了...

白雾霾 261

Amber实战:小分子配体MD模拟全流程避坑指南(附磷酸基团处理技巧)

本文提供了一份基于Amber软件进行小分子配体分子动力学模拟的实战避坑指南。详细解析了从晶体结构预处理、配体参数化(重点探讨AM1-BCC与RESP电荷选择)、复合物体系构建到模拟稳定性调试的全流程。特别针对磷酸基团等特殊官能团处理中常见的模拟崩溃问题,给出了系统性的诊断与解决方案,旨在帮助研究者获得稳定可靠的模拟结果。

weixin_29237635的博客 682

Android响应事件onClick方法的四种实现方式

Android onClick方法的四种实现方式

Crazy程序猿 3870

在虚拟机上搭建FTP服务器

chroot_list_file=/etc/vsftpd/chroot_list # 对chroot_list下用户限制。[root@localhost ~]# vim /etc/vsftpd/vsftpd.conf #打开配置文件。# 指定用户的shell: -s /usr/bin/nologin。# 在配置文件中找到以下几行代码, 去掉注释(去掉 "#"号)# 指定用户主目录:/data/ftp/ftpuser -M。(2)修改配置文件,路径/etc/vsftpd/ 下的文件。

weixin_70753380的博客 3211

基于轻量级神经网络MobileNet V2的水果识别种类算法研究

本文阐述了一种基于轻量级卷积神经网络MobileNet V2的水果分类与识别算法研究。为了最大限度地促进机械收获,需要一个检测系统,它可以让我们识别不同类别的水果。一个相对未开发的想法是使用深度学习和人工智能算法,不仅可以检测水果的种类,还可以检测水果是否成熟。这可以证明是有利可图的,因为它可以提供作物生长状况以及成熟和未成熟果实的个体数量,以及决定是否是收获时间的有用信息。第一步对数据进行了预处理,数据预处理技术在众多的深度学习计算中起到了重要作用。

qq_43556680的博客 1641

Android——Click事件实现方式

Android观察者模式(Observer Design Pattern):在对象之间定义⼀个⼀对多的依赖,当⼀个对象状态改变。分别点击 button5,button6,button7,即可看到继承接口1,继承接口2,继承接口3。定义被观察者必须实现的职责, 它必须能够动态地增加、 取消观察者。观察者接收到消息后, 即进⾏update(更新⽅法) 操作, 对接收到的信息进⾏处理。类, 仅仅完成作为被观察者必须实现的职责: 管理观察者并通知观察者。定义被观察者⾃⼰的业务逻辑, 同时定义对哪些事件进⾏通知。

m0_74174723的博客 2027

重磅!AI实时读取总结微信聊天记录,附MCP协议+智能体配置教程!

【摘要】本文介绍了一套AI实时分析微信聊天记录的解决方案,通过Chatlog+Trae+MCP协议实现智能整理群聊信息。Chatlog作为开源工具本地解析微信数据,确保隐私安全;Trae提供AI分析能力,支持自然语言处理。操作步骤包括:1)下载运行Chatlog并启动HTTP服务;2)安装Trae配置MCP协议;3)创建智能体设置提示词。该方案虽需初始配置,但能有效解决群聊信息过载问题,自动提炼关键内容,避免有价值信息被淹没。文中提供了详细教程链接和网盘资源。

puyihuan的博客 1万+

进阶必备-Android Click事件是怎么触发的?

????????关注后回复“进群”,拉你进程序员交流群????????作者丨Bob来源丨IT烂笔头一、背景由于有同学问到onClick和touch事件的关系,这里就从源码的角度分析下o...

<sdffdsfsdfdfs>sfsfsfsdfsdffds</sdfsDS>Fsd 516

Muse Spark:功能、性能测试及使用方法

对于一个仅用九个月时间从零开始重建的团队来说,这样的健康状况和多模态测试结果无疑是迈出了坚实的第一步,并且经受住了独立测试的考验。Muse Spark 为每个产品确定了最重要的主题(A 产品的发布策略、B 产品的定价策略、C 产品的规模化策略),并提出了切实可行的具体行动方案。抽象视觉推理也遵循同样的模式:Muse Spark 的 ARC-AGI-2 得分为 42.5,而 GPT-5.4 和 Gemini 的得分都在 70 分左右。他的离职是由于组织结构的变化限制了他的角色,以及团队转向闭源开发。

xiaoshun007的专栏 124

mongodb在游戏开发领域的优势

目前游戏服务器使用mysql作为数据库的较多,然而,使用mongodb来作为存储层,在某些方面比mysql更为方便和适合。

littleschemer的博客 1700

Android 基础知识4-1 用户界面简介VIewGroup、Onclick事件处理

引言: 一个好的应用界面的必备条件是:内容清楚、指示明白、屏幕美观和有亲切感。界面通常包含图形和文字。应用界面的设计是对控件进行适当的取舍及功能的选择和处理的过程。在程序设计中,需要对设计的方法反复推敲、琢磨,才能使其达到完美。 Android应用程序的基础功能淡单元就是Activity类中的一个对象。Activity可以做很多事,比如界面显示、事件处理等。Android应用程序的界面通常使用View和ViewGroup控件配XML样式来进行设计。而事件则包含按钮点击事件、触屏事

yyxhzdm的博客 648

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

自动化:Python、windows、安卓、网页、rpa、autojs、firerpa(抓包逆向ai)

通过VS安装一步到位更省事。如果这个环境变量是空的,uiautomator 将返回 connect_usb,您需要确保只有一个设备连接到计算机。然后就会自动安装库所需要的设备端程序:uiautomator-server,atx-agent,openstf / minicap,openstf / minitouch。因为 run_main 执行的时候,是打印所有用例文件+名称,而通过测试套件 添加 类名称时,执行方式不一样。也可以使用pyautogui库帮助文档的方法,不过本人认为使用上面的方法,更加便利。

freeking101的博客 2万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Android视频开发必备:精选MP4测试地址与集成实战指南

在Android多媒体开发中,视频播放与下载是核心功能模块,其稳定性和兼容性直接影响用户体验。理解视频编码原理(如H.264/AAC)和网络传输协议是基础,这决定了播放器能否正确解码与渲染。从技术价值看,一个标准、稳定的测试视频源如同“标尺”,能高效隔离业务逻辑问题,验证播放器兼容性、网络加载及解码性能。在实际应用场景中,开发者常面临测试资源匮乏、格式不兼容或网络环境复杂等挑战。本文围绕Android视频开发,提供了多个亲测有效的MP4测试地址,涵盖不同分辨率、编码格式(如包含MP3音频的测试文件)和网络协

792

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

为什么你的AI爬虫总被Cloudflare拦截?camofox-browser来救场

**AI 爬虫总被 Cloudflare 拦截?** camofox-browser 是一个专为 AI 智能体(AI Agent)打造的反检测无头浏览器服务器,基于 Camoufox 引擎在 C++ 层伪造浏览器指纹,轻松绕过 Cloudflare 与机器人检测,可作为 Puppeteer/Playwright 的直接替代品,让 AI 爬虫畅行真实网页。 [![camofox-browser 反

gitblog_00261的博客 783

浏览器开发者工具进阶指南:从调试到性能优化的瑞士军刀

浏览器开发者工具是现代Web开发的核心调试与分析平台,其功能远超基础的DOM检查和日志输出。它基于浏览器引擎与JavaScript运行时,提供了对网络请求、代码执行、内存管理及渲染流程的深度洞察能力。在工程实践中,开发者工具的价值在于将模糊的性能问题转化为可量化的数据,例如通过Network面板分析请求生命周期中的TTFB(首字节时间)与资源加载瓶颈,或利用Performance面板定位导致卡顿的长任务与强制同步布局。这些能力对于优化单页应用性能、排查内存泄漏及保障应用安全至关重要。本文聚焦于开发者工具的高

weixin_33912453的博客 458

Unity Android log view(Android Debug Bridge)

Android Debug Bridge

蛰伏--当你不够强大时,就不要放弃努力 4161

Unity Sprite Renderer点击事件全攻略:从Collider配置到射线检测

在Unity游戏开发中,交互系统是连接玩家与虚拟世界的桥梁。其核心原理是通过射线检测技术,判断用户输入(如鼠标点击或触摸)是否与场景中的特定对象发生交集。这一机制的技术价值在于,它能够将抽象的输入指令转化为具体的游戏逻辑响应,是实现游戏可玩性的基础。在2D游戏开发领域,Sprite Renderer作为最常用的精灵渲染组件,其点击交互的实现却常因Unity中UI系统与物理系统的割裂而成为开发难点。通过合理配置BoxCollider 2D的尺寸、偏移及Is Trigger属性,并正确运用Physics 2D

weixin_33895695的博客 327

FairyGUI中Lambda表达式实现优雅点击事件处理与闭包应用

在Unity UI开发中,事件处理是构建交互逻辑的核心基础,其实现方式直接影响代码的可维护性与可读性。传统基于命名回调的方法绑定模式在复杂UI场景下容易导致代码分散和命名污染,增加维护成本。C#的委托机制为事件处理提供了类型安全的解决方案,而Lambda表达式作为其语法糖,允许开发者以内联方式直接定义事件处理逻辑,大幅减少方法跳转与命名负担。结合闭包特性,Lambda能够捕获外部变量,使得动态UI元素(如列表项中的按钮)能够直接访问其上下文数据,无需通过繁琐的数据查找或自定义组件传递。这一技术组合在Fair

既是过河之卒,惟有奋力向前。 323

QtScrcpy按键映射终极配置指南:从零到精通

QtScrcpy作为一款功能强大的Android实时投屏工具,其自定义按键映射功能让用户能够通过键盘鼠标精准控制移动设备,特别在游戏场景中提供PC级的操作体验。本文将为您提供完整的QtScrcpy按键映射配置方案,帮助您快速掌握这一强大功能。 ## 快速上手:按键映射基础概念 按键映射的核心思想是将PC键盘鼠标操作转换为Android设备的触摸事件。QtScrcpy通过JSON配置文件实现这一

gitblog_00020的博客 929

UI Auto Monkey自动化测试:原理、架构与Python实战

自动化测试是软件质量保障的核心环节,其核心原理是通过脚本模拟用户操作,验证软件功能与稳定性。在UI测试领域,Monkey测试作为一种特殊的自动化测试策略,通过模拟用户的随机、无规律操作,对应用界面进行高强度压力测试,旨在发现常规测试用例难以覆盖的边界异常和隐藏缺陷。其技术价值在于能够有效触发内存泄漏、空指针异常等深层次问题,并检验应用在持续负载下的健壮性。在工程实践中,一个完整的UI Auto Monkey系统通常包含驱动层、事件生成层、状态感知层和调度报告层,通过Python结合uiautomator2、

weixin_30607029的博客 289
上一篇: ConstraintLayout的基本用法及优点
下一篇: Android热修复原理简述
IT烂笔头
博客等级 码龄15年 621粉丝 78原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值