小编reg*_*aes的帖子

Kotlin - 使用"by lazy"与"lateinit"进行属性初始化

在Kotlin中如果你不想在构造函数或类体的顶部初始化类属性,你基本上有这两个选项(来自语言参考):

  1. 延迟初始化

lazy()是一个函数,它接受一个lambda并返回一个Lazy实例,它可以作为实现一个惰性属性的委托:第一次调用get()执行传递给lazy()的lambda并记住结果,后续调用get()只返回记住的结果.

public class Hello {

   val myLazyString: String by lazy { "Hello" }

}
Run Code Online (Sandbox Code Playgroud)

所以第一次调用和子命令调用,无论它在哪里,到myLazyString将返回"Hello"

  1. 延迟初始化

通常,必须在构造函数中初始化声明为具有非null类型的属性.但是,这通常不方便.例如,可以通过依赖注入或单元测试的设置方法初始化属性.在这种情况下,您无法在构造函数中提供非null初始值设定项,但在引用类体内的属性时仍希望避免空值检查.

要处理这种情况,可以使用lateinit修饰符标记属性:

public class MyTest {

   lateinit var subject: TestSubject

   @SetUp fun setup() { subject = TestSubject() }

   @Test fun test() { subject.method() }
}
Run Code Online (Sandbox Code Playgroud)

修饰符只能用于在类体(不在主构造函数中)内声明的var属性,并且只能在属性没有自定义getter或setter时使用.属性的类型必须为非null,并且它不能是基本类型.

那么,如何在这两个选项之间正确选择,因为它们都可以解决同样的问题?

properties kotlin

232
推荐指数
7
解决办法
7万
查看次数

在Android Studio中构建应用之前自动运行测试

我编写了两个测试用例LoginTestSignUpTest使用了JUnit和一个Test Suite SessionUnitTestSuite.每次我想构建和运行我的应用程序时,我都必须运行测试套件(通过选择Test Suite然后单击"Run"),如果测试通过,则运行我的应用程序(通过选择应用程序模块和然后单击"运行").

有没有办法在运行我的应用程序模块之前自动运行测试,如果测试失败,取消我的应用程序的安装?

junit android unit-testing build.gradle

9
推荐指数
1
解决办法
2459
查看次数

获取"上传的APK的AndroidManifest.xml无法解析.是否编译正确?" 启用Google App Signing后出错

启用Google App Signing后,每当我尝试将已签名的版本APK上传到Play商店时,我都会收到错误消息,说明无法解析上传的APK的AndroidManifest.xml.编译得当吗?.

以下是使用APK分析工具从已签名的APK获取的Android清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="227"
    android:versionName="4.9"
    package="com.myproject">

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="25" />

    <uses-permission
        android:name="com.google.android.c2dm.permission.RECEIVE" />

    <uses-permission
        android:name="android.permission.INTERNET" />

    <uses-permission
        android:name="android.permission.WAKE_LOCK" />

    <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE" />

    <uses-permission
        android:name="android.permission.VIBRATE" />

    <uses-permission
        android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <uses-permission
        android:name="android.permission.MANAGE_USERS" />

    <uses-permission
        android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />

    <uses-permission
        android:name="com.android.vending.BILLING" />

    <permission
        android:name="com.myproject.permission.C2D_MESSAGE"
        android:protectionLevel="0x2" />

    <uses-permission
        android:name="com.myproject.permission.C2D_MESSAGE" />

    <application
        android:theme="@ref/0x7f10013f"
        android:label="@ref/0x7f0f004f"
        android:icon="@ref/0x7f08005a"
        android:name="br.com.regmoraes.myproject.CustomApp"
        android:allowBackup="true"
        android:largeHeap="true"
        android:supportsRtl="true">

        <meta-data
            android:name="search-engine"
            android:resource="@ref/0x7f120001" />

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@ref/0x7f0a0006" />

        <meta-data
            android:name="com.mixpanel.android.MPConfig.ResourcePackageName"
            android:value="br.com.regmoraes.myproject" />

        <meta-data
            android:name="AA_MODELS" …
Run Code Online (Sandbox Code Playgroud)

android android-manifest apk google-play android-app-signing

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

Kotlin - 如何从一个接口"覆盖"var的覆盖?

我有一个名为的界面 UserManager

interface UserManager {

    var user:User

    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

和一个名为UserManagerImpl,实现的类UserManager

class UserManagerImpl : UserManager {

    override var user: User // = must provide an User object

    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

如何允许其他类设置一个UserUserManager()任何时间(不提供初始User旁边的财产申报对象,并让另一个阶级创造和提供一个User实例)?

算一下吧

  1. 接口不能具有lateinit属性
  2. 我希望它User是一个非null值,所以没有可空的属性(User?)
  3. 我想使用字段访问而不是声明并在接口中使用setUser(User)getUser()方法

field kotlin

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

Android SQLite:使用新数据库替换旧数据库或使用迁移脚本

我有一个Android应用程序,它使用SQLite数据库和Active Android作为ORM.在每次应用更新时,我需要使用新的/更新的数据发送我的数据库.这就是我一直在做的事情

  1. 我有一个my_app.db数据库
  2. 我对my_app.db的行,表等进行了修改
  3. 我将修改后的my_app.db保存为my_app_v2.db(依此类推)
  4. 我更换my_app.db与资产的文件夹的文件my_app_v2.db并将其设置为默认的数据库
  5. 我使用新创建的my_app_v2.db编译并运行程序

因此,当用户获取应用程序时,它将使用带有新内容的my_app_v2.db.

我知道Active Android 支持迁移脚本,但在每次数据库更新时,我需要添加/更新大约2000多条记录.因此,对于每个数据库更新,我需要一个包含2000多个插入/更新语句的迁移脚本,这意味着对于3个以上的连续升级,应用程序必须执行大约6000多个语句.

我想知道我用新的数据库替换整个数据库的方法是不好的做法,应该首选迁移脚本.

database sqlite android

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

在干净的架构中结合用例/交互器

我正在开发一个 Android 应用程序,其架构基于Uncle 的 Bob Clean Architecture

到目前为止,我已经实现了很多我的用例/交互器而没有问题。

我有以下用例:

搜索室

  • 主要成功场景

    1. 系统根据给定参数搜索房间
    2. 系统加入房间内的用户
  • 延期

    1. 找不到房间

      a) 系统根据给定的参数创建一个新房间

      b) 系统加入房间的用户

我的问题是:我应该创建一个交互器(SearchOrCreateRoomAndJoin),还是应该创建三个交互器(SearchRoom、 CreateRoom 和JoinRoom)并根据我的用例描述将它们组合起来?

例子:

 Room room = searchRoom.execute(roomOptions)

 if(room != null){

     joinRoom.execute(room)

 }else{

     Room room = createRoom.execute(roomOptions)

     joinRoom.execute(room)
}
Run Code Online (Sandbox Code Playgroud)

重要的是,在我的应用程序的某些方面,我执行了一些交互器,例如SearchRoom

architecture android

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