How to pass data from onCreate() to onSaveInstanceState()? - android

I have an onCreate() function and an onSaveInstanceState() function in my Main Activity. I have declared a Map in my onCreate() and I want to access the keys of that Map in my onSaveInstanceState() function, so as to save them to the outState bundle.
class MainActivity: AppCombatActivity(){
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
//Want to access the iconMap here, but it is outside of the Map's scope. How do I access it?
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val iconMap = mapOf("contactlessIcon" to getDrawable(R.drawable.ic_contactless_24px), "fingerprintIcon" to getDrawable(R.drawable.ic_fingerprint_black_48dp), "codeIcon" to getDrawable(R.drawable.ic_code_24px))
}
}
I'm fairly new to Android programming, so this might be an easy fix. I want to access the iconMap in the onSaveInstanceState() but it is outside iconMap's scope. I cannot make iconMap a global variable, for this crashes my app.

As #ianhanniballake commented - you shouldn't be saving Drawables that are always the same. In this case it's especially unnecessary since you're onCreate will be called again whenever the activity is restored.
But, to answer your question, you can do it like this :
class MainActivity: AppCombatActivity(){
// define it here, so it's a member of the class
lateinit val iconMap: Map<String, Drawable>
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
//now you can use it here
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//set its value
iconMap = mapOf("contactlessIcon" to getDrawable(R.drawable.ic_contactless_24px), "fingerprintIcon" to getDrawable(R.drawable.ic_fingerprint_black_48dp), "codeIcon" to getDrawable(R.drawable.ic_code_24px))
}
}

Related

Function onCreate not execute on activity start Kotlin Android

I'm new to Android development and I just started learning.
Here's my problem:
My onCreate function in activity_main works normally, it shows everything. Then he logs in and shows me the second activity and there also the onCreate function works but when I go to the third activity the onCreate function does not execute.
DashboardActivity.kt
class DashboardActivity : AppCompatActivity() {
#SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dashboard)
val policy = ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
sendGet()
// sendPostRequest()
}
fun openTest(view: View){
setContentView(R.layout.activity_test);
}
}
TestActivity.kt
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
println("test")
}
}
Could someone guide me or explain what and how? I've been sitting on this for a while, searching the internet and nothing...
I searched the internet, tried solutions, tried to create more activities, turned on debug mode by adding breakpoint and it doesn't even enter this function
To start an Activity, you need to call the following:
startActivity(Intent(this, NextActivity::class.java))
Otherwise, onCreate(Bundle?) will not be called if you do not explicitly call the above.
So in your case, seems that you would like to get to TestActivity in openTest(View), you should have something like this:
fun openTest(view: View) {
startActivity(Intent(this, TestActivity::class.java))
// Calling setContentView() will not trigger another Activity
// setContentView(R.layout.activity_test);
}

How to execute the same function in the onCreate method of all activities?

What is the problem?
I want to add this custom window callback in each activity already implemented in the app, currently I need to manually modify the code of the onCreate method of each activity or make it inherit a class that already has onCreate in the desired way, but I need that this process could be performed without modifying the app's existing code, just adding some initialization.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
window.callback = CustomCallback(window.callback, this)
}
Inside you app Application Class (you'll need to create one, if not done yet), on "onCreate" method, call
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//Code here will run for every activity
}
}
You need a BaseActivity
class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//your code
}
All of your activities need to extends BaseActivity
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
}
}

NullPointerException on this.getPreferences()

class PlayerDetails : AppCompatActivity(), View.OnClickListener, TextWatcher {
val sharedPref = this.getPreferences(Context.MODE_PRIVATE) // NPE
var applicationID = sharedPref.getString("applicationID", null)
private lateinit var binding: ActivityPlayerDetailsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_player_details)
...
}
...
I'm attempting to create a reference to the default Shared Preferences file of my activity by called this.getPreferences().
The results is giving me a NullPointerException - why is this? It's not associated with the UI so it doesn't need to be called after setContentView(). Why would the activity be null at this point?
It's not associated with the UI so it doesn't need to be called after
setContentView()
Right, but it must be called after:
super.onCreate(savedInstanceState)
because this refers to the activity's Context and this Context is only valid after this call.
So what you can do is change the declaration to:
val sharedPref: SharedPreferences? by lazy { this.getPreferences(Context.MODE_PRIVATE) }
this way sharedPref will be initialized the first time it will be used, after the call to super.onCreate(savedInstanceState).
Read more about lazy.
The safest place to call this is after super.onCreate(savedInstnaceState).
Move the line inside onCreate after super.onCreate
val PREFS_NAME = "com.teamtreehouse.colorsarefun.prefs"
var prefs: SharedPreferences? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
prefs = = this.getSharedPreferences(PREFS_FILENAME, 0)
binding = DataBindingUtil.setContentView(this, R.layout.activity_player_details)
...
}
By doing this.getPreferences(Context.MODE_PRIVATE) you called inherit method from AppCompatActivity , Since onCreate is the first callback when activity launched , so things are not set up yet.

Uninitialized exception while initializing "late init" property

I am not really sure if my case is just not possible with late init properties. But let me just ask :)
I have an applicationController which is used in nearly every activity - so i created a BaseActivity
The problem now is that when I want to get dependencies from the application controller in the child activity, I get an Uninitialized Exception.
Thanks for your help!
Because you override wrong method in BaseActivity, that why your app crash.
Solution: Change your code to
abstract class BaseActivity : AppCompatActivity() {
lateinit var applicationController: ApplicationController
// [IMPORTANT] Remove or comment-out this method
// override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
// super.onCreate(savedInstanceState, persistentState)
// applicationController = ApplicationController.getInstance(applicationContext)
// }
// Override this method
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
applicationController = ApplicationController.getInstance(applicationContext)
}
}
Explanation: This section will explain why the code is not working.
kotlin.UninitializedPropertyAccessException
This is a sub-class of RuntimeException, the app will throw this
exception when you access an object by calling properties or methods
on its own before initializing.
When LoginScreen activity is created, Android will call its onCreate method.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login_screen)
emailMatcher = applicationController.getEmailMatcher()
passwordMatcher = applicationController.getPasswordMatcher()
}
The first line super.onCreate(savedInstanceState) will call onCreate method of its parent, in this case onCreate (bundle) in BaseActivity activity will be called.
Unfortunately, in BaseActivity activity, you override and put the initial code for applicationController in another method onCreate(bundle, persistentState) which quite similar to onCreate (bundle). The difference between them is number of params. As a result, at this time applicationController is still not initialized.
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
applicationController = ApplicationController.getInstance(applicationContext)
}
Until the app reach this line
emailMatcher = applicationController.getEmailMatcher()
Because you call getEmailMatcher method on an uninitialized object applicationController, so the app throws kotlin.UninitializedPropertyAccessException and make your app crash.

How to know if system is restoring from savedInstanceState in viewModel

Using Architecture Component, When onCreate, I use the ViewModel to fetch the data.
#OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
fetchData()
}
However, if it is being restored from savedInstanceState, I would like to avoid calling fetchData. How could I do so?
i.e. using the old way, I could do below.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedinstanceState == null) {
fetch()
}
}
Execute the fetchData()call inside the ViewModel constructor.

Categories

Resources