acc--›Android无障碍开发手势操作

2023-05-16

文章目录

  • 前言
  • dispatchGesture `api>=24`
    • GestureDescription
    • GestureResultCallback
    • 执行手势
  • DslAccessibilityGesture
    • click 点击
    • double 双击
    • move 移动
    • fling 快速移动
  • 系列文章
  • 联系作者

前言

无障碍可以执行触屏手势操作,并且非常简单.

函数签名如下api>=24:

android.accessibilityservice.AccessibilityService#dispatchGesture

官方文档地址

dispatchGesture api>=24

GestureDescription

构建手势:

  • 声明一个构造器
val gestureBuilder = GestureDescription.Builder()
  • 创建一个手势
val path = Path()

//如果是点击/双击手势
path.moveTo(x, y)

//如果是移动/快速手势
path.moveTo(fromX, formY)
path.lineTo(toX, toY)

val stroke = GestureDescription.StrokeDescription(path,startTime,duration)

//startTime 手势开始的时间延迟, 毫秒
//duration 手势持续的时间, 毫秒

//如果需要快速滑动效果 duration 设置成一个小值

  • 添加手势
gestureBuilder.addStroke(stroke)

//如果需要双击
val stroke1 = GestureDescription.StrokeDescription(path,startTime,duration)
val stroke2 = GestureDescription.StrokeDescription(path,startTime+60,duration)

gestureBuilder.addStroke(stroke1)
gestureBuilder.addStroke(stroke2)

//构建
gestureBuilder.build()

GestureResultCallback

手势执行回调.

val gestureResultCallback = object : AccessibilityService.GestureResultCallback() {
    override fun onCancelled(gestureDescription: GestureDescription?) {
        super.onCancelled(gestureDescription)
        //手势取消
    }

    override fun onCompleted(gestureDescription: GestureDescription?) {
        super.onCompleted(gestureDescription)
        //手势完成
    }
}

执行手势

dispatchGesture方法必须在主线程调用.

如果未指定Handler, gestureResultCallback默认在主线程回调.

如果上一个手势还未执行完成, 下一个手势就触发了, 则上一个手势会被中断.

如果用户干预了手势执行, 手势也会被中断.

如果在主线程执行手势, 那么主线程卡顿时, 也会影响手势执行的结果.

service.dispatchGesture(gestureBuilder.build(),gestureResultCallback,null)

DslAccessibilityGesture

这里有一份我封装的手势操作类, kotlin语言编写.

typealias GestureResult = (gestureDescription: GestureDescription? /*执行的手势*/, dispatched: Boolean /*是否发送*/, canceled: Boolean /*是否被取消*/) -> Unit

@TargetApi(Build.VERSION_CODES.N)
class DslAccessibilityGesture {

    companion object {

        //开始时间
        const val DEFAULT_GESTURE_START_TIME = 16L

        //点击时长
        const val DEFAULT_GESTURE_CLICK_DURATION = 16L

        //双击间隔时长
        const val DEFAULT_GESTURE_DOUBLE_DURATION = 60L

        //如果Duration时间太短, 将会产生fling
        const val DEFAULT_GESTURE_MOVE_DURATION = 600L
        const val DEFAULT_GESTURE_FLING_DURATION = 30L //值太大, 将没有fling效果
    }

    /**执行回调*/
    var gestureResult: GestureResult? = null

    var startTime: Long = DEFAULT_GESTURE_START_TIME
    var duration: Long = DEFAULT_GESTURE_MOVE_DURATION
    var clickDuration: Long = DEFAULT_GESTURE_CLICK_DURATION
    var doubleDuration: Long = DEFAULT_GESTURE_DOUBLE_DURATION
    var willContinue: Boolean = false

    /**无障碍服务, 用于执行手势*/
    var service: AccessibilityService? = null

    /**
     * 用于构建手势, 支持多指触控
     * [android.accessibilityservice.GestureDescription.getMaxStrokeCount]
     * */
    var _gestureBuilder: GestureDescription.Builder? = null

    var _gestureResultCallback: AccessibilityService.GestureResultCallback? = null

    //是否发送了事件
    var _isDispatched: Boolean = false

    /**是否执行完成*/
    var _isCompleted: Boolean = false

    var _countDownLatch: CountDownLatch? = null

    //是否已经有手势在执行
    var _isDo: Boolean = false

    init {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            _gestureResultCallback = object : AccessibilityService.GestureResultCallback() {
                override fun onCancelled(gestureDescription: GestureDescription?) {
                    super.onCancelled(gestureDescription)
                    L.d("手势取消:$gestureDescription ${gestureDescription?.strokeCount ?: 0}".apply {
                        //AutoParseInterceptor.log(this)
                    })
                    _isCompleted = false
                    gestureResult?.invoke(gestureDescription, true, true)
                    clear()
                }

                override fun onCompleted(gestureDescription: GestureDescription?) {
                    super.onCompleted(gestureDescription)
                    L.d("手势完成:$gestureDescription ${gestureDescription?.strokeCount ?: 0}".apply {
                        //AutoParseInterceptor.log(this)
                    })
                    _isCompleted = true
                    gestureResult?.invoke(gestureDescription, true, false)
                    clear()
                }
            }
        }
    }

    fun clear() {
        _isDo = false
        _isDispatched = false
        _gestureBuilder = null
        gestureResult = null
        _countDownLatch?.countDown()
        _countDownLatch = null
    }

    /**开始执行手势*/
    fun doIt(): Boolean {
        if (_isDo) {
            return false
        }
        _isDispatched = false
        _isCompleted = false
        val service = service
        val builder = _gestureBuilder
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && service != null && builder != null) {
                //设备支持手势
                _isDo = true
                return if (isMain()) {
                    _isDispatched = service.dispatchGesture(
                        builder.build(),
                        _gestureResultCallback,
                        null
                    )
                    L.w("派发手势:$_isDispatched")
                    _isDispatched
                } else {
                    MainExecutor.execute {
                        _isDispatched = service.dispatchGesture(
                            builder.build(),
                            _gestureResultCallback,
                            null
                        )
                        L.w("派发手势:$_isDispatched")
                    }
                    _countDownLatch = CountDownLatch(1)
                    _countDownLatch?.await()
                    _isCompleted
                }
                //AutoParseInterceptor.log("派发手势:$_isDispatched")
            } else {
                //设备不支持手势
                gestureResult?.invoke(null, false, true)
                //AutoParseInterceptor.log("设备不支持手势")
                L.w("设备不支持手势")
                return true
            }
        } catch (e: Exception) {
            clear()
            e.printStackTrace()
            L.w("手势异常${e.stackTraceToString()}")
            return false
        }
    }

    fun ensureBuilder(action: GestureDescription.Builder.() -> Unit) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (_gestureBuilder == null) {
                _gestureBuilder = GestureDescription.Builder()
            }
            _gestureBuilder?.action()
        }
    }

    //<editor-fold desc="操作方法">

    fun moveDuration(
        startTime: Long = DEFAULT_GESTURE_START_TIME,
        duration: Long = DEFAULT_GESTURE_MOVE_DURATION
    ) {
        this.startTime = startTime
        this.duration = duration
    }

    fun flingDuration(
        startTime: Long = DEFAULT_GESTURE_START_TIME,
        duration: Long = DEFAULT_GESTURE_FLING_DURATION
    ) {
        this.startTime = startTime
        this.duration = duration
    }

    fun doubleDuration(
        startTime: Long = DEFAULT_GESTURE_START_TIME,
        duration: Long = DEFAULT_GESTURE_CLICK_DURATION,
        doubleDuration: Long = DEFAULT_GESTURE_DOUBLE_DURATION
    ) {
        this.startTime = startTime
        this.duration = duration
        this.doubleDuration = doubleDuration
    }

    /**点击*/
    fun touch(
        fromX: Float, fromY: Float,
        startTime: Long = this.startTime,
        duration: Long = this.clickDuration
    ) {
        touch(PointF(fromX, fromY), startTime, duration)
    }

    /**点击*/
    fun touch(fromX: Int, fromY: Int) {
        touch(Point(fromX, fromY))
    }

    /**点击*/
    fun touch(
        point: PointF,
        startTime: Long = this.startTime,
        duration: Long = this.clickDuration
    ) {
        touch(Path().apply {
            moveTo(point.x, point.y)
        }, startTime, duration)
    }

    /**点击*/
    fun touch(point: Point) {
        touch(PointF(point))
    }

    /**移动*/
    fun touch(
        fromX: Float,
        fromY: Float,
        toX: Float,
        toY: Float,
        startTime: Long = this.startTime,
        duration: Long = this.clickDuration
    ) {
        touch(Path().apply { moveTo(fromX, fromY);lineTo(toX, toY) }, startTime, duration)
    }

    /**移动*/
    fun touch(fromX: Int, fromY: Int, toX: Int, toY: Int) {
        touch(fromX.toFloat(), fromY.toFloat(), toX.toFloat(), toY.toFloat())
    }

    /**双击*/
    fun double(fromX: Float, fromY: Float) {
        double(PointF(fromX, fromY))
    }

    /**双击*/
    fun double(fromX: Int, fromY: Int) {
        double(fromX.toFloat(), fromY.toFloat())
    }

    /**双击*/
    fun double(point: PointF) {
        //双击, 需要伴随MOVE事件, 才能生效
        touch(
            point.x,
            point.y,
            point.x - nextInt(5, 10),
            point.y + nextInt(5, 10)
        )
        startTime += duration + doubleDuration
        touch(
            point.x,
            point.y,
            point.x + nextInt(5, 10),
            point.y - nextInt(5, 10)
        )
    }

    /**手势操作核心*/
    fun touch(
        path: Path,
        startTime: Long = this.startTime,
        duration: Long = this.duration,
        willContinue: Boolean = this.willContinue
    ) {
        if (_isDo) {
            L.w("$path ignore touch stroke.".apply {
                //AutoParseInterceptor.log(this)
            })
            return
        }
        ensureBuilder {
            try {
                //AutoParseInterceptor.log("添加手势:$startTime ms,$duration ms")
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    addStroke(
                        GestureDescription.StrokeDescription(
                            path,
                            startTime,
                            duration,
                            willContinue
                        )
                    )
                } else {
                    addStroke(
                        GestureDescription.StrokeDescription(
                            path,
                            startTime,
                            duration
                        )
                    )
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    //</editor-fold desc="操作方法">
}

/**DSL*/
fun AccessibilityService.dslGesture(action: DslAccessibilityGesture.() -> Unit = {}): Boolean {
    val gesture = DslAccessibilityGesture().apply {
        service = this@dslGesture
        action()
        doIt()
    }
    return gesture._isDispatched
}

fun AccessibilityService.gesture(): DslAccessibilityGesture? =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        DslAccessibilityGesture().apply {
            service = this@gesture
        }
    } else {
        null
    }

//<editor-fold desc="move">

fun DslAccessibilityGesture.move(
    fromX: Int,
    fromY: Int,
    toX: Int,
    toY: Int,
    startTime: Long = this.startTime,
    duration: Long = DslAccessibilityGesture.DEFAULT_GESTURE_MOVE_DURATION,
    result: GestureResult? = null
): Boolean {
    return touch(
        fromX.toFloat(),
        fromY.toFloat(),
        toX.toFloat(),
        toY.toFloat(),
        startTime,
        duration,
        result
    )
}

fun DslAccessibilityGesture.move(
    fromX: Float,
    fromY: Float,
    toX: Float,
    toY: Float,
    startTime: Long = this.startTime,
    duration: Long = DslAccessibilityGesture.DEFAULT_GESTURE_MOVE_DURATION,
    result: GestureResult? = null
): Boolean {
    moveDuration()
    return touch(fromX, fromY, toX, toY, startTime, duration, result = result)
}

fun DslAccessibilityGesture.moveUp(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fX = screenWidth / 2 * 1f + nextInt(5, 10)
    val fY = screenHeight * 3 / 5 * 1f - nextInt(5, 10)
    val tY = screenHeight * 2 / 5 * 1f + nextInt(5, 10)

    return move(fX, fY, fX, tY, result = result)
}

fun DslAccessibilityGesture.moveDown(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fX = screenWidth / 2 * 1f + nextInt(5, 10)
    val fY = screenHeight * 3 / 5 * 1f - nextInt(5, 10)
    val tY = screenHeight * 2 / 5 * 1f + nextInt(5, 10)

    return move(fX, tY, fX, fY, result = result)
}

fun DslAccessibilityGesture.moveLeft(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fY = screenHeight / 2 * 1f + nextInt(5, 10)
    val fX = screenWidth * 3 / 5 * 1f + nextInt(5, 10)
    val tX = screenWidth * 2 / 5 * 1f - nextInt(5, 10)

    return move(fX, fY, tX, fY, result = result)
}

fun DslAccessibilityGesture.moveRight(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fY = screenHeight / 2 * 1f + nextInt(5, 10)
    val fX = screenWidth * 3 / 5 * 1f + nextInt(5, 10)
    val tX = screenWidth * 2 / 5 * 1f - nextInt(5, 10)

    return move(tX, fY, fX, fY, result = result)
}

//</editor-fold desc="move">

//<editor-fold desc="fling">

fun DslAccessibilityGesture.fling(
    fromX: Float,
    fromY: Float,
    toX: Float,
    toY: Float,
    startTime: Long = DslAccessibilityGesture.DEFAULT_GESTURE_START_TIME,
    duration: Long = DslAccessibilityGesture.DEFAULT_GESTURE_FLING_DURATION,
    result: GestureResult? = null
): Boolean {
    flingDuration(startTime, duration)
    return touch(fromX, fromY, toX, toY, startTime, duration, result)
}

/**手指往上[fling] ↑*/
fun DslAccessibilityGesture.flingUp(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fX = screenWidth / 2 * 1f + nextInt(5, 10)
    val fY = screenHeight * 3 / 5 * 1f - nextInt(5, 10)
    val tY = screenHeight * 2 / 5 * 1f + nextInt(5, 10)

    return fling(fX, fY, fX, tY, result = result)
}

/**手指往下[fling] ↓*/
fun DslAccessibilityGesture.flingDown(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fX = screenWidth / 2 * 1f + nextInt(5, 10)
    val fY = screenHeight * 3 / 5 * 1f - nextInt(5, 10)
    val tY = screenHeight * 2 / 5 * 1f + nextInt(5, 10)

    return fling(fX, tY, fX, fY, result = result)
}

fun DslAccessibilityGesture.flingLeft(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fY = screenHeight / 2 * 1f + nextInt(5, 10)
    val fX = screenWidth * 3 / 5 * 1f + nextInt(5, 10)
    val tX = screenWidth * 2 / 5 * 1f - nextInt(5, 10)

    return fling(fX, fY, tX, fY, result = result)
}

fun DslAccessibilityGesture.flingRight(result: GestureResult? = null): Boolean {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val fY = screenHeight / 2 * 1f + nextInt(5, 10)
    val fX = screenWidth * 3 / 5 * 1f + nextInt(5, 10)
    val tX = screenWidth * 2 / 5 * 1f - nextInt(5, 10)

    return fling(tX, fY, fX, fY, result = result)
}

//</editor-fold desc="fling">

//<editor-fold desc="other">

fun DslAccessibilityGesture.touch(
    fromX: Float,
    fromY: Float,
    toX: Float,
    toY: Float,
    startTime: Long = this.startTime,
    duration: Long = this.clickDuration,
    result: GestureResult? = null
): Boolean {
    gestureResult = result
    touch(fromX, fromY, toX, toY, startTime, duration)
    return doIt()
}

fun DslAccessibilityGesture.click(
    x: Float = _screenWidth / 2f,
    y: Float = _screenHeight / 2f,
    startTime: Long = this.startTime,
    duration: Long = this.clickDuration,
    result: GestureResult? = null
): Boolean {
    gestureResult = result
    touch(x, y, startTime, duration)
    return doIt()
}

fun DslAccessibilityGesture.double(
    x: Float = _screenWidth / 2f,
    y: Float = _screenHeight / 2f,
    startTime: Long = DslAccessibilityGesture.DEFAULT_GESTURE_START_TIME,
    duration: Long = DslAccessibilityGesture.DEFAULT_GESTURE_DOUBLE_DURATION,
    result: GestureResult? = null
): Boolean {
    gestureResult = result
    doubleDuration(startTime, duration)
    double(x, y)
    return doIt()
}

/**随机在屏幕中产生一个点位信息*/
fun randomPoint(
    offsetLeft: Int = 10 * dpi,
    offsetTop: Int = _satusBarHeight,
    offsetRight: Int = 10 * dpi,
    offsetBottom: Int = _navBarHeight
): Point {
    val screenWidth = _screenWidth
    val screenHeight = _screenHeight

    val x: Int = nextInt(offsetLeft, screenWidth - offsetRight)
    val y: Int = nextInt(offsetTop, screenHeight - offsetBottom)

    return Point(x, y)
}

fun nextDp(from: Int, until: Int) = nextInt(from * dpi, until * dpi)

//</editor-fold desc="other">

/**随机操作, 返回随机操作名称*/
fun DslAccessibilityGesture.randomization(): Pair<Boolean, String> {
    val p1 = PointF(randomPoint())
    val p2 = PointF(randomPoint())
    return when (nextInt(10)) {
        0 -> fling(p1.x, p1.y, p2.x, p2.y) to "fling ${p1}->${p2}"
        1 -> move(p1.x, p1.y, p2.x, p2.y) to "move ${p1}->${p2}"
        2 -> click(p1.x, p1.y) to "click $p1"
        3 -> double(p1.x, p1.y, result = null) to "double $p1"
        4 -> fling(p1.x, p1.y, p2.x, p2.y) to "fling ${p1}->${p2}"
        5 -> fling(p1.x, p1.y, p2.x, p2.y) to "fling ${p1}->${p2}"
        6 -> fling(p1.x, p1.y, p2.x, p2.y) to "fling ${p1}->${p2}"
        7 -> fling(p1.x, p1.y, p2.x, p2.y) to "fling ${p1}->${p2}"
        8 -> click(p1.x, p1.y) to "click $p1"
        9 -> double(p1.x, p1.y, result = null) to "double $p1"
        else -> true to "pass"
    }
}

有了这个工具类, 可以很快速的执行常规的手势操作, 如下:

click 点击

DslAccessibilityGesture.click(x,y)

double 双击

DslAccessibilityGesture.double(x,y)

move 移动

DslAccessibilityGesture.move(x1,y1, x2,y2)

fling 快速移动

DslAccessibilityGesture.fling(x1,y1, x2,y2)

系列文章

  • acc–›Android无障碍开发入门
  • acc–›Android无障碍开发常用操作
  • acc–›Android无障碍开发手势操作
  • acc–›Android无障碍开发框架

联系作者

群内有各(pian)种(ni)各(jin)样(qun)的大佬,等你来撩.

点此QQ对话 该死的空格 点此快速加群

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

acc--›Android无障碍开发手势操作 的相关文章

  • 如何为ScrollView放置固定图像背景?

    我应该想要滚动视图滚动 而不是背景中的图像 将图像添加到滚动视图框架之前的视图层次结构的较高位置
  • 如何在 Android 中保存相机的临时照片?

    在尝试从相机拍照并将其保存到应用程序的缓存文件夹中时 我没有得到任何可见的结果 应用程序不会崩溃 但在 LogCat 上 当我尝试将 ImageView src 字段设置为刚刚获取的文件的 URI 时 我收到此消息 09 17 14 03
  • React Native 从 JavaScript 代码内部访问 strings.xml

    有没有办法访问当前值android app src main res values strings xml从 JavaScript 代码内部 我想为每个构建放置不同的端点 URL 但我什至无法检测到反应本机代码内的构建类型 而不必求助于 D
  • Android 后退按钮无法与 Flutter 选项卡内的导航器配合使用

    我需要在每个选项卡内有一个导航器 因此当我推送新的小部件时 选项卡栏会保留在屏幕上 代码运行得很好 但是 android 后退按钮正在关闭应用程序而不是运行 Navigator pop import package flutter mate
  • 谷歌坐标认证

    当我尝试连接到 Google 坐标时 总是出现异常GoogleAuthException 我拥有 Google 地图协调中心许可证 我确实使用我的包应用程序名称和 SHA1 在 google 控制台中创建了我的客户端 ID 我将权限添加到清
  • 如何在android中获取Camera2 API的当前曝光

    In android hardware Camera旧的 我使用下面的代码获取当前曝光并获取它Camera Camera Parameters param mCamera getParameters currentExposure para
  • Adobe 是否为其 PDF 阅读器提供 Android SDK 或 API? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望能够在我们的应用程序内的视图中显示本地 PDF 文件 在 Android 4 03 下的平板电脑上运行 目前 我们将 Adob eR
  • 使用 Android 发送 HTTP Post 请求

    我一直在尝试从 SO 和其他网站上的大量示例中学习 但我无法弄清楚为什么我编写的示例不起作用 我正在构建一个小型概念验证应用程序 它可以识别语音并将其 文本 作为 POST 请求发送到 node js 服务器 我已确认语音识别有效 并且服务
  • 带有 EditText 和 Spinner 的对话框

    我有一个按钮 单击后会弹出一个对话框 我希望对话框有一个EditText and a Spinner对话框内 我不知道如何设置它的视图 我有一个代码AlertDialog它有效 只是EditText and Spinner我需要将其放入其中
  • 发布android后更改应用内购买项目的价格

    在 Google Play 上发布后 是否可以更改应用内购买商品的价格 我假设该应用程序也已发布 完整的在线文档位于http developer android com http developer android com也http sup
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 如何使用 IF 检查 TextView 可见性

    我有一个 onCheckedChangeListener 来根据选择的单选按钮显示文本视图 我有 1 个疑问和 1 个难题 想知道是否有人可以帮助我 问题 您能否将单选组默认检查值设置为 否 单选按钮 以便一开始就不会检查任何内容 问题 如
  • Ubuntu 16.04 - Genymotion:找不到 /dev/hw_random

    I install Genymotion on the Ubuntu 16 04 64Bit I created a virtual emulator for Android 6 0 then I run this emulator but
  • 我想实现下面的布局,按钮应该在屏幕底部,当惰性列被填充时,按钮不应该出去

    顶部有惰性列 惰性列下方有输入电话号码布局并从电话簿布局添加联系人 我希望当未添加联系人时此布局位于顶部 当我添加大量联系人时输入电话号码并添加电话簿布局中的联系人会随着惰性列滚动并移出屏幕 我不让他们走出屏幕 当接触较多时 它们必须粘在底
  • 如何默认在 ActionOpenDocument 意图中显示“内部存储”选项

    我需要用户选择一个自定义文件类型的文件 并将其从 Windows 文件资源管理器拖到 Android 设备上 但默认情况下内部存储选项不可用 当我使用以下命令启动意图时 var libraryIntent new Intent Intent
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 错误:在根项目“projectName”中找不到项目“app”

    我有一个在 Eclipse 中开发的旧应用程序 现在尝试将其迁移到 Android Studio 我更新了库并遵循了基本步骤 现在 我收到此错误 Error Project app not found in root project pro
  • Android 套接字和 asynctask

    我即将开始制作一个应该充当 tcp 聊天客户端的应用程序 我一直在阅读和阅读 我得出的结论是最好 如果不需要 将我的套接字和异步任务中的阅读器 问题是我不确定从哪里开始 因为我是 Android 新手 这至少对我来说是一项艰巨的任务 但据我
  • 如何确定对手机号码的呼叫是本地呼叫还是 STD 或 ISD

    我正在为 Android 开发某种应用程序 但不知道如何获取被叫号码是本地或 STD 的号码的数据 即手机号码检查器等应用程序从哪里获取数据 注意 我说的是手机号码 而不是固定电话 固定电话号码 你得到的数字是字符串类型 因此 您可以获取号
  • 一次显示两条Toast消息?

    我希望在一个位置显示一条 Toast 消息 并在另一位置同时显示另一条 Toast 消息 多个 Toast 消息似乎总是按顺序排队和显示 是否可以同时显示两条消息 是否有一种解决方法至少可以提供这种外观并且不涉及扰乱活动布局 Edit 看来

随机推荐

  • 程序员也是会浪漫的->打造浪漫的Android表白程序

    一年前 xff0c 看到过有个牛人用HTML5绘制了浪漫的爱心表白动画 xff0c 后来又在华超的这篇文章上看到大神用Android写出了相同的效果 xff0c 于是也动手写了一下 xff0c 并加了一些功能 xff0c 感谢大神的指引 写
  • Android登录注册功能封装

    我们都知道Android应用软件基本上都会用到登录注册功能 xff0c 那么对一个一个好的登录注册模块进行封装就势在必行了 这里给大家介绍一下我的第一个项目中所用到的登录注册功能的 xff0c 已经对其进行封装 xff0c 希望能对大家有帮
  • Kotlin 官方学习教程之扩展

    扩展 类似于 C 和 Gosu xff0c Kotlin 也提供了一种可以在不继承父类也不使用类似装饰器这样的设计模式的情况下对指定类进行扩展的功能 这是通过称为扩展名的特殊声明来实现的 Kotlin 支持函数扩展和属性扩展 函数扩展 要声
  • Kotlin 官方学习教程之密封类与泛型

    密封类 密封类用于表示受限类层次结构 xff0c 当值可以有一个有限集合的类型 xff0c 但不能有其他类型 它们在某种意义上是枚举类的扩展 xff1a 枚举类型的值集合也受到限制 xff0c 但每个枚举常量仅作为单个实例存在 xff0c
  • 致年轻时如此拼搏的你我

    离别总是伤人意 这一篇文章写在这个时候是有其特殊意义和价值 xff0c 起码对我来说是这样的 这个时候正是一年一度的毕业季 xff0c 而我最敬重的师兄即将要离校实习 xff0c 很幸运的是师兄收到了很不错的 offer xff0c 在这里
  • Linux网络编程:libnet 移植及使用

    目录 参考文章 xff1a 一 libnet库下载二 libnet库交叉编译安装三 应用程序交叉编译四 Ubuntu系统安装 libnet xff08 非交叉编译 xff09 五 libnet使用六 开发板上测试 参考文章 xff1a li
  • ZYNQ Linux 使用SPI驱动

    原文链接 xff1a ZYNQ Linux使用SPI驱动 配置 Vivado Vivado中双击ZYNQ PS核 xff08 例如ZYNQ7000 xff09 xff0c 选上需要使用的SPI xff0c 这一步略 spi该驱动不支持片选功
  • Call to undefined function think\captcha\imagettftext()

    php安装gd库以后 xff0c 在生成验证码图片的时候报错Call to undefined function think captcha imagettftext xff0c 查阅资料 xff08 参考资料 xff1a http www
  • acc--›Android无障碍开发常用操作

    文章目录 前言AccessibilityNodeInfo获取输入焦点 96 api gt 61 14 96 清理输入焦点 96 api gt 61 14 96 选中 96 api gt 61 14 96 清理选中 96 api gt 61
  • 解决composer安装alibabacloud/sdk下载不下来问题

    近期需要接入阿里云服务相关接口 xff0c 官方文档中写着php sdk可以支持composer安装 xff0c 于是就按照官网文档执行了了composer require alibabacloud sdk 结果等了半天也没反应 xff0c
  • 请求报警:Referrer Policy: strict-origin-when-cross-origin或引用站点策略: no-referrer-when-downgrade

    提交表单发送ajax请求时 xff0c chrome请求返回Referrer Policy strict origin when cross origin错误 xff0c 360浏览器返回 引用站点策略 no referrer when d
  • docker安装ES及kibana

    docker安装elasticsearch xff1a docker pull elasticsearch 7 4 2 docker pull kibana 7 4 2 xff08 可视化界面 xff0c 要与es版本保持一致 xff09
  • redis分布式锁到redisson的转变

    首先导入redis依赖 xff1a lt dependency gt lt groupId gt org springframework boot lt groupId gt lt artifactId gt spring boot sta
  • 实现Mysql事务嵌套(部分回滚)

    测试数据库表结构 xff1a CREATE TABLE 96 my user 96 96 id 96 int 11 NOT NULL AUTO INCREMENT 96 name 96 varchar 50 DEFAULT NULL 96
  • iframe框架中a标签的target失效问题,导致链接跳转到新窗口

    最近遇到一个问题很奇怪 xff0c 我用iframe搭建的页面 xff0c 页面左侧设置了菜单栏 xff0c 右侧是菜单对应的链 接内容 a标签加target实现 xff0c 但是最近发现有一个菜单链接一访问会导致所有的菜单target失效
  • http和https网页切换导致cookie失效问题

    网站先后从https和http方式登陆网站 xff0c 会导致http中cookie无法生效 xff0c 即https覆盖和http但作用域只在https中 xff0c 在http中浏览器debug中查看不到相关cookie 之前遇到这个问
  • 程序员要多跳巢才能涨工资

    不要一辈子呆死在一家公司 都是打工高薪才是王道 fs xff1a 这 篇文章的本意 xff0c 是告诉大家如何识别公司 而不是鼓励大家无脑跳槽 只有当你在一个公司略有所成的时候 xff0c 你才能有所积累 跳槽更多时候 xff0c 应该看到
  • Ajax反正现在我没怎么看懂

    AJAX即 A synchronous J avascript A nd X ML xff08 异步JavaScript和XML xff09 xff0c 是指一种创建交互式 网页应用的网页开发技术 AJAX 61 异步 JavaScript
  • ViewBinding封装基类(BaseActivity,BaseFragment)

    混淆规则 keep class 包名 databinding 使用反射 BaseActivity public class BaseActivity lt T extends ViewBinding gt extends AppCompat
  • acc--›Android无障碍开发手势操作

    文章目录 前言dispatchGesture 96 api gt 61 24 96 GestureDescriptionGestureResultCallback执行手势 DslAccessibilityGestureclick 点击dou