每当我有一个足够大的函数可以分解成更小的函数时,我总是将较小的函数创建为较大函数作用域的嵌套函数,如下所示:
class Foo {
fun bar() : Int {
fun a() : Int {
// Do a load of stuff
return 1
}
fun b() : Int {
// Do a load of stuff
return 1
}
return a() + b()
}
}
Run Code Online (Sandbox Code Playgroud)
我这样做是因为它提供了这些功能的封装,这些功能目前只有一个调用点;封闭范围的那个。
然而,我在工作中经常被要求将这些函数重构为封闭类的私有函数,如下所示:
class Foo {
fun bar() : Int {
return a() + b()
}
private fun a() : Int {
// Do a load of stuff
return 1
}
private fun b() : Int {
// …
Run Code Online (Sandbox Code Playgroud) 我正在Android上实现应用链接.我们的服务器团队已经托管assetlinks.json
在我们的开发端点上/.well-known/assetlinks.json
.
在我的应用程序清单中,我根据官方文档编写了intent过滤器,如下所示:
<!-- Intent filter for supporting deep linking (referred to as magic login links) -->
<intent-filter
android:autoVerify="true"
tools:ignore="UnusedAttribute">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="@string/app_link_login_host"
android:scheme="https" />
<data
android:host="@string/app_link_login_host"
android:scheme="http" />
</intent-filter>
Run Code Online (Sandbox Code Playgroud)
现在,我的理解是,当应用程序第一次运行时,Android操作系统将搜索清单对于包含主机/方案对,其中所有的意图过滤器autoVerify=true
和VIEW
行动,并DEFAULT
和BROWSABLE
类别都存在.然后它将转到主机URL并assetlinks.json
从/.well-known/
路径请求文件,并使用此json文件中的SHA哈希和包名称来验证应用程序是否允许接受来自给定主机的深层链接.如果此操作成功,则应将应用程序标记为status: always
与意图过滤器内主机提供的链接相关联.如果失败,那么应用程序将被标记为status: never
主机.
但是,我们的服务器团队已经为登台设置了一个新的端点,他们没有将assetlinks.json
文件上传到/.well-known/
路径(事实上他们根本没有托管它).然而,应用程序仍然可以接受来自清单中指定的主机的链接(由于assetlinks
端点上没有文件而应该验证失败).
这是当我意识到也许dev端点assetlinks.json
文件从未用于验证应用程序时,我只是注意到因为深层链接仍然在暂存环境中工作(当它不应该有).
这是Android OS的一个错误(换句话说,它根本不进行资产链接检查?).是的,在安装指向登台的版本之前,我卸载了指向开发服务器的旧应用程序...
以下是官方文档:
https://developer.android.com/training/app-links/
这是段落,特别是我的问题的根源(因为它明确指出,如果任何主机不解析路径上的assetlinks.json
文件/.well-known/
(包括assetlinks.json …
我正在创建一个新的android项目,并决定将新的AndroidX替换为支持库,有关支持的文档,请参见:https : //developer.android.com/jetpack/androidx/migrate。
我按照字母的步骤进行操作,并在同步gradle之后,可以访问androidx
名称空间和其中包含的各种类。但是,在创建我的应用程序类时,我想从中继承androidx.multidex.MultiDexApplication
(可以在上面的链接的表中看到)。但是,整个multidex
软件包不存在。
有人解决了这个问题吗?有指针吗?
在工作中,我们尝试在通过 firebase 门户创建动态链接时使用可选的活动跟踪 UTM 参数。
动态链接工作正常,据我从所有官方文档中得知,在创建动态链接时在最后一个可选步骤中添加 UTM 值应该会导致这些值与dynamic_link_app_open
事件一起发送。
但是,当我们查看事件的事件或转化选项卡时,我们没有看到任何归因值dynamic_link_app_open
。我们看到正在发送该事件,但我们只是没有获得广告系列归因值,因此我们不知道哪些广告系列导致了这些事件和转化。
这个特定功能的文档真的很缺乏,这让我们的营销部门感到沮丧,最终与开发人员(即我)合作。
我已经开发了一个解决方法,但它是一个黑客:
在 firebase 门户上创建动态链接时,我将utm_source
,utm_medium
和utm_campaign
查询字符串直接放入深层链接中(出于安全原因,不是我们实际的深层链接,但您明白了):
https://www.example.com?utm_source=Test&utm_medium=Test&utm_campaign=Test
Run Code Online (Sandbox Code Playgroud)
然后在客户端中,我添加了代码,在通过 firebase 动态链接 SDK 传递动态链接后,将这些代码从生成的深层链接中提取出来。有了这 3 位信息,我可以app_open
通过FirebaseAnalytics
SDK将事件发送到 Firebase 分析,如下所示:
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(this, pendingDynamicLinkData -> {
if (pendingDynamicLinkData != null) {
Uri optionalDynamicDeepLink = pendingDynamicLinkData.getLink();
if (optionalDynamicDeepLink != null) {
List<String> utmSource = optionalDynamicDeepLink.getQueryParameters(UTM_SOURCE);
List<String> utmCampaign = optionalDynamicDeepLink.getQueryParameters(UTM_CAMPAIGN);
List<String> utmMedium = optionalDynamicDeepLink.getQueryParameters(UTM_MEDIUM);
if (!utmSource.isEmpty() && !utmCampaign.isEmpty() && !utmMedium.isEmpty()) {
String utmSourceParam = …
Run Code Online (Sandbox Code Playgroud) android event-tracking firebase firebase-analytics firebase-dynamic-links
我正在尝试创建一个 Playstore 版本。
我已按照指南创建上传密钥和密钥库,一字不差: https: //developer.android.com/studio/publish/app-signing#generate-key
然后,我使用上传密钥生成了我的应用程序的签名应用程序包,如下所示:https: //developer.android.com/studio/publish/app-signing#sign_release
这导致了一个名为:app-release.aab
现在,由于此应用程序是全新的,并且以前从未发布过,因此无需导出加密密钥并“选择将现有应用程序加入 Play 应用程序签名”,因为我在创建新应用程序时已经选择了此选项当然,我之前从未上传过使用此应用程序列表的另一个密钥签名的 APK。
接下来,我转到 Play 控制台并创建一个新的生产版本。但是,当我上传app-release.aab
文件时,我看到以下错误消息:
"The Android App Bundle was not signed."
这完全令人困惑。
据我所知,我已严格按照说明进行操作,并且我尝试在谷歌上进行一些研究,但没有找到答案。
有这个过程经验的人可以帮助我吗?
编辑:
我对整个过程不了解的是,我被要求在本地生成上传密钥,但实际上从未将密钥上传到 google play 控制台 - Google 到底如何知道该应用程序是使用上传密钥签名的,如果他们从未见过上传密钥?但是,生成上传密钥的文档中没有任何地方指出我应该使用本地生成的密钥执行任何操作,而不是使用它在本地生成签名的应用程序包,这正是我所做的。
编辑2:
以下屏幕截图显示了我创建上传密钥并使用上传密钥生成应用程序签名包的过程:
keytool -printcert -jarfile app-release.aab
然后,相当奇怪的是,从捆绑包所在的目录运行的结果:
TO BE CLEAR:
The most likely part of the code which has the problem is the connect function, which you can find in the code block.
EDIT:
I've had a good dig through LogCat and found something interesting (this occurred the exact moment enableNetwork was called):
2018-12-04 20:13:14.508 1315-7000/? I/WifiService: enableNetwork uid=10158 disableOthers=true
2018-12-04 20:13:14.508 1315-1607/? D/WifiStateMachine: connectToUserSelectNetwork netId 49, uid 10158, forceReconnect = false
2018-12-04 20:13:14.541 1315-1607/? D/WifiConfigStore: Writing to stores completed in 14 ms.
2018-12-04 20:13:14.541 1315-1607/? E/WifiConfigManager: …
Run Code Online (Sandbox Code Playgroud) 我很习惯使用 RX 来处理并发,但是,在我目前的工作中,我们混合使用了 AsyncTask、Executors + Handlers、Threads 和一些 LiveData。现在我们正在考虑转向使用 Kotlin Coroutines(事实上已经开始在代码库的某些地方使用它)。
因此,我需要开始关注协程,最好是利用我现有的并发工具知识来加快进程。
我曾尝试为他们关注 Google 代码实验室,虽然它让我有所了解,但它也提出了许多悬而未决的问题,因此我尝试通过编写一些代码、调试和查看日志输出来弄脏我的手。
据我了解,协程由 2 个主要构建块组成;挂起函数是你工作的地方,协程上下文是你执行挂起函数的地方,这样你就可以处理协同程序将在哪些调度程序上运行。
下面我有一些代码,它的行为符合我的预期。我已经使用 Dispatchers.Main 设置了一个协程上下文。因此,正如预期的那样,当我启动协程时,由于以下原因,getResources
它最终会阻塞 UI 线程 5 秒Thread.sleep(5000)
:
private const val TAG = "Coroutines"
class MainActivity : AppCompatActivity(), CoroutineScope {
override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
log("onCreate", "launching coroutine")
launch {
val resource = getResource()
log("onCreate", "resource fetched: $resource")
findViewById<TextView>(R.id.textView).text = resource.toString()
}
log("onCreate", "coroutine launched")
}
private suspend fun getResource() …
Run Code Online (Sandbox Code Playgroud) 我正在尝试学习Haskell,但是我迷上了某些东西。到目前为止,我已经了解到函数签名符合以下约定:
<name> :: <type constraint A> => <input type A> -> <input type B> -> .. <input type X> -> <return type>
Run Code Online (Sandbox Code Playgroud)
因此,以我目前的理解为例:
-- Returns input + 2
add2 :: Int -> Int
add2 x = x + 2
-- Returns the result of applying a function that takes an int and returns an int on an input int
adds2 :: (Int -> Int) -> Int -> Int
adds2 func x = func x
-- Returns a String with "Hello" …
Run Code Online (Sandbox Code Playgroud) 我一直在学习 Haskell,但在我的日常工作中,我正在编写 Kotlin/Java。
我遇到过 Eta ( https://eta-lang.org/ ),这是一种 Haskell 方言,可编译为 Java 字节码并在 JVM 上运行。在网站上,它声明它有:
Robust Interoperability
Eta has a strongly-typed Foreign Function Interface (FFI) that allows you to safely interoperate with Java.
Run Code Online (Sandbox Code Playgroud)
但在页面下方有一个“即将推出”部分,其中列出了互操作。所以我的问题,在我去设置一个开发环境的麻烦之前:
这是官方支持的吗?
我试图弄清楚如何在 Kotlin 中将一个函数声明性地定义为其他两个函数的组合,但我很挣扎。这是我的代码:
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): Int {
return a.invoke() + b.invoke()
}
Run Code Online (Sandbox Code Playgroud)
compose 函数的想法是,它将接受两个函数作为输入(这两个函数都接受两个 Int 并返回一个 Int)并返回两个传递函数的结果之和。问题是我必须调用传递的函数来计算它们的总和(显然大声笑)但我不知道我希望在 compose 方法内部调用的值(它们是传递给函数的值)。
我在这里完全错过了什么吗?我知道这在像 Haskell 这样的语言中是可能的,在 Kotlin 中是否可能?
android ×5
kotlin ×4
haskell ×2
android-wifi ×1
androidx ×1
deep-linking ×1
eta ×1
firebase ×1
google-play ×1
jvm ×1
rx-java2 ×1
wifimanager ×1