Why variable is not initialized even if it was created? - android

I don't really understand why logFile(and loggingProcess) are not initialized. The logcat shows that the file exists and createLogFile() method had been called when Activity was created, but when I'm trying to uploadLogs() from the Activity(using SandboxApp().uploadLogs()) it throws an exception
class SandboxApp: Application(), MyCallbacks {
companion object {
#JvmField
val TAG = SandboxApp::class.java.simpleName
}
private lateinit var loggingProcess: Process
private lateinit var logFile: File
private lateinit var fileDirectory: File
private var isLogging = false
private val formatter = SimpleDateFormat("dd-MM-yyyy_HH-mm", Locale.getDefault())
private lateinit var workManager: WorkManager
override fun onCreate() {
super.onCreate()
workManager = WorkManager.getInstance(this)
registerActivityLifecycleCallbacks(this)
}
fun createLogFile() {
val currentTime = formatter.format(Calendar.getInstance().time)
val fileName = "logs-$currentTime.log"
fileDirectory = File(filesDir.absolutePath + File.separator + "sandboxLog")
fileDirectory.mkdirs()
Log.d(TAG, "FileDir exists? $fileDirectory, ${fileDirectory.exists()}")
logFile = File(fileDirectory, fileName)
logFile.createNewFile()
Log.d(TAG, "File exists? $logFile, ${logFile.exists()}")
}
fun startLogging() {
isLogging = true
loggingProcess = Runtime.getRuntime().exec("logcat -f $logFile")
}
private fun stopLogging() {
isLogging = false
loggingProcess.destroy()
}
fun uploadLogs() {
stopLogging()
val data = Data.Builder()
.putString("file path", logFile.absolutePath)
.build()
val request = OneTimeWorkRequest.Builder(LogsWorker::class.java)
.setInputData(data)
.build()
workManager.enqueue(request)
createLogFile()
startLogging()
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
super.onActivityCreated(activity, savedInstanceState)
Log.d(TAG, "onActivityCreated method")
createLogFile()
startLogging()
}
}
This is the exception, tha same is for the loggingProcess variable
2020-08-04 15:55:51.338 8741-8741/com.example.sandboxlog E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.sandboxlog, PID: 8741
kotlin.UninitializedPropertyAccessException: lateinit property logFile has not been initialized
at com.example.sandboxlog.SandboxApp.uploadLogs(SandboxApp.kt:66)
at com.example.sandboxlog.MainActivity$onCreate$2.onClick(MainActivity.kt:33)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
upd: onCreate method of MainActivity, where uploadLogs is being called
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(TAG, "MainActivity created")
Thread.setDefaultUncaughtExceptionHandler(CrashHandler())
button.setOnClickListener {
// creating an exception
RequestBody.create(MultipartBody.FORM, exceptionFile!!)
}
buttonSend.setOnClickListener {
SandboxApp().uploadLogs()
}
buttonSecondActivity.setOnClickListener {
Log.d(TAG, "Starting second activity")
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
}
}

You shouldn't create an instance of your app class SandboxApp by yourself, it is done by the system. To have access to the instance of SandboxApp you can use ctx.applicationContext property:
val app = context.applicationContext as SandboxApp
app.uploadLogs()
So in the OnClickListener it will look like the following:
buttonSend.setOnClickListener {
val app = applicationContext as SandboxApp
app.uploadLogs()
}

Related

NullPointerException: NfcAdapter.getDefaultAdapter(this) must not be null - Kotlin

I developed an application to get NFC adapter using NfcAdapter.getDefaultAdapter(this) function. But it gives NullPointerException - NfcAdapter.getDefaultAdapter(this) must not be null.
class TappingActivity : BaseActivity() {
private lateinit var mNfcAdapter: NfcAdapter
private lateinit var mFusedLocationClient: FusedLocationProviderClient
private lateinit var mBroadcastReceiver: BroadcastReceiver
private lateinit var mAdapter: RecyclerViewAdapter<SecurityPoint, ViewHolder>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tapping)
ButterKnife.bind(this)
setSupportActionBar(toolbar)
savedInstanceState?.let {
lastLoggedPremisesID = it.getInt("lastLoggedPremisesID")
}
mNfcAdapter = NfcAdapter.getDefaultAdapter(this)
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
if (!mNfcAdapter.isEnabled) {
snack(getString(R.string.str_nfc_disabled), Snackbar.LENGTH_INDEFINITE, R.color.error)
}
}
override fun onResume() {
super.onResume()
setupForegroundDispatch()
}
override fun onPause() {
super.onPause()
stopForegroundDispatch()
}
override fun onDestroy() {
super.onDestroy()
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver)
}
private fun setupForegroundDispatch() {
val intent = Intent(this, TagDetection::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
val intentFilter = IntentFilter()
intentFilter.addAction(NfcAdapter.ACTION_TAG_DISCOVERED)
intentFilter.addCategory(Intent.CATEGORY_DEFAULT)
val techList = arrayOf<Array<String>>()
mNfcAdapter.enableForegroundDispatch(this, pendingIntent, arrayOf(intentFilter), techList)
}
private fun stopForegroundDispatch() {
mNfcAdapter.disableForegroundDispatch(this)
}
}
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.antlergroup.patrolsystem, PID: 11333
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.antlergroup.patrolsystem/com.antlergroup.patrolsystem.ui.SecurityPointRegistrationActivity}: java.lang.NullPointerException: NfcAdapter.getDefaultAdapter(this) must not be null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4076)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2473)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8349)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
Caused by: java.lang.NullPointerException: NfcAdapter.getDefaultAdapter(this) must not be null
at com.antlergroup.patrolsystem.ui.SecurityPointRegistrationActivity.onCreate(SecurityPointRegistrationActivity.kt:72)
at android.app.Activity.performCreate(Activity.java:8085)
at android.app.Activity.performCreate(Activity.java:8073)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1320)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3870)
You need to define NfcManager first then you can call the getDefaultAdapter method. Please refer to the code snippet.
private var mNfcAdapter: NfcAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tapping)
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
mNfcAdapter = manager.getDefaultAdapter();
}
For more information, you can refer to this link

Cannot create an instance of Application ViewModel

I'm Trying to make a viewmodel scoped to my application to control logic related to showing of not showing pin in multi activity app .
I've used AndroidViewModel to pass the application to it and here is the class for AppViewModel
#HiltViewModel
class AppViewModel #Inject constructor(
private val getUserPassCodeUseCase: GetUserPassCodeUseCase,
private val isPasscodeInputUseCase: IsPasscodeInputUseCase,
private val clearAllDataUseCase: ClearAllDataUseCase,
#ApplicationContext private val context: Context
) : AndroidViewModel((context as App)) {
private val _openPin = MutableSharedFlow<Long>()
val openPin = _openPin.asSharedFlow()
// uptime in millis
private var time: Long = 0
private var restoreStatus = RestoreStatus.EMPTY
private var isPasscode = false
private var passCode = ""
init {
// get user status
}
private fun checkIfShouldLock() {
viewModelScope.launch {
isPasscode = withContext(IO) {
isPasscodeInputUseCase()
}
val userHasAccount = (restoreStatus == RestoreStatus.ID_SUBMISSION
|| restoreStatus == RestoreStatus.TERMS_AND_CONDITION
|| restoreStatus == RestoreStatus.ACTIVATE_CARD
|| restoreStatus == RestoreStatus.FULL_NAME
|| restoreStatus == RestoreStatus.COMPLETED)
if (true)
_openPin.emit (System.currentTimeMillis() )
}
}
fun onResume() {
updatePasscode()
if (!isPasscode) {
time = 0
return
}
val now = SystemClock.elapsedRealtime()
when {
time == 0L -> {
// remember first value
time = now
}
// check is session expired
now - time > sessionExpiredTime -> {
time = now
when (restoreStatus) {
RestoreStatus.COMPLETED -> checkIfShouldLock()
RestoreStatus.EMPTY -> {}
else -> {}
}
}
else -> {
time = now
}
}
}
fun onPause() {
updatePasscode()
viewModelScope.launch {
delay(Constants.PASSCODE_DELAY)
if (!isPasscode) {
time = 0
return#launch
}
// start "timer"
time = SystemClock.elapsedRealtime()
}
}
private fun updatePasscode() {
viewModelScope.launch {
isPasscode = withContext(IO) {
isPasscodeInputUseCase()
}
}
}
fun logout() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
clearAllDataUseCase()
}
}
}
companion object {
const val MAIN_VIEW_MODEL_TAG = "AppViewModel"
}
}
and here is my application class and how i try to access the viewmodel
#HiltAndroidApp
class App : Application(), Application.ActivityLifecycleCallbacks,
Configuration.Provider {
#Inject
lateinit var workerFactory: HiltWorkerFactory
override fun getWorkManagerConfiguration() =
Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
// uptime in millis
private var time: Long = 0
var appViewModel : AppViewModel ?=null
var currentActivity : String ?=null
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
appViewModel = ViewModelProvider.AndroidViewModelFactory(this).create(AppViewModel::class.java)
appViewModel?.openPin?.onEach {
// if (authToken.isNotEmpty())
when (currentActivity) {
SplashActivity::class.java.name,
PinActivity::class.java.name -> Unit
else -> {
startActivity(Intent(this, PinActivity::class.java).apply {
// flag of should end with result or not
// putExtra(Constants.IS_CAME_FROM_BACKGROUND, true)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}
}
}
setupCrashlytics()
if (BuildConfig.DEBUG)
Timber.plant(Timber.DebugTree())
else
Timber.plant(CrashReportingTree())
DyScan.init(this, Constants.DYSCAN_API_KEY)
registerActivityLifecycleCallbacks(this)
}
private fun setupCrashlytics() {
with(FirebaseCrashlytics.getInstance()) {
setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG)
}
}
private fun isDeviceRooted(): Boolean {
var process: Process? = null
return try {
process = Runtime.getRuntime().exec("su")
true
} catch (e: Exception) {
Timber.i(e, "Rooted device command exception")
false
} finally {
if (process != null) {
try {
process.destroy()
} catch (e: Exception) {
Timber.i(e, "Rooted device command close exception")
}
}
}
}
private fun hideSystemBars(activity: Activity) {
val windowInsetsController =
ViewCompat.getWindowInsetsController(activity.window.decorView) ?: return
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars())
}
override fun onActivityCreated(activity: Activity, p1: Bundle?) {
currentActivity = activity.localClassName
if (isDeviceRooted()) {
Toast.makeText(
activity,
getString(R.string.rooted_device_message),
Toast.LENGTH_SHORT
).show()
activity.finishAffinity()
}
}
override fun onActivityStarted(p0: Activity) {
appViewModel?.onResume()
}
override fun onActivityResumed(p0: Activity) {}
override fun onActivityPaused(p0: Activity) {}
override fun onActivityStopped(activity: Activity) {
appViewModel?.onPause()
}
override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {}
override fun onActivityDestroyed(p0: Activity) {}
}
i keep getting RuntimeException: Cannot create an instance of class x.x.AppViewModel
2022-03-08 22:29:44.189 10889-10889/com.x.x E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.x.x, PID: 10889
java.lang.RuntimeException: Unable to create application com.x.x.App: java.lang.RuntimeException: Cannot create an instance of class com.x.x.AppViewModel
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
at android.app.ActivityThread.access$1700(ActivityThread.java:274)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:233)
at android.app.ActivityThread.main(ActivityThread.java:8010)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)
Caused by: java.lang.RuntimeException: Cannot create an instance of class com.x.x.AppViewModel
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:230)
at com.x.x.App.onCreate(App.kt:54)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1208)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6986)
at android.app.ActivityThread.access$1700(ActivityThread.java:274) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:233) 
at android.app.ActivityThread.main(ActivityThread.java:8010) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978) 
Caused by: java.lang.NoSuchMethodException: com.x.x.AppViewModel.<init> [class android.app.Application]
at java.lang.Class.getConstructor0(Class.java:2332)
at java.lang.Class.getConstructor(Class.java:1728)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:228)
at com.x.x.App.onCreate(App.kt:54) 
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1208) 
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6986) 
at android.app.ActivityThread.access$1700(ActivityThread.java:274) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2093) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:233) 
at android.app.ActivityThread.main(ActivityThread.java:8010) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978) 
What i am doing wrong in this implementation ?
Is this the right way to implement a viewModel scoped to application ?
From what I can tell, something is trying to call a no argument constructor on your ViewModel, but you have only defined a constructor that takes arguments.
You have arguments in viewmodel constructor. You will have to extend viewmodel factory and handle the parameters passed. Later pass the required parameter values to custom viewmodel factory instance. Finally use the custom view model factory instance in ViewModelProvider.AndroidViewModelFactory(this ,customInstance).create (AppViewModel::class.java)

"Intent must not be null" when sending strings from one activity to another

I'm new to Kotlin and I'm trying to send two strings from two textViews in one activity to another using intents. However, I'm getting this error when I run the function load.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.pdm_2021_i_p1_project1, PID: 18672
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.pdm_2021_i_p1_project1/com.example.pdm_2021_i_p1_project1.PlayActivity}: java.lang.IllegalStateException: intent must not be null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3365)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.IllegalStateException: intent must not be null
at com.example.pdm_2021_i_p1_project1.PlayActivity.getWord(PlayActivity.kt:119)
at com.example.pdm_2021_i_p1_project1.PlayActivity.<init>(PlayActivity.kt:21)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
at android.app.Instrumentation.newActivity(Instrumentation.java:1253)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3353)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:223) 
at android.app.ActivityThread.main(ActivityThread.java:7656) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
Here's my code from the activity receiving the strings
class PlayActivity : AppCompatActivity() {
//Variable Declarations
private val lives : Int = 4
private var fails : Int = 0
private var correctGuesses = mutableSetOf<Char>()
private var guesses = mutableSetOf<Char>()
private val word = getWord().toLowerCase(Locale.ROOT)
private val clue = getClue().toLowerCase(Locale.ROOT)
private val letters = word.toLowerCase(Locale.ROOT).toCharArray().toHashSet()
private val txtArray = arrayOfNulls<TextView>(word.length)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_play)
btnCheck.setOnClickListener{(checkWord())}
createTxtViews()
txvClue.text = clue.toUpperCase(Locale.ROOT)
txvLives.text = "❤❤❤❤"
}
private fun checkWord(){
val character = txtPlayAddLetter.text.toString().toLowerCase(Locale.ROOT)
if (txtPlayAddLetter.text.isNotEmpty()){
if (word.contains(txtPlayAddLetter.text.toString().toLowerCase(Locale.ROOT))) {
correctGuesses.add(character[0])
guesses.add(character[0])
txvGuessed.text = guesses.toString().toUpperCase(Locale.ROOT)
txvTest.text = letters.toString()
showLetters()
txtPlayAddLetter.text.clear()
checkGameState()
}
else
{
fails++
guesses.add(character[0])
txvGuessed.text = guesses.toString().toUpperCase(Locale.ROOT)
txtPlayAddLetter.text.clear()
val hearts = txvLives.text.dropLast(1)
txvLives.text = hearts
when (fails) {
1 -> {frame1.isVisible = false
frame2.isVisible = true}
2 -> {frame2.isVisible = false
frame3.isVisible = true}
3 -> {frame3.isVisible = false
frame4.isVisible = true}
4 -> {frame4.isVisible = false
frame5.isVisible = true}}
if (fails == lives)
{
showDefeat()
}
}
}
else
{
Toast.makeText(this#PlayActivity, "Please enter a letter :)", Toast.LENGTH_LONG).show()
}
}
private fun showDefeat(){
val intent = Intent(this, DefeatActivity::class.java)
finish()
startActivity(intent)
}
private fun showVictory(){
val intent = Intent(this, VictoryActivity::class.java)
finish()
startActivity(intent)
}
private fun createTxtViews(){
val lLayout = findViewById<View>(R.id.txtPlayGuessed) as LinearLayout
for (i in word.indices) {
txtArray[i] = TextView(this)
txtArray[i]?.id = i
txtArray[i]?.setTextColor(resources.getColor(R.color.white))
txtArray[i]?.hint = " _ "
txtArray[i]?.setHintTextColor(resources.getColor(R.color.white))
txtArray[i]?.textSize = 25F
lLayout.addView(txtArray[i])
txtArray[i]?.isVisible = true
}
}
private fun showLetters(){
val str = txtPlayAddLetter.text.toString().toLowerCase(Locale.ROOT)
for (i in word.indices){
if (txtPlayAddLetter.text.single().toLowerCase() == word[i]){
txtArray[i]?.text = " ".plus(str.toUpperCase(Locale.ROOT)).plus(" ")
}
}
}
private fun checkGameState(){
if (correctGuesses == letters){
showVictory()
finish()
}
}
fun getWord(): String{
val bundle=intent.extras
val setword= bundle?.get("setword")
return getString(R.string.setwordplay,setword)
}
fun getClue(): String{
val bundle = intent.extras
val setclue = bundle?.get("setclue")
return getString(R.string.setwordplay,setclue)
}}
And here's my code from the activity sending the strings
fun load(){
val intent = Intent(this, PlayActivity::class.java)
intent.putExtra("setword", editTextTypeAWord.text.toString())
intent.putExtra("setclue", editTextHint.text.toString())
startActivity(intent)
}
You are trying to initialise the val with data from Intent. In PlayActivity, the init{} block and property initialisations run before onCreate().
To work around this issue you could try:
class PlayActivity : AppCompatActivity() {
companion object {
const val ARG_WORD = "word"
const val ARG_CLUE = "clue"
}
private lateinit var word: String
private lateinit var clue: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
word = intent.getStringExtra(ARG_WORD) ?: throw IllegalArgumentException("Word was not supplied")
clue = intent.getStringExtra(ARG_CLUE) ?: throw IllegalArgumentException("Clue was not supplied")
}
}
Call with:
val intent = Intent(this, PlayActivity::class.java).apply {
putExtra(PlayActivity.ARG_WORD, "giraffe")
putExtra(PlayActivity.ARG_CLUE, "long neck")
}
startActivity(intent)
Also, remember to refactor other properties that rely on word and clue to use either functions or getters, otherwise you'll run into UninitializedPropertyAccessException.
What using getters does is that every time you call the property the get()-portion is calculated. Since you're using the properties after onCreate(), your lateinit properties should already have been initialised from the intent you've received!
class PlayActivity : AppCompatActivity() {
companion object {
const val ARG_WORD = "word"
const val ARG_CLUE = "clue"
}
private lateinit var word: String
private lateinit var clue: String
private val letters: HashSet<Char>
get() = word.toLowerCase(Locale.ROOT).toCharArray().toHashSet()
private val txtArray: Array<TextView?>
get() = arrayOfNulls<TextView>(word.length)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
word = intent.getStringExtra(ARG_WORD) ?: throw IllegalArgumentException("Word was not supplied")
clue = intent.getStringExtra(ARG_CLUE) ?: throw IllegalArgumentException("Clue was not supplied")
}
}
I highly recommend you to read this: https://kotlinlang.org/docs/properties.html
val intent = Intent(this, PlayActivity::class.java).apply {
putExtra("setword", message)
}
startActivity(intent)
try this
private fun showVictory(){
val intent = Intent(this, VictoryActivity::class.java)
startActivity(intent)
finish()
}
use like this
intent?.getStringExtra("setword") ?: ""
intent?.getStringExtra("setclue") ?: ""
try this way
fun getWord(): String{
val setword= intent.getStringExtra("setword")
return getString(R.string.setwordplay,setword)
}
fun getClue(): String{
val setclue = intent.getStringExtra("setclue")
return getString(R.string.setwordplay,setclue)
}}

When use RxJava and coroutines , get error lateinit property observable has not been initialized

Android Studio 4.0
import retrofit2.Response
import retrofit2.http.GET
interface TestRestClient {
#GET("films")
suspend fun getFilms(): Response<List<Film>>
}
suspend fun getFilms(isCustomtHandle: Boolean = false): Response<*> {
Debug.d(TAG, "getFilms: ")
suspend fun execOperation(): Response<*> = testRestClient.getFilms()
return runOperation(isCustomtHandle, ::execOperation)
}
In my ViewModel
class FilmsRxJavaViewModel(application: Application) : AndroidViewModel(application) {
companion object {
private val TAG = FilmsRxJavaViewModel::class.java.name
}
lateinit var observable: Single<List<Film>>
init {
loadData()
}
fun loadData() {
viewModelScope.launch(Dispatchers.Main) {
Debug.d(TAG, "loadData: START")
val response = TransportService.getFilms()
val isSuccessResponse = response.isSuccessful
if (isSuccessResponse) { // code >= 200 && code < 300;
val filmsList : List<Film> = response.body() as List<Film>
observable = Single.just(filmsList)
} else { // error - status (300-599) or network failure
val message = response.errorResponse.message
Debug.w(TAG, "loadData: message = $message")
}
Debug.d(TAG, "loadData: FINISH")
} // end coroutine
}
}
In my activity
class FilmsRxJavaActivity : AppCompatActivity() {
private lateinit var filmsRxJavaViewModel: FilmsRxJavaViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Debug.d(TAG, "onCreate: savedInstanceState = $savedInstanceState")
setContentView(R.layout.films_rx_java_activity)
binding = FilmsRxJavaActivityBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
val dispose = filmsRxJavaViewModel.observable
// to subscribe in IO thread
.subscribeOn(Schedulers.newThread())
// observe the task's result on the main thread
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Debug.d(TAG, "initLogic: subscribe_filmsList(${it.size})\n$it")
}, {
Debug.e(TAG, "initLogic: error = $it")
)
}
}
But I get error when open my activity:
Error in this line:
lateinit var observable: Single<List<Film>>
Details:
07-14 10:23:51.557 D/AndroidRuntime( 6803): Shutting down VM
--------- beginning of crash
FATAL EXCEPTION: main
Process: .androidtestproject.debug, PID: 6803
java.lang.RuntimeException: Unable to start activity ComponentInfo{androidtestproject.debug/.androidtestproject.ui.activity.FilmsRxJavaActivity}: kotlin.UninitializedPropertyAccessException: lateinit property observable has not been initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property observable has not been initialized
at .androidtestproject.viewmodel.FilmsRxJavaViewModel.getObservable(FilmsRxJavaViewModel.kt:26)
at .androidtestproject.ui.activity.FilmsRxJavaActivity.initLogic(FilmsRxJavaActivity.kt:54)
at .androidtestproject.ui.activity.FilmsRxJavaActivity.init(FilmsRxJavaActivity.kt:45)
at .androidtestproject.ui.activity.FilmsRxJavaActivity.onCreate(FilmsRxJavaActivity.kt:33)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
... 11 more
Exception happens inside else block because observable will still not initialized
fun loadData() {
viewModelScope.launch(Dispatchers.Main) {
Debug.d(TAG, "loadData: START")
val response = TransportService.getFilms()
val isSuccessResponse = response.isSuccessful
if (isSuccessResponse) { // code >= 200 && code < 300;
val filmsList : List<Film> = response.body() as List<Film>
observable = Single.just(filmsList)
} else { // error - status (300-599) or network failure
val message = response.errorResponse.message
Debug.w(TAG, "loadData: message = $message")
// give a value to observable when error happen .
}
Debug.d(TAG, "loadData: FINISH")
} // end coroutine
}

: kotlin.UninitializedPropertyAccessException: lateinit property manager has not been initialized

I am developing news and I am getting following nullpointexception
java.lang.RuntimeException: Unable to start activity ComponentInfo{yodgorbek.komilov.musobaqayangiliklari/yodgorbek.komilov.musobaqayangiliklari.ui.WelcomeActivity}: kotlin.UninitializedPropertyAccessException: lateinit property manager has not been initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2976)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3113)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:113)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:71)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1858)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6820)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property manager has not been initialized
at yodgorbek.komilov.musobaqayangiliklari.ui.WelcomeActivity.onCreate(WelcomeActivity.kt:26)
at android.app.Activity.performCreate(Activity.java:7224)
at android.app.Activity.performCreate(Activity.java:7213)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2956)
... 11 more
below my WelcomeActivity.kt class
class WelcomeActivity : AppIntro() {
private lateinit var manager: PreferencesManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Make sure you don't call setContentView!
if (manager.isFirstRun()) {
showIntroSlides()
} else {
goToMain()
}
}
// Call addSlide passing your Fragments.
// You can use AppIntroFragment to use a pre-built fragment
private fun showIntroSlides() {
manager.setFirstRun()
addSlide(
AppIntroFragment.newInstance(
title = "Welcome to the NewsApp",
description = "NewsApp give your information about life news around the world",
imageDrawable = R.drawable.news,
backgroundDrawable = R.drawable.news_slider,
titleColor = Color.YELLOW,
descriptionColor = Color.RED,
backgroundColor = Color.BLUE,
titleTypefaceFontRes = R.font.opensans_light,
descriptionTypefaceFontRes = R.font.opensans_regular
)
)
addSlide(
AppIntroFragment.newInstance(
title = "...Let's get started!",
description = "This is the last slide, I won't annoy you more :)"
)
)
}
private fun goToMain() {
startActivity(Intent(this, MainActivity::class.java))
}
override fun onSkipPressed(currentFragment: Fragment?) {
super.onSkipPressed(currentFragment)
goToMain()
}
override fun onDonePressed(currentFragment: Fragment?) {
super.onDonePressed(currentFragment)
goToMain()
}
override fun onSlideChanged(oldFragment: Fragment?, newFragment: Fragment?) {
super.onSlideChanged(oldFragment, newFragment)
Log.d("Hello", "Changed")
}
}
I don't understand what is the causing null pointer exception even I have tried initialize manager following way
private var manager: PreferencesManager? = null
but it did not solve my problem
I want to know where I am making mistake what I have to do avoid nullpointer exception
It's simple by looking into logs. Your manager is not initialized before using. Look at onCreate
private lateinit var manager: PreferencesManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Make sure you don't call setContentView!
// <<<<<<<<<<<<<<< INITIALISE manager HERE >>>>>>>>>>>>>>
if (manager.isFirstRun()) { <<<<<<<< HERE you are using an uninitilised manager
showIntroSlides()
} else {
goToMain()
}
}
Initialise manager before if (manager.isFirstRun()) { in onCreate()

Categories

Resources