Handling Android App Crashes in Production with Crittercism
Practically all software is not bug free, when it is first launched. That is especially true for apps, which might crash on some exotic smartphones you never have considered testing your app on. Or you just don't have the money to test your app on every possible smartphone in this fast changing tech world, where every week new smartphones are launched, on which your app might crash.
You will feel helpless, when your app crashes somewhere in the world and you just don't know what caused the crash. So what is the solution to that problem?
Enter Crittercism!
Crittercism provides a real-time global view of app diagnostics and crashes across iOS, Android, Windows Phone 8, Hybrid and HTML5 apps. It offers some easy-to-understand statistics about crashes in specific versions of the app, how often they occurred and how many users have been affected by it. So for instance when your app crashes in Taiwain, you will get a notification about that with the stacktrace of the crash and additional hardware information.
There is actually much more information and features Crittercism offers, but in this post I will mainly focus on the crash-handling features and how you can integrate Crittercism in your Android App.
  Integrating Crittercism in your Android App
First of all, you need to download the Crittercism jar-file, which you can find here:
Now you only need to initialize Crittercism in your App, which should be done in your main Activity class. For instance in our App "Picment" that is done in StartActivity in the onCreate method
import com.crittercism.app.Crittercism; public class StartActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Crittercism.initialize(getApplicationContext(), "YourCrittercismAppID"); . . . } }
Your “Crittercism App ID” is given to you, after you have registered your app on Crittercism. Check out this website, in case you don’t know how to do that. If you have already registered your app, you need to go to “Setting > App Settings”. There you will find your App ID under “Application Information”
Congratulations! Everything is set up and you are ready to use Crittercism. Now if your app crashes, you will be notified with an email about it. As I mentioned at the beginning, Crittercism offers alot of information and tons of analytics, but personally I mostly take a look at the overview of the crashes and each of the stacktraces thrown by the app.
 Here is an overview of the crashes for a specific version of the app:
And here you see a stacktrace a device has thrown:
That’s it! Now you are not helpless, when your app crashes somewhere in the world. In most of the cases you get enough information to fix any bugs.
Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
âś“ Live Streamingâś“ Interactive Chatâś“ Private Showsâś“ HD Qualityâś“ Free Actions
Free to watch • No registration required • HD streaming
One of the most important problems in Android development is the User Interface (UI) responsiveness. Part of this is the fault of Android implementation, but much faults lies on the developer. A key to a good GUI performance in Android development is to move as much work as possible off from the UI thread into the background. Using AsyncTasks is one of the easiest way to do this. In this article I would describe when to use AsyncTasks and give you an example of how to use AsyncTasks in your Android applications.
An AsyncTask is designed to be a helper class around Thread and Handler. As describe in Android documentation:
“AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.”
Simply said: An AsyncTask is used to do some computation in background and publish the result on the UI thread.
AsyncTasks ideally are  designed to perform operations in background which take at most a few seconds. It is not recommended to use them for downloading megabytes of file from server or doing CPU intensive tasks such as image processing. If you want to keep threads running for a long period of time, it is strongly recommended to use Java threads or classes such as  java.util.concurrent.Executor or java.util.concurrent.ThreadPoolExecutor in combination with    android.os.Handler to publish the results on the UI thread.
Note that  you need to do network operations using either Java threads or AsyncTask. In Android 4 attempting to access the network from the UI thread will cause an exception to be thrown.
AsyncTask Life Cycle
The following diagram and table describe the life cycle of AsyncTasks.
AsyncTasks was introduced with Capcake and they were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. In HONEYCOMB again tasks are executed on a single thread to avoid common application errors cased by parallel execution.
Example
To use AsyncTask you must subclass it. An AsyncTask is started via the execute() method.
The execute() method calls the doInBackground() method. The following class demonstrates a registration task, where the response from server is a JSON-Object. For this example you need to download the UrlJSONAsyncTask from here
public class RegisterActivity extends Activity { private static ProgressDialog prDialog; private SharedPreferences mPreferences; private EditText userEmailField; private EditText userNameField; private EditText userPasswordField; private String mEmail, mUserName, mPassword; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Remove title bar this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_register); mPreferences = getSharedPreferences("user", MODE_PRIVATE); userEmailField = (EditText) findViewById(R.id.userEmail); userNameField = (EditText) findViewById(R.id.userName); userPasswordField = (EditText) findViewById(R.id.userPassword); }
public void registerNewAccount(View button) { prDialog = new ProgressDialog(RegisterActivity.this); prDialog.setMessage("Please wait ..."); mEmail = userEmailField.getText().toString(); mUserName = userNameField.getText().toString(); mUserPassword = userPasswordField.getText().toString(); if (mUserEmail.length() == 0 || mUserName.length() == 0 || mUserPassword.length() == 0) { // input fields are empty Toast.makeText(this, "Please complete all the fields", Toast.LENGTH_LONG).show(); return; } else { // everything is ok! RegisterTask registerTask = new RegisterTask(RegisterActivity.this); registerTask.execute(Commons.URLs.REGISTER_API_ENDPOINT_URL); } } private class RegisterTask extends UrlJsonAsyncTask<String, Void, JSONObject> { public RegisterTask(Context context) { super(context); } @Override protected void onPreExecute(){ prDialog.show(); } @Override protected JSONObject doInBackground(String... urls) { HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established. // The default value is zero, that means the timeout is not used. HttpConnectionParams.setConnectionTimeout(httpParameters, Commons.CONNECTION_TIMEOUT);
// Set the default socket timeout (SO_TIMEOUT) // in milliseconds which is the timeout for waiting for data. HttpConnectionParams.setSoTimeout(httpParameters, Commons.CONNECTION_TIMEOUT); DefaultHttpClient client = new DefaultHttpClient(httpParameters); client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); HttpPost post = new HttpPost(urls[0]); JSONObject holder = new JSONObject(); JSONObject userObj = new JSONObject(); JSONObject json = new JSONObject(); String response = null; try { try { // setup the returned values in case something goes wrong json.put("success", false); // add the users's info to the post params userObj.put("email", mEmail); userObj.put("user_name", mUserName.toLowerCase()); userObj.put("password", mPassword); userObj.put("password_confirmation", mPassword); holder.put("user", userObj);
StringEntity se = new StringEntity(holder.toString()); post.setEntity(se); // setup the request headers post.setHeader("Accept", "application/json"); post.setHeader("Content-Type", "application/json"); ResponseHandler responseHandler = new BasicResponseHandler(); response = client.execute(post, responseHandler); json = new JSONObject(response); } catch (HttpResponseException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } catch (JSONException e) { e.printStackTrace(); } return json; } @Override protected void onPostExecute(JSONObject json) { try { prDialog.dismiss(); if (json.getBoolean("success")) { // everything is ok SharedPreferences.Editor editor = mPreferences.edit();
// save the returned auth_token into the SharedPreferences String userName = json.getJSONObject("data").getString("user_name"); String email = json.getJSONObject("data").getString("email"); editor.putString(Commons.SHARED_PREFERENCES_KEYS.AUTH_TOKEgetJSONObject("data").getString("auth_token")); editor.putString(Commons.USERNAME_KEY, userName); editor.putString(Commons.EMAIL_KEY, email); editor.commit(); Toast.makeText(context, json.getString("info"), Toast.LENGTH_LONG).show(); setResult(Commons.RESULT.REGISTRATION_SUCC, getIntent()); Intent addFriends = new Intent(getApplicationConAddFriendsAfterRegistration.class); startService(addFriends); finish(); }else { Toast.makeText(context, json.getJSONObject("data").getJSONArray("errors").get(0).toString(), Toast.LENGTH_LONG).show(); } } catch (Exception e) { // something went wrong: show a Toast // with the exception message } finally { super.onPostExecute(json); } } } }
Disadvantages of using AsyncTasks
The AsyncTask does not handle configuration changes automatically, i.e. if the activity is recreated, the programmer has to handle that in his coding. A common solution to this is to declare the AsyncTask in a retained headless fragment.
Summery
AsyncTask  is an intelligent thread that is advised to be used. Intelligent as it can help with it’s methods, and there are two methods that run on UI thread, which is good to update UI components.
Use AsyncTask for:
Simple network operations which do not require downloading a lot of data
Disk-bound tasks that might take less than a few milliseconds