小编fre*_*yle的帖子

默认情况下,应用程序链接在 Android 12 中无法打开。可能的 SHA256 问题

我已通过在此处上传 assetlinks.json 文件来设置深度链接

https://example.com/.well-known/assetlinks.json
Run Code Online (Sandbox Code Playgroud)

它在 Android 11 之前都可以正常工作。如果不是从 Playstore 下载的,它也可以在 Android 12 中工作(即从我的 android studio 或我从 android studio 制作的 apk 文件安装,即使我使用 Keystore 签署 apk 文件也能工作。)

在 Android 12 上从 Playstore 下载时,如果您进入应用程序设置 -> 默认打开 -> 在应用程序中打开的链接。我们可以看到我的域默认被禁用。我认为这与我在 assetlinks.json 中使用的 sha256 有关

我从 Android studio 中的 App Link Assistant 获取了 assetlinks.json。(我在生成 assetlinks 时也选择了密钥库文件)。

如果我去我的play console->Setup->App integrity->App signing

我可以在数字资产 Json 部分中看到不同的 Sha256(也在应用程序签名密钥证书部分中)

我可以在上传密钥证书部分看到我上传的 Sha256。

我的问题是我应该在 assetlinks.json 中使用哪种 sha256?

我在这里看到我应该同时使用两者。如果应该的话,如何将 sha256 添加到我的 assetlink.json 中。我可以将其添加为像这样的逗号分隔值吗?

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example", …
Run Code Online (Sandbox Code Playgroud)

android deep-linking android-deep-link android-app-links

16
推荐指数
2
解决办法
3万
查看次数

如何将视图模型范围限定为父片段?

所以我正在使用新的导航组件(具有一个活动原则)并使用共享视图模型在每个片段之间进行通信,但是,我有时需要清除视图模型但我找不到清除它的好地方。但是 tbh 我认为与其试图自己清除它,我真的应该允许框架为我做这件事,但这不是因为视图模型是共享的并限定于活动,但我认为我可以将它们限定为一个父片段,我画了一张图来说明我想要做什么。我的导航流程 所以当我从“Child 1 Child a”导航回来时,我只想清除 2 个视图模型,当前视图模型永远不会被清除,试图通过在片段中调用“this”来获取当前的视图模型,而 getParentFragment 在孩子中没有不行,谁能举个例子?

编辑

看起来我已经在做类似的事情,但在我的情况下它不起作用所以我将添加一些代码,这是我如何访问父片段中的第一个视图模型

model = ViewModelProviders.of(this).get(RequestViewModel.class);
Run Code Online (Sandbox Code Playgroud)

然后在子片段中,我正在这样做

requestViewModel = ViewModelProviders.of(getParentFragment()).get(RequestViewModel.class);
Run Code Online (Sandbox Code Playgroud)

但这并没有保留他们之间的数据,他们都附加了观察者

android viewmodel android-fragments android-architecture-navigation

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

当与 viewpager 和 recyclerview 一起使用时,CollapsingToolbarLayout 的部分内容变得粘在上面

我正在尝试实现这样的布局:

在此处输入图片说明

问题是,当向上滚动卡片时,它会接触到工具栏,并且不再像这样向上滚动:

在此处输入图片说明

我希望它向上滚动直到 viewpager 填满屏幕,即至少矩形卡应该向上滚动到工具栏之外(即使 tabLayout 也可以向上滚动)。但我不希望它在顶部保持粘性。

主要布局在这里:

 <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:showIn="@layout/activity_main">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/background_dark"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/toolbarCollapse"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="190dp"
                android:minHeight="190dp"
                android:src="@drawable/ic_launcher_foreground"
                app:layout_collapseMode="parallax" />


            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?actionBarSize"
                app:layout_collapseMode="pin" />

        </com.google.android.material.appbar.CollapsingToolbarLayout>


    </com.google.android.material.appbar.AppBarLayout>


    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:behavior_overlapTop="90dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:id="@+id/lin"
            android:nestedScrollingEnabled="false"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <include layout="@layout/debit_card_item" />


            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="?actionBarSize"
                android:layout_marginTop="40dp"
                android:background="?attr/colorPrimary" />


            <androidx.viewpager.widget.ViewPager
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1" />

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Run Code Online (Sandbox Code Playgroud)

寻呼机的片段位于 NestedScrollView 中,如下所示:

<?xml …
Run Code Online (Sandbox Code Playgroud)

android android-recyclerview android-coordinatorlayout android-collapsingtoolbarlayout android-nestedscrollview

8
推荐指数
1
解决办法
888
查看次数

在Android Studio Gutter中启用代码覆盖率指示

当我与代码覆盖了Android工作室运行我的单元测试,并选择看到覆盖率工具栏的来源,我不能看到如图所示的编辑在阴沟里(边栏)的代码覆盖率信息在这里。没有有关装订线中的命中次数或颜色指示器的信息。

在此处输入图片说明 在此处输入图片说明

这就是我正在使用的:

Android Studio 3.2.1
Build#AI-181.5540.7.32.5056338,建于2018年10月9日
JRE:1.8.0_152-release-1136-b06 amd64
JVM:JetBrains sro
Linux 4.15.0-34的OpenJDK 64位服务器VM -通用

user-interface unit-testing gutter android-studio

7
推荐指数
1
解决办法
111
查看次数

如何使用 Dagger 2 在 ViewPager 中注入相同 Fragment 的 ViewModel

我正在尝试将 Dagger 2 添加到我的项目中。我能够为我的片段注入 ViewModels(AndroidX 架构组件)。

我有一个ViewPager,它有 2 个相同片段的实例(每个选项卡只有很小的更改),并且在每个选项卡中,我观察LiveData到更新数据更改(来自 API)。

问题在于,当 api 响应到来并更新 时LiveData,当前可见片段中的相同数据将发送给所有选项卡中的观察者。(我认为这可能是因为 的范围ViewModel)。

这是我观察数据的方式:

override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        activityViewModel.expenseList.observe(this, Observer {
            swipeToRefreshLayout.isRefreshing = false
            viewAdapter.setData(it)
        })
    ....
}
Run Code Online (Sandbox Code Playgroud)

我正在使用这个类来提供ViewModels:

class ViewModelProviderFactory @Inject constructor(creators: MutableMap<Class<out ViewModel?>?, Provider<ViewModel?>?>?) :
    ViewModelProvider.Factory {
    private val creators: MutableMap<Class<out ViewModel?>?, Provider<ViewModel?>?>? = creators
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        var creator: Provider<out ViewModel?>? = creators!![modelClass]
        if (creator == …
Run Code Online (Sandbox Code Playgroud)

android android-viewpager dagger-2 android-mvvm androidx

7
推荐指数
1
解决办法
1745
查看次数

从数据列表中查找RecyclerView中项目的位置

我想RecyclerView从数据集中获取项目的位置RecyclerView.我的数据集中的每个项目都包含唯一的ID.我想RecyclerView在数据集中的id中找到项目的适配器位置.

我的数据集类如下所示.

class dataset {
    int id;
    JSONArray linked;
    int type;
    ....
}
Run Code Online (Sandbox Code Playgroud)

我添加TextViewEditTextRecyclerView根据类型.

最终目标:我RecyclerView可以拥有多个EditText并且TextViews是独立的(尽管TextView将有一个EditText与其相关联的id的字段).当我点击时TextView,我将获得EditText(数据集)的id 来从中获取数据.我想从那些id中EditText的项目中获取相应的文本RecyclerView.如果我可以从数据集中获取适配器位置,我可以使用

recyclerview.getChildAt(position);
Run Code Online (Sandbox Code Playgroud)

但是没有办法从数据集中获取适配器位置.

java android recycler-adapter android-recyclerview

6
推荐指数
0
解决办法
752
查看次数

Android 单元测试因 java.lang.IllegalArgumentException 失败:需要 INTERNET 权限

我正在尝试为我的应用程序设置单元测试。但我遇到了Segment的问题

这是我的测试课:

@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1])
class LoginViewModelTest {
    private lateinit var viewModel: LoginViewModel

    @Mock
    private lateinit var authService: AuthService

    @Mock
    private lateinit var sharedPreferences: SharedPreferences

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        val mMyApplication = mock<Application>()
        viewModel = LoginViewModel(mMyApplication, sharedPreferences, authService)
    }

    @Test
    fun test_phone(){
        viewModel.isPhone.observeForTesting {
            val isPhone = LiveDataTestUtil.getValue(viewModel.isPhone) ?: 
                return@observeForTesting
           Assert.assertFalse(isPhone)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

失败并出现以下错误:

INTERNET permission is required.
java.lang.IllegalArgumentException: INTERNET permission is required.
    at com.segment.analytics.Analytics$Builder.<init>(Analytics.java:1068)
    at com.app.android.MyApplication.onCreate(MyApplication.kt:42)
Run Code Online (Sandbox Code Playgroud)

MyApplication 类正在初始化 Segment,如下所示:

override fun onCreate() {
val …
Run Code Online (Sandbox Code Playgroud)

android mockito robolectric android-viewmodel android-unit-testing

6
推荐指数
1
解决办法
724
查看次数

将MP3转换为PCM并在Android中播放

我正在尝试将mp3文件转换为pcm文件并尝试播放它.我希望值为int16.我能够使用android中的MediaCodec和MediaExtractor成功转换它.我能够正常播放它(我不得不改变采样率以播放PCM),而我直接将其写为字节数组,如下所示:

override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: MediaCodec.BufferInfo) {
            Log.d(TAG, "onOutputBufferAvailable")
            val buffer = mediaCodec.getOutputBuffer(index)
            val b = ByteArray(info.size - info.offset)
            val a = buffer.position()
            buffer.get(b)
            buffer.position(a)
            mediaCodec.releaseOutputBuffer(index, true)
            Log.i(TAG,"byte data: "+b.contentToString())
            fos.write(b,0,info.size-info.offset)
        }
Run Code Online (Sandbox Code Playgroud)

但正如我所说,我希望它作为Int16(我的印象是这可以转换为int并保存.如果我错了请纠正我)当我将它保存为int这样的

override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: MediaCodec.BufferInfo) {
            Log.d(TAG, "onOutputBufferAvailable")
            val buffer = mediaCodec.getOutputBuffer(index)
            val byteArray = ByteArray(info.size - info.offset)
            val bufferPosition = buffer.position()
            buffer.get(byteArray)
            buffer.position(bufferPosition)
            mediaCodec.releaseOutputBuffer(index, true)
            for (i in byteArray){
                Log.i(TAG,"byte data: "+i.toInt())
                fileWriter.write(i.toString()+" ")
            }
        }
Run Code Online (Sandbox Code Playgroud)

它充满了噪音.我需要它作为int,以便我可以对音频文件进行一些操作.如果你想查看整个项目,它是在github

我想知道如何正确地将pcm文件写为int值并在android中播放.提前致谢

android format-conversion pcm mediaextractor android-mediacodec

5
推荐指数
0
解决办法
508
查看次数

将构建类型更改为 Release 会导致某些类“无法解析符号”

当我将构建类型更改为发布时,我的某些类在 android studio 中显示为“找不到符号”。即使显示错误,应用程序也已成功构建并运行。当我改回调试时,这些文件被正确识别。

这是我的 build.gradle

apply plugin: 'com.android.application'

apply plugin: 'realm-android'

apply plugin: 'io.fabric'

apply plugin: 'com.google.gms.google-services'


android {
    signingConfigs {
        debug {
            keyAlias 'debugkey-name'
            keyPassword 'dpassword'
            storeFile file('debugkey.jks')
            storePassword 'dspassword'
        }
        release {
            keyAlias 'releasekey-name'
            keyPassword 'rpassword'
            storeFile file('releasekey.jks')
            storePassword 'rspassword'
        }
    }

compileSdkVersion rootProject.ext.compileSdkVersion

defaultConfig {
    applicationId "com.app.appname"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    multiDexEnabled true
    versionCode 0
    versionName "0.9.2"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

applicationVariants.all { variant ->

    variant.outputs.all {
        outputFileName = "Appname-${variant.name}-${defaultConfig.versionName}.apk"
    }

}

buildTypes {

    debug {
        minifyEnabled …
Run Code Online (Sandbox Code Playgroud)

android proguard android-studio android-gradle-plugin android-build-type

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

将数据从一个ViewModel传递到另一个Android MVVM

你们有一个与设计有关的问题。

因此,我一直在遵循Google编写的《应用程序架构指南》,使用Kotlin,MVVM和数据绑定来构建我的应用程序。我正在使用Google规定的Jetpack组件(导航,实时数据等)。

问题是,在开发过程中,很多时候我需要将数据从一个片段传输到另一个片段。之前,我曾经创建片段的实例并添加复杂数据,然后移至片段,如下所示:

class Frag1: Fragment(){

    ...
    fun openFrag2(){
        val frg2 = frag2.newInstance(complexDataObj)
        childFragmentManager.addFragment(frg2,TAG)
    }
}

class Frag2: Fragment(){
    var cd: ComplexDataClass = null
    companion object{
    fun newInstance(complexData: ComplexDataClass): Fragment{
        val frag = ActivityFragment()
        frag.cd = complexData
        return frag
    }
    ....
}
Run Code Online (Sandbox Code Playgroud)

导航目的地之间传递数据应该是像这样或以使用共享视图模型也被同一文档中提到。>>

通常,强烈建议您仅在目标之间传递最少的数据量。例如,您应该传递键来检索对象,而不要传递对象本身,因为所有保存状态的总空间在Android上受到限制。如果您需要传递大量数据,请考虑使用在片段之间共享数据中所述的ViewModel。

这可行。

我的问题是,使用体系结构的主要原因之一是关注点分离。这样我们就可以编写干净且可维护的代码。根据我的理解,sharedviewmodel的这种用法无法达到目的,因为这会导致大型ViewModel类。

我将尝试使用非常常见的情况来解释问题。

我有一个带有数据列表的片段。列表中的每个项目都对应一个用户。当我们点击一​​个项目时,它将移至用户详细信息屏幕,如果我们点击编辑按钮,则应移至可编辑详细信息的编辑屏幕。

             View User Frag
             ____                 ____________
            |    |               |            |
 List Frag  |    |               |            |
 ______     |____|               |            |
|______| /
|______|/ …
Run Code Online (Sandbox Code Playgroud)

android mvvm android-architecture android-jetpack android-jetpack-navigation

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

为 android 中的每种风格替换 XML 文件

我正在尝试将Braze集成到我的应用程序中以进行推送通知。Braze 需要我们在其中添加 API 密钥和其他 braze 相关内容(这里是文档)创建一个braze.xml文件。src/main/res/values

现在我需要区分 prod 和 qa 环境,这意味着它们将有 2 个不同的 API 密钥。

我想知道如何使用不同的braze.xml口味来实现不同的效果。

我找到了这个

sourceSets {
    main {
         java {
            srcDirs = ['src']
         }
    }

    test {
        java {
            srcDirs = ['test']
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道如何使用它来替换我的 braze.xml 以适应不同的构建变体。

android source-sets build.gradle android-gradle-plugin android-variants

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

在 Android Retrofit 中并行调用多个 API 时,身份验证器刷新令牌

我想在访问令牌过期时刷新它。我已经实现了 Authenticator,如下所示:

@Singleton
class TokenAuthenticator(
    val authService: Lazy<AuthService>,
    private val sharedPreferences: SharedPreferences
) : Authenticator {


override fun authenticate(route: Route?, response: Response): Request? {
    return authRequestWithNewToken(response.request)
}

private fun authRequestWithNewToken(
    request: Request
): Request? {
    getFreshAccessToken()?.let { freshToken ->
        return getNewRequest(request, freshToken)
    }
    return null
}

private fun getFreshAccessToken(): String? {
    val refreshResponse = authService.get().refreshTokenTemp().execute()
    if (refreshResponse.isSuccessful) {
        val updatedAccessToken =
            refreshResponse.body()?.data?.accessToken ?: return null
        val updatedRefreshToken =
            refreshResponse.body()?.data?.refreshToken ?: return null
        updateToken(updatedAccessToken, updatedRefreshToken)
        Timber.tag("TOKEN")
            .d("Auth Updated token\n AccessToken: $updatedAccessToken …
Run Code Online (Sandbox Code Playgroud)

android android-authenticator retrofit okhttp refresh-token

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