background

With the aftertaste of 2018 Spring Festival still lingering, Alibaba has prepared a belated New Year gift for mobile developers — alibaba Android Development Manual version 1.0.1.

Here I write down my reading notes to record some problems that I do not pay attention to at ordinary times and regulate myself.

The body of the

1. The “mandatory” through implicit Intent to jump between the Activity, must be inspected by resolveActivity before send Intent, avoid no suitable component, called ActivityNotFoundException abnormalities.

public void viewUrl(String url, String mimeType) {
	Intent intent = new Intent(Intent.ACTION_VIEW);
	intent.setDataAndType(Uri.parse(url), mimeType);
	if(getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ ONLY) ! = null) { startActivity(intent); }else{// Can not find the specified Activity}}Copy the code

2. Avoid using BroadcastReceiver#onReceive(). If it is BroadcastReceiver#onReceive(), it is better to create IntentService instead of subthread.

Description:

Since this method is executed on the main thread, the UI is not smooth if you perform a time-consuming operation. Context#registerReceiver (BroadcastReceiver, IntentFilter, String, BroadcastReceiver) Handler) method in other Wroker threads to execute onReceive method. The BroadcastReceiver#onReceive() method takes more than 10 seconds and may be killed by the system.

1. 3. Smart refrigerator Ensure that fragmentAction #commit() is called within Activity#onPostResume() or FragmentActivity#onResumeFragments(). Do not use FragmentTransaction#commitAllowingStateLoss() instead, any use of commitAllowingStateLoss() must be reviewed to ensure no negative effects.

Description:

An Activity can be destroyed for a variety of reasons, and the Android support page saves its own state via Activity#onSaveInstanceState() before being destroyed. But if FragmentTransaction.com MIT () in the Activity state after save, will cause the Activity heavy build, restore state cannot restore page state, which could go wrong. In order to avoid bad to cause the user experience, the system will be thrown IllegalStateExceptionStateLoss anomalies. Recommended practice is the Activity of onPostResume () or onResumeFragments () (to FragmentActivity) performed in FragmentTransaction.com MIT (), also can be in if necessary OnCreate (). Don’t use FragmentTransaction.com mitAllowingStateLoss () or directly use try-catch avoid the crash, that is not the root of the problem solution, if and only if you confirm the Activity Do this only when the loss of this commit will not have an impact when rebuilding or restoring the state.

4. Do not free resources within Activity#onDestroy(), such as destroying and stopping worker threads, because onDestroy() may be executed late. This can be done in Activity#onPause()/onStop() with isFinishing() judgment as needed.

5. [Recommended] Always start or bind a Service with an explicit Intent and do not declare an IntentFilter for the Service to ensure application security. If you really want to use implicit invocation, you can provide an Intent Filter for the Service and exclude the component name from the Intent, but you must set the Intent with the Intent#setPackage() method Specify a package name for the target service, which fully eliminates the uncertainty of the target service.

6. For broadcasts only used in applications, it is preferred to use LocalBroadcastManager for registration and transmission, which has better security and higher operation efficiency.

Description:

Prompt for code that sends a global broadcast using Context#sendBroadcast() and other methods. If the broadcast is only used in applications, LocalBroadcastManager can be used to avoid security issues such as broadcast leakage and broadcast interception, and is more efficient than global broadcast local broadcast.

7. Other activities are created (onCreate) or resumed (onRestart) only after the onPause method of the current Activity is executed. Therefore, the onPause method is not suitable for time-consuming activities, which may affect the efficiency of page hops.

8. [Recommended] Use dp for text size and DP for View size. For TextView, it is recommended to use wrAP_content layout if the text size is determined to avoid the problem of incomplete text display.

Description:

The text size is also recommended to use DP instead of SP, because SP was recommended by Android in the early stage, but its real SP is not only affected by the screen density as DP, but also by the font size in system Settings. Therefore, using DP will ensure the consistency and restore degree of UI for application development.

9. [Recommendation] When using Toast, it is recommended to define a global Toast object, so as to avoid the situation that the last Toast message cannot be cancelled when the Toast is displayed continuously. Avoid direct calls Toast#makeText even if you need to pop up toasts continuously.

10. [Mandatory] Do not allow the thread pool to be created by Executors. Use the ThreadPoolExecutor method to clear the thread pool operation rules and avoid resource depletion.

Description:

* If the thread pool object returns by Executors, it has the following disadvantages:

  1. FixedThreadPool and SingleThreadPool: allow queue length integer. MAX_VALUE, which may cause a large number of requests to accumulate, resulting in OOM.

  2. CachedThreadPool and ScheduledThreadPool: Allow Integer.MAX_VALUE to create a large number of threads, resulting in OOM.

Is:

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); 

int KEEP_ALIVE_TIME = 1;

TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>(); 

ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES*2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT,
taskQueue, new BackgroundThreadFactory(), new DefaultRejectedExecutionHandler());

Copy the code

Example:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

Copy the code

11. [Recommended] ThreadPoolExecutor Sets the thread lifetime (setKeepAliveTime) to ensure that threads can be released when idle.

12. [Recommended] Disable data sharing using SharedPreferences between multiple processes. Although it is possible (MODE_MULTI_PROCESS), it is not officially recommended.

13. [Mandatory] Do not hardcode the file path at any time, please use the Android file system API to access.

Description:

Android applications provide internal and external storage for storing application data and user data generated by applications respectively. You can use related apis to obtain corresponding directories and perform file operations.

  1. android.os.Environment#getExternalStorageDirectory()

  2. android.os.Environment#getExternalStoragePublicDirectory()

  3. android.content.Context#getFilesDir()

  4. android.content.Context#getCacheDir

Is:

public File getDir(String alName) {
	File file = new File(Environment.getExternalStoragePublicDirectory(Environment. 		DIRECTORY_PICTURES), alName);
	if(! file.mkdirs()) { Log.e(LOG_TAG,"Directory not created");
	}
	return file;
}

Copy the code

Example:

Public File getDir(String alName) {// Do not hardcode the File path at any time."/mnt/sdcard/Download/Album", alName);
	if(! file.mkdirs()) { Log.e(LOG_TAG,"Directory not created");
	}
	return file;
}

Copy the code

14. [Mandatory] Check the availability of external storage devices

Is:

// Read/write check public BooleanisExternalStorageWritable() {
	String state = Environment.getExternalStorageState();
	if (Environment.MEDIA_MOUNTED.equals(state)) { 
		return true;
	}
	return false; } // Read-only check public BooleanisExternalStorageReadable() {
	String state = Environment.getExternalStorageState();
	if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
		return true;
	}
	return false; 
}

Copy the code

15. [Mandatory] When sharing files between applications, use FileProvider instead of relaxing file system permissions.

16. [Mandatory] If the data managed by ContentProvider is stored in an SQL database, you should avoid directly concatenating untrusted external data into the original SQL statement.

????? What kind of joke is this??

Is:

// Use an alternative argument String mSelectionClause ="var = ?"; String[] selectionArgs = {""}; selectionArgs[0] = mUserInput;

Copy the code

Example:

// Concatenates user input and column names. String mSelectionClause ="var = " + mUserInput;

Copy the code

17. [Mandatory] Use TinyPNG or similar tools to compress PNG images to reduce the package size.

18. [Recommendation] Compress the image according to the actual display needs, rather than directly display the original image. The small screen of the phone, which displays the original image directly, does not increase the visual benefit, but it consumes a lot of valuable memory.

Is:

Public static Bitmap decodeSampledBitmapFromResource (Resources res, int resId, int reqWidth, int reqHeight) {/ / by firstinJustDecodeBounds=trueFinal bitmapFactory.options Options = new bitmapFactory.options (); options.inJustDecodeBounds =true; BitmapFactory.decodeResource(res, resId, options); Options. inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); / / set the compression ratio, and decoding options. InJustDecodeBounds =false;
	return BitmapFactory.decodeResource(res, resId, options);
}

Copy the code

19.【 Force 】 In an Activity#onPause() or Activity#onStop() callback, close the animation that the activity is currently executing.

Is:

public class MyActivity extends Activity {
        ImageView mImageView;
        Animation mAnimation;
        Button mBtn;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            mImageView = (ImageView) findViewById(R.id.ImageView01);
            mAnimation = AnimationUtils.loadAnimation(this, R.anim.anim);

            mBtn = (Button) findViewById(R.id.Button01);
            mBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mImageView.startAnimation(mAnimation); }}; } @Override public voidonPause() {/ / page, clear in time animation resources mImageView. ClearAnimation (); }}Copy the code

20. [Recommended] Use RGB_565 instead of RGB_888 to reduce memory footprint without much visual impact.

Description:

Android. Graphics. The Bitmap. The Config class definition about the storage style of the picture color:

  1. ALPHA_8 stands for 8-bit Alpha bitmap;

  2. ARGB_4444 stands for 16-bit ARGB bitmap;

  3. ARGB_8888 stands for 32-bit ARGB bitmap;

  4. RGB_565 stands for 8-bit RGB bitmap.

The higher the bitmap number, the more color information is stored and the more realistic the image is. Most scenarios use ARGB_8888 and RGB_565, which is a solution to OOM by reducing memory overhead while maintaining image quality.

However, it is important to note that RGB_565 has no transparency. If the image itself needs to be transparent, RGB_565 should not be used.

Is:

Config config = drawableSave.getOpacity() ! = PixelFormat.OPAQUE ? Config.ARGB_8565 : Config.RGB_565; Bitmap bitmap = Bitmap.createBitmap(w, h, config);Copy the code

Example:

Bitmap newb = Bitmap.createBitmap(width, height, Config.ARGB_8888);

Copy the code

21. In interactions that rely heavily on the onAnimationEnd callback,onAnimationEnd may not be called due to various exceptions (see: https://stackoverflow.com/questions/5474923/onanimationend-is-not-getting-calle d-onanimationstart-works-fine ), Add timeout protection or replace onAnimationEnd with postDelay.

Is:

	View v = findViewById(R.id.xxxViewID);
        final FadeUpAnimation anim = new FadeUpAnimation(v);
        anim.setInterpolator(new AccelerateInterpolator());
        anim.setDuration(1000);
        anim.setFillAfter(true);
        new Handler().postDelayed(new Runnable() {
            public void run() {
                if(v ! = null) { v.clearAnimation(); } } }, anim.getDuration()); v.startAnimation(anim);Copy the code

22. When the View Animation finishes, call View.clearAnimation() to release related resources.

Is:

	View v = findViewById(R.id.xxxViewID);
        final FadeUpAnimation anim = new FadeUpAnimation(v);
        anim.setInterpolator(new AccelerateInterpolator());
        anim.setDuration(1000);
        anim.setFillAfter(true);
        anim.setAnimationListener(new AnimationListener() {@override public void onAnimationEnd(Animation arg0) {// Check whether the resource is freedif (v != null) {
                v.clearAnimation();
            }
        });
        v.startAnimation(anim);

Copy the code

conclusion

To be honest, this manual is quite well summarized, although the content is a little short, but it is only version 1.0.1 and will be improved.

I don’t think point 8 above makes much sense:

8. [Recommended] Use dp for text size and DP for View size. For TextView, it is recommended to use wrAP_content layout if the text size is determined to avoid the problem of incomplete text display.

Description:

The text size is also recommended to use DP instead of SP, because SP was recommended by Android in the early stage, but its real SP is not only affected by the screen density as DP, but also by the font size in system Settings. Therefore, using DP will ensure the consistency and restore degree of UI for application development.

I think: if the user sets the system font size, so must hope to overall system font becomes large or small, and what’s the matter with your APP does not change, it looks not harmonious, 2 will not achieve the purpose of the user to change system font size, feel it is a little destruction of ecological system, is not recommended to do so.