I have a question regarding the Koin handling exception.
In a module where I defined EncryptedSharedPreferences.create(), sometimes causing an exception, which results in a crash in the user's device. I see in the crashlytic report that the crash already happens over 200 times. More specific exception is below.
Caused by java.security.UnrecoverableKeyException: Failed to obtain information about key
...
Caused by android.security.KeyStoreException: -49
Apparently, this issue is already reported, yet there's no valid answer to handle or solving it. Because I'm using Koin to define the EncryptedSharedPreferences, I thought it's better to handle it inside single{} function. Put a try catch that will catch the exception. But when I try to throw an Exception inside try, it didn't catch the Exception, it's just crash, not what I expecting. The code looks like below
single(named(ENCRYPTED_SHARED_PREF)) {
val context = androidApplication().applicationContext
try {
val masterKey =
MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
EncryptedSharedPreferences.create(
context,
SP_ENCRYPTED_KEY,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
throwError()
} catch (e: Exception) {
Timber.d("[SHARED PREF] Terjadi exception")
when (e) {
is KeyStoreException -> {
Toast.makeText(context, "Terjadi exception", Toast.LENGTH_SHORT).show()
}
}
//Update missing link below
androidApplication().getSharedPreferences(SP_KEY, Context.MODE_PRIVATE)
}
}
...
#Throws(KeyStoreException::class)
fun throwError(): Nothing {
throw KeyStoreException("Terjadi exception")
}
Now for the question, is there's a way to handle this kind of Exception inside Koin single or not? I had try to search for the documentation and google it, seems a dead end to me.
Other useful information:
EncryptedSharedPreferences version : androidx.security:security-crypto:1.1.0-alpha03
Issue tracker for EncryptedSharedPreferences I faced : https://issuetracker.google.com/u/1/issues/167977579
The crash or exception not related to Koin issue, rather it's on EncryptedSharedPreferences
Koin version : org.koin:koin-android-viewmodel:2.1.6
UPDATE SOLVE
Took me a while to realize that the catch block needs to return something such as a value or another object, let say normally shared preference. Nothing wrong with the code thought after in-depth research. Thanks all, I also update the code in my explanation above.
if your try - catch is not working and your app crashes , it means that the things inside the try block are in another thread . check this
i had the same problem , but not inside koin init . i fixed by using android coroutine -> i can catch the exception now
you can also check for async variables inside koin here
Related
I have an app that processing some pdf files in background and suddenly it crashes with no 'caused by' description. Tried with real devices, new emulators, restarted pc and so on.
Never had something before and I don't know where to search for the root cause.
Edit: I found that problem was in a try/catch block
try {
val pdfReader = PdfReader(URL(it))
//process
pdfReader.close()
} catch(e: FileNotFoundException){
//process exception
}
So the problem was in wrong exception, when I switched to a more general exception, I could handle it and see error in logcat
try {
val pdfReader = PdfReader(URL(it))
//process
pdfReader.close()
} catch(e: Exception){
//process exception
}
If you are using iTextPdf it can sometimes throw NoClassDefFoundError for no reason as far as i have experienced. Maybe catching this Error instead of Exceptions could help you identify the problem. Like this:
try
{
// do stuff
}
catch (Error err) //or NoClassDefFoundError
{
System.err.println(err.getMessage());
}
I would like to know your ways to handle different kinds of errors (like http exceptions, no internet connection exceptions etc) in retrofit Rx onError without using instanceof like it's proposed here: How to handle network errors in Retrofit 2 with RxJava or here: Handle errors in Retrofit 2 RX
In kotlin I will simply make some extension functions for each kind of throwable to do whatever I want.
But I am forced to use Java in the project. Any nice suggestions?
is the approach to build some kind of error handler like this:
public interface ErrorHandler {
void handleError(Exception e);
void handleError(HttpException e);
void handleError(NullPointerException npe);
}
good? I know it is not because every time i need to handle another specific error I am forced to change interface, so it is violation of Open Close Principle. But I can't figure out any solution .
cheers
Wojtek
The compiler determines which method to call, rather than the VM. So the class you've described won't solve the problem unless you check instanceof first and cast the paramter to the correct type. Otherwise you're going to get handleError(Exception e) every time.
But I wanted to create an answer not for that reason, but to argue that having only one error handler is actually preferable in many cases, not a liability. Oftentimes in java we end up in awful situations like this:
catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("No such algorithm: RSA?", e);
}
catch (NoSuchProviderException e) {
throw new IllegalStateException("No such provider: " + ANDROID_KEYSTORE_ID, e);
}
catch (InvalidAlgorithmParameterException e) {
throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e);
}
catch (KeyStoreException e) {
throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e);
}
catch (IOException e) {
Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e);
}
catch (CertificateException e) {
Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e);
}
Having only one error handler gives us the ability to lump many types of exceptions together. You can see in this code, there are exceptions that should never be thrown, exceptions that can really only be the result of a bug in the code, and legitimate exceptional states that we need to handle. I find this messy, and would prefer to say:
if (e instanceof NoSuchAlgorithmException || e instanceof NoSuchProviderException) {
Log.wtf(TAG, "What the heck is this?", e);
throw new IllegalStateException("This is some kind of weird bug", e);
}
else if (e instanceof IOException || e instanceof CertificateException) {
// This can happen sometimes, track event in analytics and perhaps
// try some alternative means of credential storage.
}
else {
// At least here the app won't crash if some unexpected exception occurs,
// since we're trapping everything.
}
I don't think it's such a bad thing to be able to lump unexpected failures together and handle them in a more user friendly way than crashing the app. Even if it's just a bug, better to track it in your analytics framework behind the scenes than bomb the user out of the app. So many crashes in Android apps are actually completely recoverable, but we don't go around catching Throwable in every try/catch statement because it's a lot of extra code.
The proper OOP way to avoid chained ifs or catches is polymorphism. You can define several custom exception classes exposing common interface that is enough for a single handler to process.
Suppose you need to divide errors in two groups: recoverable and not recoverable. Then your base exception class (or interface) shall have abstract method isRecoverable() that you override in each subclass. Then there will be only one if in your handler: if (e.isRecoverable()) { ... } else { ... }.
The downside is that you have to wrap all standard exceptions into your custom ones at places where they are thrown (you have to catch them).
The right choice will greatly depend on your task, though.
I'm trying to make an http request in Android, using Kotlin, and I've come across two ways of doing so.
One is the traditional way, using AsyncTask (not really pretty) which I got to work with the following code (just the doInBackground, as the rest of the class seemed unnecessary):
override fun doInBackground(vararg params: Void?): String? {
val url = URL("myUrl")
val httpClient = url.openConnection() as HttpURLConnection
if(httpClient.getResponseCode() == HttpURLConnection.HTTP_OK){
try {
val stream = BufferedInputStream(httpClient.getInputStream())
val data: String = readStream(inputStream = stream)
return data;
} catch (e : Exception) {
e.printStackTrace()
} finally {
httpClient.disconnect()
}
}else{
println("ERROR ${httpClient.getResponseCode()}")
}
return null
}
Now, I've come across a library called Anko, which many here know, and I tried to use its DSL for asynchronous tasks. The thing is, I haven't found a lot of info here about Anko for asynchronous tasks, so I thought I would open a new topic to see if someone could walk me through what I'm doing wrong, or what they think I should do to make it work.
The code I wanted to use is the following:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
async() {
val result = URL("myUrl").readText()
textView1.setText(result)
}
}
I tried to keep it as slim as possible so to minimize any potential mistakes, but I must be doing something wrong here because the code inside the async block is not doing anything, yet the app is not crashing and I'm not getting any exceptions. I've tried debugging it using Intellij IDEA, but after the first line inside the async block it stops the debugging while saying "The application is running". My best guess is that it got hung up somewhere in that first line due to the failed connection, but I don't know.
I've also tried to use the regular URL("myUrl").openConnection() inside the async block, but that hasn't worked either.
Anyway, any help would be deeply appreciated.
The problem textView1 contents not getting updated is caused by calling setText outside of main thread.
The documentation shows a nice example how to properly use async. Take a look at the following adapted version of your code:
async() {
val result = URL("http://stackoverflow.com/").readText()
uiThread {
textView1.text = result
}
}
PS. While not directly related to the question consider using a nicer http client i.e. Retrofit, OkHttp
The problem turned out to be a lot more basic than what I was thinking. It was a problem of compatibility apparently from having an older version of Android Studio running with the new version 1.0.2 of the Kotlin plugin and, again, apparently the function readText was not working properly and therefore I wasn't getting anything from it.
Anyway, I updated Android Studio, with the latest version of Kotlin and it started working fine, although I'm going to see if I can find out what it was that was causing the problem inside readText.
I'm using the android crittercism library and trying to send a report when I catched an error level exception.
But I can't find the documentation on how to do that. Is this even possible? If so, how?
They temporarily moved the feature into beta. If you e-mail support they'll enable your account for handled exceptions. Below is the sample Android code:
try
{
throw new Exception("Exception Reason");
}
catch (Exception exception)
{
Crittercism.logHandledException(exception);
}
Just in case you need it, here is sample code on iOS:
#try {
[NSException raise:NSInvalidArgumentException
format:#"Foo must not be nil"];
} #catch (NSException *exception) {
// Pass it on to us!
[Crittercism logHandledException:exception]
}
I'm the co-founder and CTO of Crittercism. If you send me an awesome email, I can enable it for your account. I'm rob[at] :)
Crittercism.logHandledException(new Throwable("test"));
You don't actually have to throw the Exception (or Throwable, in this case).
It will appear under "Handled Exceptions" on Crittercism website.
In my app I want to catch all types of exceptions and send reports by e-mail. For that I'm using global try catch block. But now I need to recognize exception by type. How can I do it?
try{
...
}
catch (Exception e){
//Here I need to recognize exception by type
send(Error);
}
Why you don't simple send the whole stacktrace?
send(e.getStackTrace())
It not only contains the Exception type but also where (file, class, line) it occurred.
Additionally, you can also simply use the toString() method.
See the java doc for further information
Instead of rolling your own error logging and reporting mechninism I strongly recommend you use ACRA Its free, open source, and supports sending error logs to email. I have used it for quite some time and it is very good.
This will give you all sorts of information such as phone make, model, resolution, free memory, as well as a full stack trace of the error. Its by far the easiest way to get quality error reporting into an Android app.
The best part is it takes all of about 5 minutes to get setup and integrated.
e.getClass() // will give you Class object
e.getClass().getName() // will give you class name
However if you know the class names already you can use
if(e instanceof A)
{
// some processing
}
else if(e instanceof B)
{
//some processing
}
else
{
//
}