Simple Kotlin Project does not show any UI - android

I have a very simple Android Project in Kotlin. Just to dig in Kodein. I can not see the two TextViews in the main_layout?
I have used MVP pattern for the only MainActivity I have there..
The app starts without a crash and is show a blank white screen.
Any hints?
BaseActivity:
abstract class BaseActivity<V : BasePresenter.View> : AppCompatActivity(), BasePresenter.View {
protected abstract val layoutResourceId : Int
protected abstract val presenter : BasePresenter<V>
val kodeinMu = LazyKodein(appKodein)
protected abstract fun initUI()
protected abstract fun initPresenter()
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(layoutResourceId)
initUI()
initPresenter()
}
override fun onPause() {
super.onPause()
presenter.pause()
}
override fun onStop() {
super.onStop()
presenter.stop()
}
override fun onDestroy() {
super.onDestroy()
presenter.destroy()
}
protected fun toast(s: String) {
System.out.println("TAG $s")
}
}
I have read that it is because of API 28 you only can see on API_28 devices or emulators. Either emulator or on real device were also blanked out.

You override the wrong onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) in you activity:
use this : onCreate(savedInstanceState: Bundle?)

Related

I cant solve this error "lateinit property dataBinding has not been initialized"

I have base activity< T : ViewDataBinding , VM : ViewModel > extends AppCompatActivity()
and i initialize view binding and view model but when run the app i get this error "lateinit property dataBinding has not been initialized"
I don't know what I miss or what the wrong
Below is Base Activity Code
open abstract class BaseActivity<T : ViewDataBinding , VM : ViewModel> : AppCompatActivity() {
lateinit var dataBinding : T
lateinit var viewModel : VM
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
dataBinding = getViewBinding()
setContentView(dataBinding.root)
viewModel = generateViewModel()
}
abstract fun getViewBinding(): T
abstract fun generateViewModel(): VM
and this My HomeActivity
class HomeActivity : BaseActivity<ActivityHomeBinding, HomeViewModel>() {
override fun getViewBinding(): ActivityHomeBinding = ActivityHomeBinding.inflate(layoutInflater)
override fun generateViewModel(): HomeViewModel {
return ViewModelProvider(this).get(HomeViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dataBinding.vm = viewModel
}
}
this is the error message
Because in your base class the onCreate() with 2 parameters is not going to get called during the activity's lifecycles. And in your subclass you override the onCreate() with a parameter.
Just simple change your base class to override the onCreate() with a parameter to fix the problem. And the other thing is you implement these class the java's way.
You can just make it better this way:
BaseClass
abstract class BaseActivity<T : ViewDataBinding , VM : ViewModel> : AppCompatActivity() {
protected abstract val dataBinding : T
protected abstract val viewModel : VM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(dataBinding.root)
}
}
Subclass:
class HomeActivity : BaseActivity<ActivityHomeBinding, HomeViewModel>() {
override val viewModel get() = ViewModelProvider(this).get(HomeViewModel::class.java)
override val dataBinding get() = ActivityHomeBinding.inflate(layoutInflater)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dataBinding.vm = viewModel
}
}
When you are calling super.onCreate(savedInstanceState) in your HomeActivity, the onCreate from android's Activity is called, but not the onCreate from BaseActivity - because it expected second param persistentState.
So you can do this options to fix the issue:
call super method with 2 params in your HomeActivity
class HomeActivity ... {
...
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
dataBinding.vm = viewModel
}
OR
use onCreate with one param in your BaseActivity
open abstract class BaseActivity<T : ViewDataBinding , VM : ViewModel> : AppCompatActivity() {
lateinit var dataBinding : T
lateinit var viewModel : VM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...

How to implement a BaseActivity in mvvm architecture? Without using dependency Injection

I am currently learning MVVM architecture.
I tried to make a BaseActivity class.
My BaseActivity:
abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
AppCompatActivity(),
EventListener {
lateinit var binding: Binding
private var viewModel: ViewModel? = null
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
binding = DataBindingUtil.setContentView(this, layoutid)
this.viewModel = viewModel ?: getViewModel()
binding.setVariable(getBindingVariable(), viewModel)
binding.executePendingBindings()
}
#get: LayoutRes
abstract val layoutid: Int
abstract fun getViewModel(): ViewModel
abstract fun getBindingVariable(): Int
private fun getViewModelClass(): Class<ViewModel> {
val type = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
return type as Class<ViewModel>
}
}
Now I am using this BaseActivity in my SplashActivity:
class SplashActivity : BaseActivity<SplashActivityViewModel, ActivitySplashBinding>() {
private lateinit var viewModel: SplashScreenViewModel
override fun onFailure(message: String) {}
override fun onStarted() {}
override fun onSuccess() {}
override fun getViewModel(): SplashActivityViewModel {
viewModel = ViewModelProvider(this).get(SplashActivityViewModel::class.java)
return viewModel
}
override fun getBindingVariable(): Int {
return BR.splash_viewmodel
}
override val layoutid: Int
get() = R.layout.activity_splash
}
I have used following answer as a reference to implement my BaseActivity.kt: https://stackoverflow.com/questions/55289334/how-to-have-generic-viewmodel-in-baseactivty-class
But I am getting a blank white screen while running the app.
Can someone please tell me what is the problem here or how to make this BaseActivity (without using dependency injection)?
you have overridden the wrong onCreate
override fun onCreate(savedInstanceState: Bundle?) {
I did play around with something like that few years ago, you can find my approach here

startActivity skips onCreate()

I have a simple case of Activity1 -> Activity2.
In the past when I've used startActivity(Intent(this, Activity2::class.java)) there have been no issues and the onCreate() method of Activity2 would be called.
In my current case this is not happening. I have logs in the onCreate() method and they are never hit. But if I create a onStart() method it enters there. However, never in my logs for the lifetime of the application does onCreate() of Activity2 ever get hit. How is this possible. onCreate is a requirement before onStart I thought.
Here is the actual code I'm referencing above.
class Activity1 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.d("onCreate")
setContentView(R.layout.activity_splash)
startActivity(Activity2.getIntent(this))
}
}
class Activity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
Timber.d("onCreate") // Never gets touched
}
override fun onStart() {
super.onStart()
Timber.d("onStart"); // Is hit with no problems.
}
companion object {
fun getIntent(#NonNull context: Context) : Intent {
return Intent(context, Activity2::class.java)
}
}
}
You overrode the wrong onCreate - you do not want to use the PersistableBundle version. Change your onCreate to only take the savedInstanceState: Bundle? parameter:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.d("onCreate") // Now it'll be called
}

Testing BaseActivity

I have a BaseActivity, which has Dagger behavior inside:
abstract class BaseActivity : DaggerAppCompatActivity(), HasSupportFragmentInjector {
#Inject
lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState, persistentState)
/**
* Method that gets called after the [onCreate] method
*/
public override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
applyDebugOverlay(this)
}
override fun supportFragmentInjector() = fragmentDispatchingAndroidInjector
}
Now I want to test, that applyDebugOverlay(this) is calling. For this, I use Robolectric in my AbstractActivityTest
#Test
fun testDebugOverlayIsShown() {
underTest.onPostCreate(Bundle())
val buildTimeStamp = underTest.inc_debugOverlay_tv_date.text
assert(buildTimeStamp.isNotEmpty())
}
But I get "No injector factory bound for Class" error, and it is not possible to bind BaseActivity with #ContributesAndroidInjector in my ActivityBuilder Class (would get another error).

onCreate in abstract parent activity no called in kotlin

I declared a child of MapActivity:
class RecordingActivity : MapActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("RecirdingActivity", "InitializeMap") //called
}
override fun getView(): Int {
return R.layout.activity_recording
}
}
I make a call to start this activity from my main activity:
fab.setOnClickListener {
Log.d("MainActivity", "fabClick") //called
startActivity(intentFor<RecordingActivity>())
}
and I have the abstract activity:
abstract class MapActivity: AppCompatActivity(), OnMapReadyCallback {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(getView())
initializeMap()
Log.d("MapActivity", "InitializeMap")//not called
}
}
and onCreate method of this activity is never called
I traced it with a debugger and I had the same result.
What am I doing wrong?
there seems to be two solutions:
maybe the onCreate you actually want to override in MapActivity has the signature onCreate(android.os.Bundle):
abstract class MapActivity: AppCompatActivity(), OnMapReadyCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(getView())
initializeMap()
Log.d("MapActivity", "InitializeMap")
}
}
the documentation of the onCreate(android.os.Bundle, android.os.PersistableBundle) method that is being overridden in MapActivity suggests that persistableMode for the activity in the AndroidManifest.xml needs to be set to persistAcrossReboots for it to be called...but MapActivity is abstract, so you would need to set the attribute for its subclasses instead. in this case that would be RecordingActivity.
<?xml version="1.0" encoding="utf-8"?>
<manifest>
...
<application>
...
<activity
android:name=".RecordingActivity"
android:persistableMode="persistAcrossReboots"/>
...
</application>
...
</manifest>
Simple answer: method onCreate(savedInstanceState: Bundle?) and onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) is not the same.
You need to override the same method, probably the first one.

Categories

Resources