小编and*_*per的帖子

拖动时如何在使用 ItemTouchHelper 时取消 RecyclerView 中项目的拖动?

背景

我正在尝试拥有一个具有不同视图类型的 RecyclerView,但具有拖放功能以及单击和长按操作的能力。

它类似于您在电话应用程序上的功能,您可以在其中更改收藏夹项目的顺序。在电话应用程序中,当您长按某个项目时,会立即出现一个上下文菜单,如果您继续拖动,上下文菜单就会消失。

但是,在这种情况下,我需要做相反的事情。长按时,如果用户在很短的时间内没有拖动,或者用户在没有拖动的情况下停止长按,我们会在屏幕上显示一个对话框,我需要停止拖动过程。

问题

虽然我已经成功地处理了长触摸机制,并且我在这些特殊情况下显示了一个对话框,但我未能使拖动停止。

这意味着,如果用户在对话框出现后继续触摸屏幕,仍然可以继续拖动:

在此处输入图片说明

整个代码在这里可用(没有长触摸行为的代码在这里可用),但这里是主要代码:

class MainActivity : AppCompatActivity() {
    sealed class Item(val id: Long, val itemType: Int) {
        class HeaderItem(id: Long) : Item(id, ITEM_TYPE_HEADER)
        class NormalItem(id: Long, val data: Long) : Item(id, 1)
    }

    enum class ItemActionState {
        IDLE, LONG_TOUCH_OR_SOMETHING_ELSE, DRAG, SWIPE, HANDLED_LONG_TOUCH
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        val items = ArrayList<Item>(100)
        var itemDataCounter = 0L
        items.add(Item.HeaderItem(0L))
        for (i in 0 until 100) {
            items.add(Item.NormalItem(itemDataCounter, itemDataCounter))
            ++itemDataCounter …
Run Code Online (Sandbox Code Playgroud)

android drag-and-drop android-recyclerview itemtouchhelper

5
推荐指数
1
解决办法
1228
查看次数

如何使用“libsu”库(或adb)在Android Q上安装拆分的APK文件?

背景

使用 root,我知道对于单个 APK 文件,我们可以使用“libsu”库(此处)进行安装:

val installResult = Shell.su("pm install -t \"$filePath\"").exec()
Run Code Online (Sandbox Code Playgroud)

如果失败了(在新的 Android 版本上失败了,不确定是哪个版本),如下(在这里写下

val installResult = Shell.su("cat \"$filePath\" | pm install -t -S ${apkSource.fileSize}").exec()
Run Code Online (Sandbox Code Playgroud)

我还知道,在安装拆分 APK 文件时,事情会变得非常混乱(如此处所示。首先,您需要使用“pm install-create”命令创建一个会话:

var sessionId: Int? = null
run {
    val sessionIdResult =
            Shell.su("pm install-create -r -t").exec().out
    val sessionIdPattern = Pattern.compile("(\\d+)")
    val sessionIdMatcher = sessionIdPattern.matcher(sessionIdResult[0])
    sessionIdMatcher.find()
    sessionId = Integer.parseInt(sessionIdMatcher.group(1)!!)
    Log.d("AppLog", "sessionId:$sessionId")
}
Run Code Online (Sandbox Code Playgroud)

然后你必须“推送”每个 APK 文件,如下所示:

for (apkSource in fileInfoList) {
    val filePath = File(apkSource.parentFilePath, apkSource.fileName).absolutePath
    Log.d("AppLog", "installing …
Run Code Online (Sandbox Code Playgroud)

android adb android-install-apk android-app-bundle android-10.0

5
推荐指数
1
解决办法
2350
查看次数

如何从 RAM 中完全解析压缩文件?

背景

我需要解析一些各种类型的 zip 文件(出于某种目的获取一些内部文件内容,包括获取它们的名称)。

有些文件无法通过文件路径访问,因为 Android 有 Uri 来访问它们,并且有时 zip 文件位于另一个 zip 文件内。随着使用 SAF 的推动,在某些情况下使用文件路径的可能性甚至更小。

为此,我们有 2 个主要方法来处理:ZipFile类和ZipInputStream类。

问题

当我们有文件路径时,ZipFile 是一个完美的解决方案。在速度方面它也非常有效。

然而,对于其余情况,ZipInputStream 可能会遇到问题,例如这个zip 文件有问题,并导致此异常:

  java.util.zip.ZipException: only DEFLATED entries can have EXT descriptor
        at java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:321)
        at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:124)
Run Code Online (Sandbox Code Playgroud)

我尝试过的

唯一始终有效的解决方案是将文件复制到其他地方,您可以在其中使用 ZipFile 解析它,但这效率很低,并且需要您有可用存储空间,并在完成后删除文件。

因此,我发现 Apache 有一个很好的纯 Java 库(此处)来解析 Zip 文件,并且出于某种原因,它的 InputStream 解决方案(称为“ZipArchiveInputStream”)似乎比本机 ZipInputStream 类更高效。

与我们在本机框架中所拥有的相反,该库提供了更多的灵活性。例如,我可以将整个 zip 文件加载到字节数组中,并让库照常处理它,这甚至适用于我提到的有问题的 Zip 文件:

org.apache.commons.compress.archivers.zip.ZipFile(SeekableInMemoryByteChannel(byteArray)).use { zipFile ->
    for (entry in zipFile.entries) {
      val name = entry.name
      ... // use …
Run Code Online (Sandbox Code Playgroud)

memory java-native-interface zip android apache-commons

5
推荐指数
1
解决办法
836
查看次数

如何使用 People API 获取有关“其他联系人”的完整信息?

背景

我正在开发一个需要获取“其他联系人”信息的应用程序,因为它们出现在Google 的“联系人”网站上的地址簿页面上:

在此处输入图片说明

问题

Contacts API 已被弃用,我们需要使用 People API。

为此,我使用了 Java 库(此处),它可以更轻松地访问各种功能。

遗憾的是,根据文档(此处),从“其他联系人”查询项目列表,您最多只能获得 3 个可能的字段:

  • 电子邮件地址
  • 名字
  • 电话号码

确实,在使用它时,这就是我得到的。我也有“etag”和“resourceName”字段,但就是这样。没有照片,没有封面照片,没有别的……

执行此操作的代码很短(在您设置好所有内容之后):

val otherContactsResponse =
    otherContacts.list().setReadMask("emailAddresses,names,phoneNumbers")
        .setPageSize(itemsCountToRequest).setPageToken(nextPageToken).execute()
val result=otherContactsResponse.otherContacts
Run Code Online (Sandbox Code Playgroud)

我试过的

  1. 我试图看看我是否可以通过“reourceName”(例如this one)进行查询,但似乎“其他联系人”的处理方式与普通联系人不同,因此这不起作用:
result.forEach { personBasic: Person ->
    val test: Person? = peopleService.get(personBasic.resourceName!!)
        .setPersonFields(
            "addresses,ageRanges,birthdays,coverPhotos,emailAddresses,genders,metadata,names,nicknames,occupations,organizations,phoneNumbers,photos,urls")
        .execute()
    Log.d("AppLog", "$test")
}
Run Code Online (Sandbox Code Playgroud)
  1. 遗憾的是,没有类似的搜索“其他联系人”部分的查询(除了这里,它再次为您提供相同的 3 个字段)。

  2. 试图找出我遗漏的其他字段是否可以在其他地方使用。我甚至不知道resourceName或者etag是可靠和查询唯一的。

  3. 尽管文档只讨论了 3 个字段,但仍尝试向查询添加更多字段。失败了,当然...

  4. 有一个名为copyOtherContactToMyContactsGroup( here )的函数,它似乎会将联系人复制到主要联系人组。我想如果我使用它然后查询联系人本身(不仅仅是“其他联系人”),我可以获得所需的信息。但这既浪费时间,又会污染用户的通讯录,即使是暂时的。我必须确保在添加联系人后立即从那里删除联系人...

编辑:也试过这个,虽然它似乎有效,但我不想使用它,因为它会用用户尚未添加的联系人污染地址簿。另外,我有时会得到一个图像,它只是带有背景的人的字母。这是它的代码:

result.firstOrNull { !it.names.isNullOrEmpty()&&!it.emailAddresses.isNullOrEmpty() …
Run Code Online (Sandbox Code Playgroud)

android google-people-api

5
推荐指数
1
解决办法
191
查看次数

如何避免在 Google 登录对话框后获得错误令牌?

背景

在应用程序内部,有一个使用令牌向服务器注册的 Google 登录步骤。这是通过以下依赖项完成的:

api('com.google.android.gms:play-services-auth:20.0.0')
Run Code Online (Sandbox Code Playgroud)

该应用程序会触发向用户显示最多 2 个对话框:

  1. 登录(如果用户已登录当前安装的应用程序,则不会显示):

![在此输入图像描述

  1. 授予权限(如果过去授予过权限则不会显示):

在此输入图像描述

这对于大多数情况都适用。

如果用户已经登录并授予权限,我们可以使用上次获得的令牌,假设它没有过期。我使用以下方法检查它是否已过期:

GoogleSignIn.getLastSignedInAccount(context)?.isExpired`) .
Run Code Online (Sandbox Code Playgroud)

问题

我发现了一个特殊的有问题的场景:

  1. 用户过去曾登录并授予过一些权限
  2. 用户转到 Google 帐户管理器并撤销了对该应用程序的访问权限(此处)。
  3. 用户尝试再次登录(例如删除应用程序后)

在这种情况下,我得到了一个无法使用的坏令牌。它实际上与我在撤销访问权限之前获得的令牌完全相同。它可能使用上次缓存的令牌,以避免与 Google 服务器进行不必要的通信。

在这种情况下,服务器(我所使用的 SDK)会在尝试使用该令牌时向我发送一条错误消息,指出该令牌无效(这是正确的)。

这是有问题的,在我看来就像 Google SDK 上的一个错误(我已在此处报告),因为令牌应该可以工作,因为用户已使用登录对话框重新登录,并且所有内容都已重置。

我尝试过的

我尝试使用各种 API 函数,但它们似乎都没有告诉我令牌是否有效,或者让我为登录对话框请求一个新令牌,以防当前令牌无效。

我发现的唯一解决方法是,在一次登录对话框后,并检测到令牌有错误(通过服务器获取),我选择完全注销并重新登录:

@WorkerThread
fun logout(context: Context, googleClientId: String) {
    val options =
        GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestServerAuthCode(googleClientId)
            .requestEmail()
            .build()
    val signInClient = GoogleSignIn.getClient(context, options)
    val lastSignedInAccount = GoogleSignIn.getLastSignedInAccount(context)
    if (lastSignedInAccount != null) {
        Tasks.await(signInClient.revokeAccess())
        Tasks.await(signInClient.signOut())
    }
}
Run Code Online (Sandbox Code Playgroud)

只有在那之后,我才能使用我准备的 Intent 登录:

@WorkerThread
fun prepareIntent(context: Context, googleClientId: String): …
Run Code Online (Sandbox Code Playgroud)

android token google-signin

5
推荐指数
1
解决办法
499
查看次数

是否可以在运行时获取依赖版本,包括从库本身获取依赖版本?

背景

假设我制作了一个名为“MySdk”的 Android 库,并将其发布到 Jitpack/Maven 上。

SDK 的用户只需添加以下依赖项即可使用它:

implementation 'com.github.my-sdk:MySdk:1.0.1'
Run Code Online (Sandbox Code Playgroud)

我想要得到的是其中的“1.0.1”部分,无论我是从 Android 库本身(对于发送到使用哪个版本的 SDK 服务器很有用),还是从应用程序执行此操作使用它(对于报告特定问题很有用,包括通过 Crashlytics)。

问题

我找不到任何反射或 gradle 任务来实现它。

我尝试过的

搜索一下,如果我确实在 Android 库(用作依赖项)上工作,我发现我可以通过代码自己管理版本。

有人说我可以使用库的包名称的 BuildConfig,但这意味着如果我在发布依赖项之前忘记更新代码,它将使用错误的值。使用此方法的示例:

plugins {
...
}
final def sdkVersion = "1.0.22"

android {
    ...
    buildTypes {
        release {
            ...
            buildConfigField "String", "SDK_VERSION", "\"" + sdkVersion + "\""
        }
       debug {
            buildConfigField "String", "SDK_VERSION", "\"" + sdkVersion + "-unreleased\""
        }
    }
Run Code Online (Sandbox Code Playgroud)

BuildConfig.SDK_VERSION用法只是检查(构建后)的值。

另一种可能的解决方案可能是来自 Android 库内的 gradle 任务,每当您构建使用该库的应用程序时,都会强制启动该任务。但是,我没找到怎么做(在这里找到了一些东西)

问题

是否可以从依赖项的 Android 库(当然还有使用它的应用程序)查询依赖项版本,以便我可以在运行时使用它?

自动的东西,不需要我在发布之前更新它?

也许使用库中定义的 Gradle …

android dependency-management android-gradle-plugin

5
推荐指数
1
解决办法
1883
查看次数

如何使用 Kotlin 协程正确拥有待处理操作队列?

背景

我在我工作的大型应用程序上发现了一些类/函数,它们具有不应在 UI 线程上进行的调用(例如访问存储或数据库)。

此类操作可能会导致 ANR,实际上我可以在 Play Console 上看到 ANR 的百分比。

我想改变这一点,并希望通过使用 Kotlin 协程来使代码更有秩序。

因此,目前我正在开发一个扩展类BroadcastReceiver,因此它需要onReceive在 UI 线程上一个接一个地处理回调,每个回调都必须“等待”前一个回调完成。

在 onReceive 回调内部,有一些调用应该在后台线程上完成,有些则在 UI 线程上完成。有时有些条件同时具备这两者。

含义例如:

if( someCheckOnUiThread() && someDbOperation()) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

问题

我对 Kotlin 协程很陌生,尽管我已经找到了如何处理这个问题,但我很确定有一种更官方的方法可以做到这一点,因为我已经阅读了其他人关于此问题的一些提示和评论(这里)。

我尝试过的

我所做的实际上是有效的,但它看起来更像是一种解决方法:

private val mainScope = MainScope()
private val backgroundWorkDispatcher: CoroutineDispatcher =
        java.util.concurrent.Executors.newFixedThreadPool(1).asCoroutineDispatcher()
Run Code Online (Sandbox Code Playgroud)

然后在回调中使用它们onReceive

@UiThread
override fun onReceive(somcContext: Context, intent: Intent) {
    val context = somcContext.applicationContext
    //use goAsync just because I'm in BroadcastReceiver
    val pendingAsyncResult = goAsync() 
    mainScope.launch …
Run Code Online (Sandbox Code Playgroud)

multithreading android kotlin-coroutines

5
推荐指数
1
解决办法
8096
查看次数

如何在android上正确拖动视图

似乎有很多关于如何在android上使用拖动视图的解决方案.

然而,它们要么太慢,要么是马车.

一个已知的解决方案是使用framelayout,视图只需在使用OnTouchListener移动时更改其layoutParams,如下所述:http://www.anddev.org/novice-tutorials-f8/android-drag-and-drop -of-normal-views-not-bitmaps-t13404.html 但是,如果视图是imageView,当到达framelayout的最右侧(或最底部)时,图像会缩小.

另一种可能的解决方案是使用画布来显示拖动的内容,如下所述:http: //www.anddev.org/basic_drag_and_drop-t3095.html 但是,我不确定如何将它用于复杂视图.

没有人知道一个很好的解决方案,一个让拖累视图的大小保持不变,不管它是在它的容器?

请帮我 .

android drag imageview layoutparams android-framelayout

4
推荐指数
1
解决办法
1万
查看次数

如何维护多层ImageView并保持其纵横比基于最大的?

假设我有多个图像需要将一个放在另一个上面,有些可能会出现某种动画,有些甚至可能是可拖动的.

通常占据整个屏幕的最大的一个是Z坐标的底部(让我们称之为backgroundImageView),而其余的都出现在它的顶部(并且在其他顶部).

像这样:

  • backgroundImageView
  • imageView1,居中.
  • imageView2,占60%,左上角的60%
  • ...

如果我使用FrameLayout(这似乎是最好的解决方案),backgroundImageView的大小会很合适,但是如何强制其他图层相应调整大小呢?

我想我需要以某种方式得到其他层的位置以及如何设置它们的大小.

简单的方法是确保所有图层具有完全相同的大小,但这可能会占用大量内存,并在动画或拖动视图时变得非常慢.如果某些层的内容非常小,那将是一个巨大的浪费.

android layer android-animation android-imageview

4
推荐指数
1
解决办法
1万
查看次数

如何在画布上绘制位图,尊重位图的alpha值?

背景

我有一个主位图,我需要在其他位图上绘制.

主位图具有一些半透明像素(具有alpha通道变量值的像素),因此在其上绘制的其他位图应与其合并,而不是完全覆盖颜色.

这个问题

如何设置画布相对于半透明像素在主位图上绘制位图?

注意:alpha不适用于整个位图.这是每个像素.

android bitmap alpha-transparency android-canvas

4
推荐指数
1
解决办法
5278
查看次数