Log.d() stops working after calling Integer.parseInt(INVALID_INT) - android

private void someFunction(String html) {
Document doc = Jsoup.parse(html);
Element vol = doc.select(CSS_PATH).first();
Log.d("Vol", vol.text());
Log.d(TAG, "This gets printed");
Float.parseFloat(vol.text());
Log.d(TAG, "BUT THIS ONE NOT");
}
These two objects are elements of the Jsoup library.
Document doc = Jsoup.parse(html);
Element vol = doc.select(PATH.PEAK_DOWN_VOL).first();
vol.text() returns a String containing a float value.
Log.d("Vol", vol.text()); // logs something similar to 'Vol: 12.4'
But after calling Float.parseFloat(peakDownVol.text());, Log.d in this class will stop entirely. But Log.d's in the Activity class seems to work just fine.
If I change Float.parseFloat(vol.text()); to Integer.parseInt(vol.text());, it logs the subsequent statements without any problem.
I have lot of number parsing to do. So I'd like to know why is this happening exactly?

If you want the rest of the method to run regardless, you should catch the potential exception locally, so that the program can continue executing the rest of the method and not bubble back up the call stack until it finds an exception handler or crashes for the lack of one:
Log.d(TAG, "This gets printed");
try {
Float.parseFloat(vol.text());
} catch (NumberFormatException e) {
e.printStackTrace(); //leave evidence in the log
}
Log.d(TAG, "So does this");

Related

Handle IOException inside function

I have a method which copies some files from shared memory to internal app memory using the library FileUtils.
The goal is handling IOException in order not to crash the app: it's acceptable if some files are not copied out of the total number.
In the second snippet below there is the called method where the exception is handled.
I need to know 2 things:
a) is there a way to handle the exception only in the called method
and not also in the calling code?
b) in your opinion the exception handling is correct or do I need to add some other code?
Below is the code:
try {
copyfilesfromshared(context);
} catch (IOException e) {
e.printStackTrace();
}
public void copyfilesfromshared(Context context) throws IOException {
for (int ii = 0; ii < numfiles; ii++) {
try {
FileUtils.copyFileToDirectory(files[ii], dirwrite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
is there a way to handle the exception only in the called method and not also in the calling code?
If you handle the exception in copyfilesfromshared() function you do not need to declare throws IOException
public void copyfilesfromshared(Context context) {
for (int ii = 0; ii < numfiles; ii++) {
try {
FileUtils.copyFileToDirectory(files[ii], dirwrite);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then you can use it normally, without declarin try {...} catch(...) again:
copyfilesfromshared(context);
in your opinion the exception handling is correct or do I need to add some other code?
This looks fine to me, but better check the signature of FileUtils.copyFileToDirectory if it throws any other exception as well, you maybe want to catch here too.
Beside that, it is totally on your side where you wanna handle the exception, but in general the earlier the better.
Heyy,
For your first question
a) is there a way to handle the exception only in the called method
and not also in the calling code?
There is a choise between throwing the IOException from the called method OR
to implement try/catch inside method.
And thats your problem
You are choosing both options instead of one, So just choose one.
And about 2 question
b) in your opinion the exception handling is correct or do I need to
add some other code?
Exception handeling is best at this moment, So don't think and other thought
And that's all!!

Show progress of multiple website downloads during button press

I need to retrieve some data from roughly 50 different URLS with the press of a button.
The code goes through them one at a time, and although it doesn't take that long, it will take around 20 seconds, and I have all this code running inside of a button.
I was hoping I could update a TextView or something to say "Loading page 1 of 50" then "Loading page 2 of 50" etc, in between accessing the different websites.
The code below works, just the button gets stuck down for an unknown amount of time, and I want the user to have some indication of how far along the loading is doing.
btnGetData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//regionRetrieve 1 page of auction data, so we know how many future pages to retrieve. -P
String auctionURL = "https://api.hypixel.net/skyblock/auctions?page=";
String firstPage = null;
try {
firstPage = new RetrieveData().execute(auctionURL + "0").get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
auctionInfo = new JSONObject(firstPage);
} catch (JSONException e) {
e.printStackTrace();
}
//endregion
//regionRetrieve the remaining pages
int totalPages = 0;
try {
totalPages = auctionInfo.getInt("totalPages");
} catch (JSONException e) {
e.printStackTrace();
}
//Place to put the rest of the pages
ArrayList<String> remainingPages = new ArrayList<>();
//Starts at 1, because we already retrieved the 0 page as the first page.
//Also, I checked, and you do need to retrieve the 52nd page if there are say, 52 pages.
for (int i = 1; i <= totalPages; ++i) {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//ADD SOME KIND OF NOTIFICATION HERE
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
String newPage = null;
try {
newPage = new RetrieveData().execute(auctionURL + i).get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
remainingPages.add(newPage);
}
Toast.makeText(getApplicationContext(),"All data received.",Toast.LENGTH_SHORT).show();
tvLoading.setVisibility(View.GONE);
//endregion
//stuff below this point is irrelevant to the question
}
});
I tried wrapping all of the code above inside an AsyncTask, and utilizing the "onProgressUpdate", but that did not work. Furthermore, I heard that by now, AsyncTask has been deprecated, and that there are better ways to do it.
I also tried using Toast messages, but they all show up at the end, which kind of defeats the purpose.
I even put the Toast messages in the AsyncTasks that I call in order to get the data, but that didn't work either. (The RetrieveData() is an AsyncTask that reads all the information from the URLS, and returns it as a String. I know you aren't supposed to use get, but in this case it is important the data arrives in the correct order. Unless, after retrieving the first one, and knowing how many pages there are, I could launch 50 threads at the same time to retrieve the data? But still, you are limited by your internet connection, and the user is still sitting there confused.)
Is there a proper way to do this?
Any help would be appreciated!
Instead of putting all the code in the button, make the button launch another activity, and put the data retrieval code in that activity.
Launch the code inside of a thread, and from within the thread, update UI elements to inform the user of the progress.
After the data is retrieved, store it, then start an Intent to go back to the previous activity, access the data where you stored it, and use it for whatever you needed to do.
(I know I answered my own question, but I figured it out a few hours later and nobody had responded up until now, hopefully this helps someone in the future.)

How to effectively group non fatal exceptions in Crashlytics (Fabrics)?

We are using Crashlytics in our app as the crash reporting tool.
For Android native crashes, it's working fine and grouping the crashes correctly.
Our app also has few components in react-native. For the crashes which occur in these components, we catch them and then log them to Crashlytics as non-fatal exceptions.
public class PlatformNativeModuleCallExceptionhandler implements
NativeModuleCallExceptionHandler {
#Override
public void handleException(Exception e) {
try {
.
.
.
Crashlytics.logException(new Exception(exceptionString));
} catch (Exception ex) {}
}
Crashes are getting logged in Crashlytics dashboard, but it's showing all the crashes inside a single tab. These might be different crashes of the same or different react-native components.
Due to this we are not able to find out the instances of a particular crash. Need to manually go through each instance of the crash.
I guess it takes the name of the class where exception gets created, in this case PlatformNativeModuleCallExceptionHandler.
I tried creating my own custom exception class but that also did not help.
Does anybody know how we can group the non fatal exceptions better here?
All the similar crashes should be grouped together with their total instances.
Crashlytics uses the method and crash line number to group crashes, so if you have an exception handler method for all of your non-fatals, they'll be grouped together. There isn't currently a workaround for this.
Best way I've found to do this is to manually chop the shared parts of the stacktrace off:
private fun buildCrashlyticsSyntheticException(message: String): Exception {
val stackTrace = Thread.currentThread().stackTrace
val numToRemove = 8
val lastToRemove = stackTrace[numToRemove - 1]
// This ensures that if the stacktrace format changes, we get notified immediately by the app
// crashing (as opposed to silently mis-grouping crashes for an entire release).
check(lastToRemove.className == "timber.log.Timber" && lastToRemove.methodName == "e",
{ "Got unexpected stacktrace: $stackTrace" })
val abbreviatedStackTrace = stackTrace.takeLast(stackTrace.size - numToRemove).toTypedArray()
return SyntheticException("Synthetic Exception: $message", abbreviatedStackTrace)
}
class SyntheticException(
message: String,
private val abbreviatedStackTrace: Array<StackTraceElement>
) : Exception(message) {
override fun getStackTrace(): Array<StackTraceElement> {
return abbreviatedStackTrace
}
}
This way the message can be parameterized Timber.e("Got a weird error $error while eating a taco") and all of that line's calls will be grouped together.
Obviously, numToRemove will need to change depending on your exact mechanism for triggering nonfatals.
I resolved this by setting a custom stack trace to the exception. A new Exception(exceptionMessage) will create the exception there itself, what we did was to throw an exception which in catch called my counterpart of handleException() with the actual stack trace furnished in the exceptionMessage. Some parsing and the exceptionMessage can be used to set the stack trace on the newly created exception using exception.setStackTrace(). Actually, this was required in my project only because it is cross-language, for regular projects, simply passing the exception thrown and caught at the place of interest should work.
Crashlytics groups by the line number that the exception was generated on and labels it with the exception type. If you know all the types of the exceptions you can generate each one on a different line. And you could also map your strings to custom Exception types to make it more easy to identify them in Crashlytics.
Here's an example:
public void crashlyticsIsGarbage(String exceptionString) {
Exception exception = null;
switch(exceptionString) {
case "string1": exception = new String1Exception(exceptionString);
case "string2": exception = new String2Exception(exceptionString);
case "string3": exception = new String3Exception(exceptionString);
case "string4": exception = new String4Exception(exceptionString);
default: exception = new Exception(exceptionString);
}
Crashlytics.logException(exception);
}
class String1Exception extends Exception { String1Exception(String exceptionString) { super(exceptionString); } }
class String2Exception extends Exception { String2Exception(String exceptionString) { super(exceptionString); } }
class String3Exception extends Exception { String3Exception(String exceptionString) { super(exceptionString); } }
class String4Exception extends Exception { String4Exception(String exceptionString) { super(exceptionString); } }
BTW, Crashlytics will ignore the message string in the Exception.
I was looking into this just now, because the documentation says:
Logged Exceptions are grouped by Exception type and message.
Warning:
Developers should avoid using unique values, such as user ID, product ID, and timestamps, in the Exception message field. Using unique values in these fields will cause a high cardinality of issues to be created. In this case, Crashlytics will limit the reporting of logged errors in your app. Unique values should instead be added to Logs and Custom Keys.
But my experience was different. From what I found out, what Alexizamerican said in his answer is true, with a small caveat:
Issues are grouped by the method and line where the exception was created, with the caveat that it is the root cause of the exception that is being taken into account here.
By root cause I mean this:
public static Throwable getRootCause(Throwable throwable) {
Throwable cause = throwable;
while (cause.getCause() != null) {
cause = cause.getCause();
}
return cause;
}
Therefore, if you did:
#Override
public void handleException(Exception e) {
// ...
Crashlytics.logException(e);
}
That should correctly group the exceptions together.
Furthermore, if you did:
#Override
public void handleException(Exception e) {
// ...
Crashlytics.logException(new Exception(exceptionString, e));
}
That would also correctly group the exceptions, because it would look at e or its cause, or the cause of that, and so on, until it reaches an exception that doesn't have any other cause, and look at the stack trace where it was created.
Finally, unlike what miguel said, exception type or message doesn't affect grouping at all in my experience. If you have FooException("foo") at some particular line in a particular method, and you replace it with BarException("bar"), the two will be grouped together, because the line and method didn't change.

Properly running code in android main thread

So started programming android apps, mostly open source and tutorials to learn the language.
I have a problem now where if a user has signed in once, that he never has to sign in again. I used SharedPref for this after reading alot of answers on here, but the app is jumping frames due to this..
heres my code.
SharedPreferences prefs = getPreferences(Login.this);
prefs = PreferenceManager.getDefaultSharedPreferences(Login.this);
String remUsername = prefs.getString("username", null);
String remPassword = prefs.getString("password", null);
if (remUsername != null && remPassword != null)
{
String result = null;
try {
result = imService.authenticateUser(
remUsername.toString(),
remPassword.toString());
} catch (UnsupportedEncodingException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
Intent i = new Intent(Login.this, FriendList.class);
startActivity(i);
Login.this.finish();
}
The jumping frames are probably due to a resource-intensive operation (such as an HTTP request) being executed by the main thread. You must perform such operations in a separate thread, while leaving only UI and non-intensive operations for the main thread (that's why it is called the "UI" thread).
Read the basics here. Then you can implement it using an AsyncTask, for example. However for simplicity it is suggested to use a specialized library such as Volley or android-async-http.

Should I remove e.printStackTrace() from my code before publishing

I was reading the the Android Publishing docs and they said to remove all Log calls from my code. I have some calls to e.printStackTrace() in my code that can be printed as part of the normal running of my program (ie. if a file does not exist yet).
Should I also remove these calls?
You shouldn't be using e.printStackTrace() directly anyway — doing so will send the info to the Android log without displaying which application (log tag) it came from.
As others have mentioned, continue to catch the Exception in question, but use one of the android.util.Log methods to do the logging. You could log only the message, but not the stack trace, or use verbose logging for the stack trace:
try {
Object foo = null;
foo.toString();
} catch (NullPointerException ex) {
Log.w(LOG_TAG, "Foo didn't work: "+ ex.getMessage());
Log.d(LOG_TAG, Util.stackTraceWriter(ex));
}
You should strip DEBUG or VERBOSE log messages from your production builds. The easiest way is to use ProGuard to remove Log.[dv] calls from your code.
If you allow an Exception to propagate up to the OS then the OS will log it and also pop up a Force Close window, killing your application. If you catch it, then you can prevent your application from being force closed.
If you want your users to have the ability to send you errors that they are getting, then I would log the stack trace. They can then send you the log via an app like Log Collector.
If you want to avoid the possibility of exposing your stack trace information to your users, then catch the exception and don't log it.
I would use Log class for message out put. For logs that you think are important to stay in the app - use Log.i
for errors warning - Log.e Log.w
For you debug Log.d - and that you can turnoff on base on if your application is in debug mode.
http://developer.android.com/reference/android/util/DebugUtils.html
Well printStackTrace() will log it into the OS, causing your andorid (or computer) app to terminate (force close), instead, do something like this:
public void nullPointerExceptionCauser()
{
try
{
Object example = null;
example.toString();
}
catch (Exception e)
{
Logger.log(Level.SEVERE, "Caught Exception: {0}", e.getStackTrace());
}
}
in my modest opinion (I'm not an Android developer)
It should be nice. I don't know the logging options for Android but I'm sure you have some configurable thing to output (or not) your traces.
And if you don't do printStackTrace() Android will not be doing the dirty work of ignoring it.
:)
It's only a good-feeling (style) thing.
If you want to be secure i.e. not allow anyone snooping to read exception logs you can do something like
private void hideExceptionsInReleaseMode()
{
final Thread.UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
if(!BuildConfig.DEBUG)
{
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException(Thread thread, Throwable ex)
{
defaultHandler.uncaughtException(thread, new RuntimeException("Something went wrong :p"));
}
});
}
}
In order to use printStackTrace in a safer way I would use StringWrite and PrintWriter:
...
catch (final Exception e)
{
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
Log.e("TAG", sw.toString());
}
Or alternatively:
catch (final Exception e)
{
Log.e(TAG, Log.getStackTraceString(e));
}
Use this to remove the logs from release apk
if (BuildConfig.DEBUG) Log.d(TAG, "your meseage");

Categories

Resources