美文网首页
Android开发注意事项

Android开发注意事项

作者: 米开朗琪戈 | 来源:发表于2021-02-25 18:15 被阅读0次

    以下总结全部来源于开发经验积累,干货满满的,有问题请邮箱1057915589@qq.com,感谢!敬礼~

    1、安卓xml命名:比如以音乐模块为例
    music_activity.xml、music_fragment.xml、music_dialog.xml、music_list_item.xml、

    music_recycle_item.xml、music_grid_item.xml等

    2、资源文件命名:登录按钮背景资源图片(模块名_功能_控件描述_控件限定词)

    base_login_btn_pressed.png、base_login_btn_normal.png

    3、颜色由于是整个app共用的,所以我不太同意阿里规约的命名方式,我感觉可以写一套直接根据色值查找更合理

    比如:白色<color name="color_ffffff">#ffffff</color> 只需要命名一套即可

    4、控件命名可以使用控件名称缩写作为前缀,如下:

    LinearLayout对应ll、RelativeLayout对应rl、ConstraintLayout对应cl、ListView对应lv

    ScollView对应sv、TextView对应tv、Button对应btn、ImageView对应iv、CheckBox对应cb

    RadioButton对应rb、EditText对应et

    5、Android的四大组件:Activity、Fragment、Service、BroadcastReceiver

    Activity间通信可以考虑EventBus,避免数据太大报TransactionTooLargeException

    Activity的onSaveInstanceState()方法不是生命周期方法,不保证一定会被调用,它是Activity意外被销毁保存Ui状态的,只能用于临时保存数据,持久化存储应该放在onPause、onStop中

    6、Activity间隐式跳转,在发出Intent之前要通过resolveActivity检查目标组件能否找到,避免报ActivityNotFoundException的异常,比如:

     if(getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ ONLY) !=null) {

    ..................

    }

    7、Service的onStartCommand()、onBind()不能执行耗时操作,如果需要应改用IntentService或者采用异步机制完成

    8、避免在BroadcastReceiver的onReceiver()中执行耗时操作,可以通过创建IntentService完成

    9、Context的sendBroadcast()发送隐式广播会被所有感兴趣的receiver接收,避免敏感信息泄露,广播可以仅限于应用内,可以使用LocalBroadcastManager的sendBroadcast()方法,避免敏感信息外泄和Intent拦截风险,比如:

    Intent intent = new Intent("my-sensitive-event");

    intent.putExtra("event", "this is a test event");

    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

    10、不要在Activity的onDestory()内执行释放工作,比如线程的销毁、停止,由于onDestory()执行的时机比较晚,可以按实际需要结合ifFinishing()判断在Activity的onPause()、onStop()中

    11、Service组件运行在主线程中,避免耗时操作,如果有耗时操作可以使用IntentService执行后台任务

    12、当前Activity的onPause方法执行结束后会执行下一个Activity的onCreate方法,所以onPause方法中不适合执行耗时工作,会影响页面间跳转效率。

    13、不要在Application对象缓存全局数据,尽量用Intent传递或者SharedPreferences数据持久化机制

    14、Activity或者Fragment中动态注册的BroadCastReceiver时,registerReceiver()和unregisterReceiver()要成对出现

    15、布局尽量扁平化,防止View渲染经过measure、layout、draw消耗过多时间,尽量控制每一帧在16毫秒内绘制完成。

    16、禁止在布局中多次设置子View和父View中为同样的背景造成过度绘制

    17、尽量不要使用AnimationDrawable,它在初始化的时候将所有图片加载到内存中,特别占内存,并且还不能释放,容易内存溢出

    18、不要使用ScrollView包裹LIstView/GridView/ExpandableListView,因为它会把ListView的所有Item都加载到内存中,要消耗巨大的内存与CPU去绘制图面,如果非要用,推荐NestedScrollView。

    19、不要通过Intent在Android基础组件之间传递大数据(binder transaction 缓存为1MB),可能导致OOM。

    20、Application的业务初始化加入进程判断,确保只在自己需要的进程初始化,特别是后台进程减少不必要的业务初始化。

    21、新建线程时,必须通过线程池提供,不允许在应用中自行闲时创建线程。

    比如:

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

    int KEEP_ALIVE_TIME = 1;

    TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

    BlockingQueue taskQueue = new LinkedBlockingQueue();

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

    //

    执行任务

    executorService.execute(new Runnnable() {

    ...

    });

    22、子线程中不能更新界面,更新界面必须在主线程中进行,网络操作不能在主线程中调用。

    23、ThreadPoolExecutor设置线程存活时间,确保空闲时线程能被释放。

    24、谨慎使用Android多进程,多进程虽然能够降低主进程的内存压力,但会有如下问题:

    第一、不能实现完全退出所有Activity的功能

    第二、首次进入新启动进程页面会有延时的现象(黑屏、白屏几秒)

    第三、应用内多进程是,Application实例化多次,需要考虑各个模块是否都需要在所有进程初始化;

    第四、多进程间通过SharedPreferencs共享数据是不稳定

    25、SharedPreference提交数据时,尽量使用Editor的apply(),而非Editor的commit(),仅当需要确定提交结果,并据此有后续操作是,才用commit()。(apply方法提交先写入内存,然后异步写入磁盘,commit方法直接写入磁盘,频繁操作的话,apply的性能会优于commit);

    26、数据库Cursor必须确保使用完后关闭,以免内存泄漏

    public void handlePhotos(SQLiteDatabase db, String userId) {

    Cursor cursor;

    try {

    cursor = db.query(TUserPhoto, new String[] { "userId", "content" }, "userId=?", new

    String[] { userId }, null, null, null);

    while (cursor.moveToNext()) {

    // TODO

    }

    } catch (Exception e) {// TODO

    } finally {

    if (cursor != null) {

    cursor.close();

    }

    }

    }

    27、多线程操作写入数据库时,需要使用实物,避免出现同步问题。

    比如:

    public void insertUserPhoto(SQLiteDatabase db, String userId, String content) {

    ContentValues cv = new ContentValues();

    cv.put("userId", userId);

    cv.put("content", content);

    db.beginTransaction();

    try {

    db.insert(TUserPhoto, null, cv);

    // 其他操作

    db.setTransactionSuccessful();} catch (Exception e) {

    // TODO

    } finally {

    db.endTransaction();

    }

    }

    28、大数据写入数据库时,请使用事务或其他能够提高I/O效率的机制,保证执行速度。

    比如:

    public void insertBulk(SQLiteDatabase db, ArrayList users) {db.beginTransaction();

    try {

    for (int i = 0; i < users.size; i++) {

    ContentValues cv = new ContentValues();

    cv.put("userId", users[i].userId);

    cv.put("content", users[i].content);

    db.insert(TUserPhoto, null, cv);

    }

    //

    其他操作db.setTransactionSuccessful();

    } catch (Exception e) {

    // TODO

    } finally {

    db.endTransaction();

    }

    }

    29、加载大图片或者一次性加载多张图片,应在异步线程中进行,图片加载设计到IO操作,以及CPU密集操作,容易引起卡顿。

    正例:

    class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

    ...

    //

    在后台进行图片解码

    @Override

    protected Bitmap doInBackground(Integer... params) {

    final Bitmap bitmap = BitmapFactory.decodeFile("some path");

    return bitmap;

    }

    ...

    }

    30、在 ListView,ViewPager,RecyclerView,GirdView 等组件中使用图片时,

    应做好图片的缓存,避免始终持有图片导致内存泄露,也避免重复创建图片,引起

    性 能 问 题 。建议使用Fresco、Glide等图片库,可以使用系统LruCache缓存:

    正例:

    private LruCache mMemoryCache;@Override

    protected void onCreate(Bundle savedInstanceState) {

    ...

    //

    获取可用内存的最大值,使用内存超出这个值将抛出 OutOfMemory 异常。LruCache 通

    过构造函数传入缓存值,以 KB 为单位。

    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

    // 把最大可用内存的 1/8 作为缓存空间

    final int cacheSize = maxMemory / 8;

    mMemoryCache = new LruCache(cacheSize) {

    @Override

    protected int sizeOf(String key, Bitmap bitmap) {

    return bitmap.getByteCount() / 1024;

    }

    };

    ...

    }

    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {

    if (getBitmapFromMemCache(key) == null) {

    mMemoryCache.put(key, bitmap);

    }

    }

    public Bitmap getBitmapFromMemCache(String key) {

    return mMemoryCache.get(key);

    }

    public void loadBitmap(int resId, ImageView imageView) {

    final String imageKey = String.valueOf(resId);

    - 45 -

    七、Bitmap、Drawable 与动画

    final Bitmap bitmap = getBitmapFromMemCache(imageKey);

    if (bitmap != null) {

    mImageView.setImageBitmap(bitmap);

    } else {

    mImageView.setImageResource(R.drawable.image_placeholder);

    BitmapWorkerTask task = new BitmapWorkerTask(mImageView);

    task.execute(resId);

    }

    }

    class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

    ...

    // 在后台进行图片解码

    @Override

    protected Bitmap doInBackground(Integer... params) {

    final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(),

    params[0], 100, 100));

    addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);return bitmap;

    }

    ...

    }

    31、png图片使用tinypng工具压缩处理,减少apk包体积大小

    32、在Activity.onPause()或者Activity.onStop()回调中,关闭当前activity正在执行的动画。

    33、使用ARGB_565代替ARGB_888,在不怎么降低视觉效果的前提下,减少内存占用

    34、在有强依赖 onAnimationEnd 回调的交互时,如动画播放完毕才能操作页

    面,onAnimationEnd 可能会因各种异常没被回调,建 议 加 上 超 时 保 护 或 通 过 postDelay 替 代

    onAnimationEnd。

    正例: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) {

    //判断一下资源是否被释放了if (v != null) {

    v.clearAnimation();

    }

    }

    });

    v.startAnimation(anim);

    35、未完,待更新~

    相关文章

      网友评论

          本文标题:Android开发注意事项

          本文链接:https://www.haomeiwen.com/subject/pbhxtltx.html