由下图可知
onSaveInstanceState()是当生命周期进入onStop()时会被呼叫的callback
所以每当app进入後台时,便会执行onSaveInstanceState(),可视爲一个安全措施
onSaveInstanceState()可打包少量的资讯,於当app恢复时使用
在MainActivity覆写
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Timber.i("onSaveInstanceState Called")
}
执行app并收进後台
logcat显示onSaveInstanceState()确实在onStop()後呼叫
fun onSaveInstanceState(outState: Bundle)
参数outState是Bundle型态,此型态爲key-value的集合
key固定爲String,value可存放基本型态
因爲系统将bundle存放在RAM内,且有容量限制
通常存放的容量应远小於100k,否则易导致crash
在MainActivity外层,宣告几个固定常数字串作爲key
const val KEY_REVENUE = "revenue_key"
const val KEY_DESSERT_SOLD = "dessert_sold_key"
const val KEY_TIMER_SECONDS = "timer_seconds_key"
class MainActivity : AppCompatActivity() {...}
onSaveInstanceState()内将revenue(价格,整数型态)加入bundle
outState.putInt(KEY_REVENUE,revenue) //putInt(key,value)
//以及数量,timer计数等都加入
outState.putInt(KEY_DESSERT_SOLD, dessertsSold)
outState.putInt(KEY_TIMER_SECONDS, dessertTimer.secondsCount)
以上就完成将资料打包的动作
接着看onCreate()
override fun onCreate(savedInstanceState: Bundle?) {...}
onCreate()的预设用法一直都是有bundle参数
所以前面打包好後,就可以到onCreate()内取出来
if (savedInstanceState != null) {
revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
dessertTimer.secondsCount =
savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
}
常用模式爲检查bundle不爲null再往下执行
if (savedInstanceState != null)
然後加入bundle是putInt,取出就是getInt
执行app,异动内容後,将app移到後台并使用terminal关闭
检查app的内容状态有保留(实际有时还是会归零,不知道是否因存在记忆体的bundle也被清掉)
但可以看到进後台时,是甜甜圈的状态,回前台又变成杯子蛋糕
原因是甜点图片由这个函数showCurrentDessert()依照dessertsSold的数值,控制现在该显示哪张图片
但这个函数是点击图片才触发,因此当app回到前台尚未点击时
就须在if (savedInstanceState != null)检查中加入
若bundle有资料,表示showCurrentDessert()也该执行
if (savedInstanceState != null) {
revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
dessertTimer.secondsCount =
savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
showCurrentDessert()
}
额外参考: If the activity is being re-created, the onRestoreInstanceState() callback is called after onStart(), also with the bundle. Most of the time, you restore the activity state in onCreate(). But because onRestoreInstanceState() is called after onStart(), if you ever need to restore some state after onCreate() is called, you can use onRestoreInstanceState()
有一些情况属於装置重大的配置改变时,activity / fragment都会被destroy然後重新onCreate
例如改变手机的语系设定,外接萤幕或键盘,旋转手机等等
因爲这些配置改变时,app的内容可能有需要跟着调整的地方
系统爲了符合app的显示,最便利的方式就是重新onCreate()
所以当预期app可能会需要在配置改变时,仍然保持相同状态
就可利用onSaveInstanceState(),将所需的资料存入bundle
以便在重新onCreate()时,恢复先前状态
p.s
在使用模拟机测试时,发现有时调回app,有存入bundle,但还是显示归零
这部分还不太清楚什麽问题,请教导师说可先将手机所有其它在後台的程序都清除再试
就没有再遇到
开一个Google sheet,工作表1更名爲Sheet1
权限设定公开检视
连结网址/ /的中间那串就是这个资料表的SheetID
https://docs.google.com/spreadsheets/d/1uoTGeYfi8SdhxPgS3nFWDb-3-KJMibDpErfIm4c8ZH0/edit#gid=0
例如:
1uoTGeYfi8SdhxPgS3nFWDb-3-KJMibDpErfIm4c8ZH0
到 https://console.developers.google.com/flows/enableapi?apiid=sheets.googleapis.com
建立Google Api 参考
如果出现OAuth的东西先不用理它
选建立凭证
选API金钥
完成後就会看到出现API金钥
可以设定限制
有了凭证权限就可以将如下网址
与资料范围{Range},{Sheet ID},{API Key}合并
一起以浏览器开啓,就会看到JSON格式
https://sheets.googleapis.com/v4/spreadsheets/{Sheet ID}/values/{Range}?key={API Key}
也可以丢到 https://jsoneditoronline.org/ 解析
开一个android studio专案,build.gradle加入dependencies
//Import okHttp dependencies
implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
//Import Retrofit dependencies
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
网路存取权限也别忘了,要加
<uses-permission android:name="android.permission.INTERNET" />
有了JSON就再使用这个Kotlin data class from JSON
套件协助转成data class吧
建立一个BookData.kt档,Generate
data class BookData(
@SerializedName("majorDimension")
val majorDimension: String = "", // ROWS
@SerializedName("range")
val range: String = "", // Sheet1!A2:B4
@SerializedName("values")
val values: List<List<String>> = listOf()
)
然後建立api
internal object APIClient {
lateinit var retrofit: Retrofit
val client: Retrofit
get() {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(2, TimeUnit.MINUTES)
.readTimeout(2, TimeUnit.MINUTES)
.build()
retrofit = Retrofit.Builder()
.baseUrl("https://sheets.googleapis.com/v4/spreadsheets/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
return retrofit
}
val apiInterface: ApiInterface = APIClient.client.create(ApiInterface::class.java)
}
interface ApiInterface {
@GET("{SheetId}/values/{Range}?key={API Key}")
fun getBooks() : Call<BookData>
}
到MainActivity呼叫
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val call = apiInterface.getBooks()
call.enqueue(object : Callback<BookData> {
override fun onResponse(call: Call<BookData>, response: Response<BookData>) {
Log.d("Success!", response.toString())
if (response.isSuccessful) {
response.body()?.values?.forEach { bookList ->
Log.d("api", "${bookList[0]} ${bookList[1]}")
}
}
}
override fun onFailure(call: Call<BookData>, t: Throwable) {
Log.e("Failed Query :(", t.toString())
}
})
}
}
取得Google sheet的资料了
Annotation 要怎麽定义会影响使用这个 library 的使用者体验,annotation ...
test 这是H4标题 ...
最後我们学习如何控制多个表单的开合 ...
前言 本章节,是要讲述如何查看网路设定与设定在主机上的网路资讯。 识别与取得网路介面资讯 在一台主机...
还有一种类型的切版,是EDM切版, EDM切版是什麽呢? 指的就是信里面看到的版面,像是下面这个就是...