我是一个经验丰富的iOS开发人员,享受并找到有用的本书。但是,我有一个建议。

避免 魔术数字重复开奖结果3d 是软件开发的重要原则。 TimeFighter示例应用程序不会展示这些原则,我担心的是软件开发的新人可能会学习坏习惯,并且由于他们的尝试应用程序中的魔术号码或重复开奖结果3d可能错过了就业机会。我建议修改TimeFighter,以便没有魔术号码或重复的开奖结果3d。

这是重复的开奖结果3d:

countDownTimer = object : CountDownTimer(initialCountDown, countDownInterval) {
    override fun onTick(millisUntilFinished: Long) {
      timeLeft = millisUntilFinished.toInt() / 1000

      val timeLeftString = getString(R.string.time_left, Integer.toString(timeLeft))
      timeLeftTextView.text = timeLeftString
    }

    override fun onFinish() {
      endGame()
    }
}

...

countDownTimer = object : CountDownTimer((timeLeft * 1000).toLong(), countDownInterval) {
    override fun onTick(millisUntilFinished: Long) {

      timeLeft = millisUntilFinished.toInt() / 1000

      val timeLeftString = getString(R.string.time_left, Integer.toString(timeLeft))
      timeLeftTextView.text = timeLeftString
    }

    override fun onFinish() {
      endGame()
    }
}

这是Magic Number:

val initialTimeLeft = getString(R.string.time_left, Integer.toString(60))

这也是开奖结果3d重复,因为60表示与此行中的6000相同的概念:

internal var initialCountDown: Long = 60000

I have refactored GameActivity.kt to fix both problems.

class GameActivity : AppCompatActivity() {
    internal lateinit var gameScoreTextView: TextView
    internal lateinit var timeLeftTextView: TextView
    internal lateinit var tapMeButton: Button
    internal var gameStarted = false
    internal lateinit var countDownTimer: CountDownTimer
    internal var initialCountDown = 60000
    internal var countDownInterval = 1000
    internal var timeLeft = initialCountDown / countDownInterval
    internal var score = 0
    internal val TAG = GameActivity::class.java.simpleName
    internal val millisecondsPerSecond = 1000

    companion object {
        private val SCORE_KEY = "SCORE_KEY"
        private val TIME_LEFT_KEY = "TIME_LEFT_KEY"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_game)
        Log.d(TAG, "onCreate called. Score is: $score")
        gameScoreTextView = findViewById<TextView>(R.id.game_score_text_view)
        timeLeftTextView = findViewById<TextView>(R.id.time_left_text_view)
        tapMeButton = findViewById<Button>(R.id.tap_me_button)
        tapMeButton.setOnClickListener { v -> incrementScore() }
        if (savedInstanceState != null) {
            restoreGame(savedInstanceState.getInt(SCORE_KEY), savedInstanceState.getInt(TIME_LEFT_KEY))
        } else {
            resetGame()
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt(SCORE_KEY, score)
        outState.putInt(TIME_LEFT_KEY, timeLeft)
        countDownTimer.cancel()
        Log.d(TAG, "onSaveInstanceState: Saving Score: $score & Time Left: $timeLeft")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy called.")
    }

    private fun incrementScore() {
        if (!gameStarted) {
            startGame()
        }
        score++
        gameScoreTextView.text = getString(R.string.your_score, Integer.toString(score))
    }

    private fun resetGame() {
        score = 0
        timeLeft = initialCountDown / countDownInterval
        initializeGame()
        gameStarted = false
    }

    private fun initializeGame() {
        gameScoreTextView.text = getString(R.string.your_score, Integer.toString(score))
        timeLeftTextView.text = getString(R.string.time_left, Integer.toString(timeLeft))
        countDownTimer = object : CountDownTimer((timeLeft * millisecondsPerSecond).toLong(), countDownInterval.toLong()) {
            override fun onTick(millisUntilFinished: Long) {
                timeLeft = millisUntilFinished.toInt() / millisecondsPerSecond
                val timeLeftString = getString(R.string.time_left, Integer.toString(timeLeft))
                timeLeftTextView.text = timeLeftString
            }
            override fun onFinish() { endGame() }
        }
    }

    private fun startGame() {
        countDownTimer.start()
        gameStarted = true
    }

    private fun endGame() {
        Toast.makeText(this, getString(R.string.game_over_message, Integer.toString(score)), Toast.LENGTH_LONG).show()
        resetGame()
    }

    private fun restoreGame(score: Int, timeLeft: Int) {
        this.score = score
        this.timeLeft = timeLeft
        initializeGame()
        startGame()
    }
}

嗨kithril,

感谢您与此建议伸出援手。你完全正确,我们在第4章中遵守这些原则并没有做好。

我们将在船上接受这一点,并确保我们在未来版本的Android学徒中遵守这些原则。

与此同时,我们希望您喜欢这本书。让我们知道您是否有建议,我们会乐意倾听。

谢谢,

达里尔

这本书很强大,或者至少在发布时,它可能涵盖了Android,Android Studio和Kotlin的那个当前版本。

Since you asked for suggestions, though, I reiterate the request of other posters that you update the book. There have been no updates for the current versions of Android, Android Studio, and Kotlin, which means that if I use the book, I must either learn old stuff or (the code in the book doesn’t compile as-is && the Android Studio instructions are incorrect). Today I found the Chapter-11 app impossible to get working, either by creating it from scratch or by using the starter project. As an Android apprentice, I lack the expertise to troubleshoot Gradle errors. This experience did not meet my high expectations for Ray Wenderlich products.

我在论坛上没有提到过这个,因为我已经阅读了几个线程,约会几个月,这本书很快就会更新。

第15章使用已弃用的位置SDK。新的一个功能非常不同,似乎要求设置结算。 //developers.google.com/places/android-sdk/client-migration

感谢您的反馈!

该计划是很快发布一本书的书。新版本已更新,以考虑到Android Studio,Gradle和Kotlin的更改。我还可以确认第15章被更新以使用新的位置SDK。

当第二版准备好享受人们享受时,我们将宣布。

达里尔