Several scenarios leading to ANR

1. The main thread of the Activity does not process time-consuming operations and must start a new thread. Time-consuming operations in the UI thread will cause UI response blocking, resulting in ANR.

public static class MyAsyncTask extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... params) {... } @override protected void onPostExecute(String result) {showtv.settext (" main thread shows UI"); }}Copy the code

2. Time-consuming operations in Service and BroadcastReceiver must be performed in the worker thread. Time-consuming operations in Service and BroadcastReceiver work in the main thread, and time-consuming operations need to be handled asynchronously.

public class MyService extends IntentService { .... @Override public void onCreate() { super.onCreate(); } @Override protected void onHandleIntent(@Nullable Intent intent) { ... doHeavyOperation(); // Run on a worker thread. }}Copy the code

3. Multiple thread deadlocks cause ANR: Lock and release in the same order to prevent deadlocks;

Null pointer

  1. The incoming parameters of a cross-trust domain method need to be nulled: for example, in the Receiver callback method;

    public class MyReceiver extends BroadcastReceiver { ….. @Override public void onReceive(Context context, Intent intent) { … if (context == null || intent == null) { return; } String action = intent.getAction(); // The intent is not empty, so you can call its method. . }}

2. The method in the trust domain can declare whether the parameter can be empty through annotations;

Public void nonNullParamFunction(@nonnull Context Context) {// Add a non-null annotation context.getColor(); . }Copy the code

3. Pre-nullity is used for objects obtained by calling methods;

public class MyFragment extends Fragment { private void myFunction() { Activity activity = getActivity(); if (activity instanceof ActivityA) { ActivityA activityA = (ActivityA) activity; Activitya.functiona (); }}}Copy the code

3. Data verification

  1. Parameters are transmitted across trust domains, and the validity of parameters must be verified before being used.

  2. Do instanceof judgment before type conversion, can not be strong conversion without judgment;

    public class MyFragment extends Fragment { private void myFunction() { Activity activity = getActivity(); ActivityA = (ActivityA) activity; ActivityA = (ActivityA) activity; activityA.functionA(); }}}

3. String is converted to the specified numeric type.

private void parse(String string) { int parsedValue = 0; try { int parsedValue = Integer.parseInt(string); } Catch (NumberFormatException exception) {log.w (TAG, "Error String format!" ); }}Copy the code

4. Check that the divisor is non-zero before using the division/operator.

Iv. Compatibility

1. FLAG_ACTIVITY_NEW_TASK must be set to start an Activity from a non-activity context (added after 10.0);

public startActivityFromAppContext() { Intent intent = new Intent(getApplicationContext(), MainScreenActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); FLAG_ACTIVITY_NEW_TASK getApplicationContext().startActivity(intent); }Copy the code

2. In major version upgrades, new interfaces need to be called by reflection.

BatteryManager bm = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE); if (bm == null) { return false; } int result = 0; Method method = ReflectUtils.getDeclaredMethod(BatteryManager.class, "getWirelessTxSwitch"); Object invokedResult = ReflectUtils.invoke(method, bm); if (invokedResult instanceof Integer) { result = (Integer) invokedResult; }}Copy the code

5. Memory leaks

1. When the Handler implementation needs to reference an external class, it uses static inner class + weak reference;

public class CustomService extends Service { private CustomHandler mHandler; @Override public void onCreate() { super.onCreate(); mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new CustomHandler(this, mHandlerThread.getLooper()); } private static class CustomHandler extends Handler{private WeakReference<Context> mReference; // use a WeakReference object. When the CustomService is reclaimed by the JVM, it can be garbage collected normally because the CustomHandler holds a WeakReference to it. public CustomHandler(Context context,Looper looper){ super(looper); mReference = new WeakReference<Context>(context); } @Override public void handleMessage(Message msg) { Context context = mReference.get(); context.XXXX(); . }}}Copy the code

2. Remove all messages from the Handler when the external class of the Handler ends.

public class CustomService extends Service { private CustomHandler mHandler; @Override protected void onCreate() { super.onCreate(); mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new Handler(mHandlerThread); } @Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(); mHandlerThread.quitSafely(); }}Copy the code

3. The singleton life cycle is consistent with that of the application. For example, you need to use ApplicationContext to reference context.

public class SingleInstance {
    private static SingleInstance sInstance;
    private Context context;
    private SingleInstance context) {                   
        this.context = context.getApplicationContext();
    }
    public static SingleInstance getInstance(Context context) {
        if (sInstance!= null) {
	    sInstance = new SingleInstance(context);
	}
	return sInstance;
    }
}
Copy the code

4. Resource objects not closed: Cursor/InputStream/OutputStream/IO streams

5. For the Native memory occupied by Bitmap, the GARBAGE collection mechanism of JVM cannot recover the Native memory, so you need to actively call the Recycle () method to recycle it after using it.

6. Component registration and reconciliation fails: BroadcastReceiver and ContextOberver;

7. The AlertDialog hangs on the window. When the dependent Activity loses focus, the dialog needs to dismiss;

public class MyActivity extends Activity { private AlertDialog mDialog; @Override protected void Resume() { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); MDialog = dialogBuilder.seticon (r.map.ic_launcher).setTitle(" title ").setMessage(" message ").setCancelable(true).create(); mDialog.show(); } @Override void onStop() { super.onStop(); if (mDialog ! = null && mDialog.isShowing()) { mDialog.dismiss(); }}}Copy the code