rm *_*-rf 6 random android kotlin
我创建了一个应用程序,它应该从图像数组中随机选择一个图像。在我的模拟器 Nexus 5X Android 5.1 上,一切都按预期运行。一旦我在真实设备 Galaxy Note 10 Lite 上尝试相同的操作,我总是会以相同的顺序得到相同的“随机”数字。我首先需要重新启动手机以生成一个新的“随机”数字列表,然后该列表始终相同。示例:我的数组包含 200 个元素,我在 Galaxy 上打开应用程序,它为图像 ID 选择以下随机数:43、12、176、33、2、78。然后我关闭应用程序并再次打开应用程序,现在它又具有完全相同的“随机”数字:43、12、176、33、2、78。我需要重新启动手机才能获取新的随机数字,这些数字将保持不变,直到我再次重新启动手机。在我的模拟器上,一切正常,当我按预期重新启动应用程序时,我总是会得到新的随机数。
\n这是我的应用程序的完整代码,没有图像数组列表:
\nMainActivity.kt
\nclass MainActivity : AppCompatActivity() {\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n setContentView(R.layout.activity_main)\n\n val imageList = arrayOf(Image(R.drawable.image1, false),\n Image(R.drawable.image2, false),\n Image(R.drawable.image3, false))\n\nval imageViewMain = findViewById<ImageView>(R.id.imageViewMain)\n loadNextImage(imageViewMain, imageList)\n\n imageViewMain.setOnClickListener {\n val dialogClickListener =\n DialogInterface.OnClickListener { _, which ->\n when (which) {\n DialogInterface.BUTTON_POSITIVE -> {\n loadNextImage(imageViewMain, imageList)\n }\n DialogInterface.BUTTON_NEGATIVE -> { }\n }\n }\n val builder: AlertDialog.Builder = AlertDialog.Builder(this)\n builder.setMessage("N\xc3\xa4chstes Bild?").setPositiveButton("Ja", dialogClickListener)\n .setNegativeButton("Nein", dialogClickListener).show()\n }\n}\n\nprivate fun getNextChoice(): Int {\n return (0..1).random()\n}\n\nprivate fun getNextImage(imageList: Array<Image>): Int {\n val listSize = imageList.size\n var imageId: Int\n do {\n imageId = (0 until listSize).random()\n } while (imageList[imageId].played)\n\n imageList[imageId].played = true\n return imageList[imageId].image\n}\n\nprivate fun loadNextImage(imageViewMain: ImageView, imageList: Array<Image>) {\n val imageQuestionmark = R.drawable.questionmark\n val nextChoice = getNextChoice()\n if (nextChoice == 0) {\n imageViewMain.load(imageQuestionmark)\n } else if (nextChoice == 1) {\n imageViewMain.load(getNextImage(imageList))\n }\n Toast.makeText(this, "Bild hat geladen", Toast.LENGTH_SHORT).show()\n}\n}\nRun Code Online (Sandbox Code Playgroud)\n图像:
\ndata class Image(\n val image: Int,\n var played: Boolean\n)\nRun Code Online (Sandbox Code Playgroud)\n编辑: \n我尝试了 cactustictacs 在评论中建议的内容,并创建了一个简单的应用程序,一次使用 kotlin 随机函数,一次使用 java 随机函数。这是我使用的代码:
\n科特林:
\nimport androidx.appcompat.app.AppCompatActivity\nimport android.os.Bundle\nimport android.widget.Button\nimport android.widget.Toast\n\nclass MainActivity : AppCompatActivity() {\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n setContentView(R.layout.activity_main)\n\n val buttonTest = findViewById<Button>(R.id.buttonTest)\n\n buttonTest.setOnClickListener {\n val getRandomNumber = (0..999).random()\n Toast.makeText(this, getRandomNumber.toString(), Toast.LENGTH_SHORT).show()\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n爪哇:
\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport android.os.Bundle;\nimport android.widget.Button;\nimport android.widget.Toast;\n\nimport java.util.Random;\n\npublic class MainActivity extends AppCompatActivity {\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n setContentView(R.layout.activity_main);\n\n Button buttonTest = (Button) findViewById(R.id.buttonTest);\n\n buttonTest.setOnClickListener(v -> {\n int randomNumber = new Random().nextInt(999);\n Toast.makeText(this, "" + randomNumber, Toast.LENGTH_SHORT).show();\n });\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n在 Kotlin 上,我得到的行为与最初的问题相同,无论我对应用程序做什么(我什至可以卸载并再次安装),我总是得到相同的数字集。在 Java 上,它按预期工作,一旦我关闭应用程序,我就会得到一组新的数字。所以错误肯定出在 kotlin 上。
\n也许有帮助,我的 Android 版本是 12,我的手机是 Galaxy Note 10 Lite。
\n这是 Kotlin 默认 Random 类的一个非常糟糕的实现。Java Random 类尝试在每个新实例上始终使用不同的种子,而 Kotlin 在整个设备中硬编码相同的种子。这怎么可能成为 Random 实现的默认行为。我花了很多时间才理解它。
参见Java实现:
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
Run Code Online (Sandbox Code Playgroud)
啊啊啊,Kotlin 来了:
companion object Default : Random(), Serializable {
private val defaultRandom: Random = defaultPlatformRandom()
private object Serialized : Serializable {
private const val serialVersionUID = 0L
private fun readResolve(): Any = Random
}
private fun writeReplace(): Any = Serialized
override fun nextBits(bitCount: Int): Int = defaultRandom.nextBits(bitCount)
override fun nextInt(): Int = defaultRandom.nextInt()
override fun nextInt(until: Int): Int = defaultRandom.nextInt(until)
override fun nextInt(from: Int, until: Int): Int = defaultRandom.nextInt(from, until)
Run Code Online (Sandbox Code Playgroud)
defaultRandom 是一个单例,总是以相同的种子启动......
(我通过 Android Studio 源获取了此代码...)
注意:所以这是 kotlin 版本 1.7.10 和 Android api 小于 33-34 的错误。已于 20 年 7 月 1 日修复...
| 归档时间: |
|
| 查看次数: |
3572 次 |
| 最近记录: |