In debug mode, when I test with emulator device, my app works fine.
But when I upload app on google playstore and download it from market, my app is killed.
In Google play console, It says NumberFormatException
Error.
Exception java.lang.NumberFormatException: s == null
at java.lang.Integer.parseInt (Integer.java:577)
at java.lang.Integer.parseInt (Integer.java:650)
at com.chugnchunon.chungchunon_android.DiaryTwoActivity.onCreate$lambda-0 (DiaryTwoActivity.java:22)
at com.google.android.gms.tasks.zzi.run (zzi.java:21)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loopOnce (Looper.java:226)
at android.os.Looper.loop (Looper.java:313)
at android.app.ActivityThread.main (ActivityThread.java:8751)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1135)
As It says DiaryTwoActivity
, if I see the front part of that activity,
class DiaryTwoActivity : AppCompatActivity() {
private val db = Firebase.firestore
private val diaryDB = Firebase.firestore.collection("diary")
private val userDB = Firebase.firestore.collection("users")
private val userId = Firebase.auth.currentUser?.uid
val writeTime = LocalDateTime.now().toString().substring(0, 10)
private var from = ""
private lateinit var remoteConfig: FirebaseRemoteConfig
private val _mutableLiveData = MutableLiveData<AppUpdate>()
private var diaryType = ""
private var lastBackPressTime: Long = 0
private val binding by lazy {
ActivityDiaryTwoBinding.inflate(layoutInflater)
}
companion object {
private var permissionCheck = false
const val ALL_REQ_CODE: Int = 500
const val PARTNER_REQ_CODE: Int = 600
const val STEP_CONTACT_REQ_CODE: Int = 100
const val STEP_REQ_CODE: Int = 200
const val CONTACT_REQ_CODE: Int = 300
const val IGNORING_BATTERY_OPT_REQ_CODE: Int = 400
private var whiteCheck: Boolean = false
}
override fun onBackPressed() {
val currentTime = System.currentTimeMillis()
val interval = 2000
if (currentTime - lastBackPressTime < interval) {
super.onBackPressed()
finishAffinity()
finish()
} else {
lastBackPressTime = currentTime
}
}
@RequiresApi(33)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// 버전 체크
val android_versionCode = Build.VERSION.SDK_INT
val android_versionName = Build.VERSION.RELEASE
val versionSet = hashMapOf(
"android_api_level" to android_versionCode,
"android_release_version" to android_versionName,
)
userDB.document("$userId")
.set(versionSet, SetOptions.merge())
// diaryType 받아오기 - fragment 변동
diaryType = intent.getStringExtra("diaryType").toString()
// 인앱업데이트
remoteConfig = Firebase.remoteConfig
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 3600
}
remoteConfig.setConfigSettingsAsync(configSettings)
remoteConfig.fetchAndActivate().addOnCompleteListener { task ->
if (task.isSuccessful) {
val gson = GsonBuilder().create()
val result = remoteConfig.getString("app_update")
val resultJson = gson.fromJson(result, AppUpdate::class.java)
val currentAppVersion = packageManager.getPackageInfo(packageName, 0).versionCode
// 현재 버전값 저장
val currentVersionSet = hashMapOf(
"currentAppVersion" to currentAppVersion
)
userDB.document("$userId").set(currentVersionSet, SetOptions.merge())
// 현재 버전이 remote config 버전보다 낮을 경우
if (currentAppVersion < resultJson.app_version.toInt() && resultJson.force_update as Boolean) {
// 즉시 업데이트할 것
var window = this.window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor("#B3000000"))
binding.updateLayout.visibility = View.VISIBLE
var upAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_up_enter)
binding.updateCardLayout.startAnimation(upAnimation)
} else {
// 현재 버전이 remote config 버전보다 낮지 않을 경우
binding.updateLayout.visibility = View.GONE
}
} else {
// remote config에서 버전을 가져오지 못한 경우
}
}
// 인앱업데이트 취소 클릭
binding.updateCancelBox.setOnClickListener {
var downAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_down_enter)
binding.updateCardLayout.startAnimation(downAnimation)
Handler().postDelayed({
binding.updateLayout.visibility = View.GONE
var window = this.window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.WHITE);
}, 500)
}
// 인앱업데이트 확인 클릭
binding.updateConfirmBox.setOnClickListener {
val uri =
"https://play.google.com/store/apps/details?id=com.chugnchunon.chungchunon_android"
val goUpdateIntent = Intent(Intent.ACTION_VIEW, Uri.parse(uri))
startActivity(goUpdateIntent)
}
// 댓글 푸시 노티피케이션 구독
val userIdFormat = userId!!.replace(":", "")
val firebaseMessaging = FirebaseMessaging.getInstance()
firebaseMessaging.subscribeToTopic("$userIdFormat")
// FCM 토큰 저장
userDB.document("$userId")
.get()
.addOnSuccessListener { document ->
try {
// 발급 받은 토큰이 이미 있는 경우
val myFcmToken = document.data?.getValue("fcmToken").toString()
} catch (e: Exception) {
// 발급 받은 토큰이 없는 경우
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
return@OnCompleteListener
}
// 발급후 토큰 저장
val fcmToken = task.result
val fcmTokenSet = hashMapOf(
"fcmToken" to fcmToken
)
userDB.document("$userId")
.set(fcmTokenSet, SetOptions.merge())
})
}
}
// 권한 체크
val readContactPermissionCheck =
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
val stepPermissionCheck =
ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION)
val readGalleryPermission =
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
val postNotificationPermission =
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
if (Build.VERSION.SDK_INT >= 33) {
permissionCheck = readContactPermissionCheck == PackageManager.PERMISSION_GRANTED
&& stepPermissionCheck == PackageManager.PERMISSION_GRANTED
&& readGalleryPermission == PackageManager.PERMISSION_GRANTED
&& postNotificationPermission == PackageManager.PERMISSION_GRANTED
} else {
permissionCheck = readContactPermissionCheck == PackageManager.PERMISSION_GRANTED
&& stepPermissionCheck == PackageManager.PERMISSION_GRANTED
&& readGalleryPermission == PackageManager.PERMISSION_GRANTED
}
// 파트너 구분 x
if (!permissionCheck) {
binding.authNotificationLayout.visibility = View.VISIBLE
} else {
// 모두 허용된 경우
binding.authNotificationLayout.visibility = View.GONE
// 배터리 제한 없음 설정 안 한 경우
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val powerManager =
this.getSystemService(Context.POWER_SERVICE) as PowerManager
if (!powerManager.isIgnoringBatteryOptimizations(packageName)) {
val intent = Intent().apply {
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
data = Uri.parse("package:$packageName")
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
this.startActivity(intent)
} else {
// 배터리 사용량 제한없음 권한 부여 o
val batteryAuthSet = hashMapOf(
"auth_ignoring_battery" to true,
)
userDB.document("$userId").set(batteryAuthSet, SetOptions.merge())
}
}
// db에 권한 저장
var authSet = hashMapOf(
"auth_step" to true,
"auth_contact" to true,
"auth_gallery" to true,
"auth_notification" to true,
)
userDB.document("$userId").set(authSet, SetOptions.merge())
// 걸음수 호출
val startService = Intent(this, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(this, startService);
} else {
startService(startService);
}
val stepAuthIntent = Intent(this, MyDiaryFragment::class.java)
stepAuthIntent.setAction("STEP_AUTH_UPDATE")
stepAuthIntent.putExtra("StepAuth", true)
LocalBroadcastManager.getInstance(this).sendBroadcast(stepAuthIntent)
}
There's only one line related to Int()
is below:
remoteConfig.fetchAndActivate().addOnCompleteListener { task ->
if (task.isSuccessful) {
val gson = GsonBuilder().create()
val result = remoteConfig.getString("app_update")
val resultJson = gson.fromJson(result, AppUpdate::class.java)
val currentAppVersion = packageManager.getPackageInfo(packageName, 0).versionCode
// 현재 버전값 저장
val currentVersionSet = hashMapOf(
"currentAppVersion" to currentAppVersion
)
userDB.document("$userId").set(currentVersionSet, SetOptions.merge())
// 현재 버전이 remote config 버전보다 낮을 경우
if (currentAppVersion < resultJson.app_version.toInt() && resultJson.force_update as Boolean) {
Here, I get data from remote config
of firebase and change it to toInt()
.
But when I print it on debug, it prints "46" well as string and it should be converted to Int.
And since it gets data well from remote config, it shouldn't be null.
Moreover, it worked well before, the only thing that I changed is I change compileSDK from 32 to 33, and minSDKVersion from 31 to 26. (my targetSDK is 31)
I'm not sure this is related to version update.
And even not sure this line causes NumberFormatException, or other part is causing issue or not.
It worked well on debug, so I can't test with emulator..
Can you see the code and give me some advice?
22 line of DiaryTwoActivity was
import androidx.lifecycle.MutableLiveData
But since I didn't use MutableLiveData in this activity, I deleted that line but still issue comes after submitting app on market.