Skip to content
Zhibin Ye edited this page Feb 24, 2017 · 36 revisions

该文档主要用户对**SJH - Android Client**的优化方案和策略。

Code Style / 代码规范&习惯

  • private修饰变量前缀加m,例如:private int mCount;
  • static修饰变量前缀加s,例如:static String sName;
  • const常量为大写,例如:private final static int DEFAULT_TIME;
  • xml布局文件命名为:activity_topic, fragment_feed, layout_loading, dialog_selector, item_user等;
  • 控件id一般为操作大领域-小领域-控件类型,例如:car_wheel_btn;
  • 注意尽量不要出现Magic number/Hard code,例如:
    intent.putExtra("erp", erpValues); // 建议写成:
    static final String EXTRA_ERP = "erp;   
    intent.putExtra(EXTRA_ERP, erpValues);

    textview.setTextSize(14); //建议写成:
    static final int DEFAULT_TEXT_SIZE = 14;
    textview.setTextSize(DEFAULT_TEXT_SIZE);
  • 请勿保留无用的注释掉的代码,多余的注释代码会影响阅读代码的效率(颜色和行参吃不齐),如果需要找到以前的代码可以通过git log [FILENAME]即可,或者在Android Studio里面右键--GIT--git history即可查看历史。
  • 未完成的功能/实现方案含有trick的代码需要加上 TODO 标签。
  • Android Studio 自带有word check单词检查功能,对于有波浪线并且错误的单词建议修改。
  • 函数的命名尽量是如果是涵盖所有的实现内容,比如buyCar(), 该函数仅包含买车的所有实现,尽量不要出现其他的功能实现,当然可以包含准备买车的一些检查等。
  • 尽量做到代码即注释,没有必要写过多的多余代码,仅在你的实现逻辑不太容易理解或者方案有所trick时候需要加上注释。

Speed up / 敏捷性开发

  • 尽量细分化任务,把一个大模块下每一个小功能细分为一个子任务来实现,可以在相关的管理网站上标记自己需要做的事情,比如gitlab/github之类的。
  • 在动手写一个比较大的模块之前尽量跟团队协商一下这个功能的实现方案,自己所考虑的策略在别人看来不一定成立,在方案健全的情况下再动手写代码会比你写完以后发现重大bug再修改快一下,磨刀不误砍柴。
  • 把Android Studio的VM heap size调整到你内存的1/3来加快IDE在低内存下的运作。
  • 尽量把一些可复用的代码进行封装,方便以后重复使用不用再写相同的逻辑,至少需要封装什么代码,经验会告诉你。

Teamwork / 团队协作

  • 尽量对git和git internal有所了解。
  • 尽量是一个子任务分为一个branch,branch命名的方案为:
  • feature/profile //新功能profile页的开发
  • enhancement/imageLoad //对图片加载进行优化
  • bugfix/loginLogic //对登录逻辑bug的修复
  • 在每次的commit尽量是清晰的一次小任务,比如log为Added get user info api, 这里只做的是添加用户信息的接口,尽量不要掺杂其他内容,方便以后的版本历史查询。
  • 如果发现有重大bug需要revert代码的时候需要和团队进行协商沟通。

Architecture / 基本结构

image

  • 其中说明几点:
  • 自上向下不能存在任何依赖关系,从上而下或者同层可以存在依赖关系。
  • 同层级如果能够依靠Dagger解耦就尽量解耦。
  • 其中Application层将按照功能视图相关、CustomView、Service进行分包。
  • 现在的package也将按照这个结构进行分包。
  • 在项目壮大将会给部分module分成一个git submodule来管理

Network & Protocol / 网络协议处理

RxJava

RxJava是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库,主要特性有以下几点:

  • 灵活的线程切换
  • 强大的多种操作符功能
  • 方便的绑定页面的生命周期
  • 单一的数据类型,强大的异步回调

参考文档:给 Android 开发者的 RxJava 详解
GITHUB:ReactiveX/RxJava

Retrofit

Retrofit 是Square公司开发的一个网络库,能完美的和Okhttp配合完成绝大部分的网络场景,同时能够和RxJava进行结合让网络请求变得非常简便。
使用参考:

    @GET("/api/userInfo")
    Observable<UserInfo> getUserInfo(@Field("id") String uid);

    @POST("/api/file")
    Observable<HttpResult> uploadFile(@Part("file") RequestBody file);
    
    // 结合RxJava
    apiService.getUserInfo(mTargetUserId)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new ResultCallback<UserInfo>() {
                    @Override
                    protected void onFailure(ApiException e) {
                        // Do something.
                    }

                    @Override
                    protected void onSuccess(UserInfo userInfo) {
                        // Do something.
                    }
                })

参考文档:快速Android开发系列网络篇之Retrofit
GITHUB:Square/retrofit

View & Layout / 视图布局层的处理

ButterKnife

ButterKnife是一个View注入的插件,对比于现在的我们所使用Annotation来说,ButterKnife所使用的apt在编译时候生成view的注释代码大大加快了在运行时候通过注解反射来绑定View的时间,可以通过Android Studio插件进行一键来生成View的绑定。
d2 使用参考:

@Bind(R.id.toolbar)
Toolbar toolbar;

@OnClick(R.id.click_btn)
public void commit() {
 // Do something.
}

参考文档:Butterknife docs
GITHUB:[JakeWharton/butterknife](https://github.com/JakeWharton/butterknife

RecyclerView

RecyclerView是Google在5.0的时候取代ListView的一个新的控件,我们项目中大量使用了ListView,现在Google对ListView已经不在有更多的支持,并且我们对ListView并没有任何封装的情况建议更换为RecyclerView,RecyclerView具有如下几个特性:

  • 支持横向纵向的Linear/Grid布局,同时还支持瀑布流。
  • Adapter已经封装好ViewHolder,不需要我们再对ViewHolder进行复用处理。
  • 支持多项item动画,同时可以配合CoordinateLayout使用能很好的实现Material Design的风格。
    具体使用和ListView大体相同,但是Adapter会有不一样,我封装了一套比较完整的Adapter(传送门),具体使用参考如下:
public class MusicAdapter extends BaseAdapter<MusicModel> {
    public MusicAdapter(Context context) {
        super(context);
    }

    @Override
    protected void bindDataToItemView(BaseViewHolder holder, MusicModel item, int position) {
        holder.setText(R.id.name_tv, item.name)
                .setText(R.id.price_tv, "$ " + item.price)
                .setTextColorRes(R.id.price_tv, R.color.white);
        holder.getView(R.id.custom_view).setXXXX();

        if(isLargeMusicItem(position, item)) {
            // Do something
        }
    }

    @Override
    protected int getItemViewLayoutId(int position, MusicModel musicModel) {
        if (isLargeMusicItem(position, musicModel)) {
            return R.layout.item_music_large;
        }
        return R.layout.item_music_small;
    }

    private boolean isLargeMusicItem(int position, MusicModel musicModel) {
        return 0 == position % 3 && musicModel.price < 80;
    }
}

Performance optimized / 性能优化方案

  • 可以用自带的memory heap工具查看当前页面所在的泄露问题。
  • 在使用glide的时候,我们的placeholder应该是一个单例,这里glide存在一个bug每次创建placeholder都会占用内存。
  • 在加载图片的时候,服务器尽量返回大小合适的图片。
  • 在写xml布局的时候,尽量少嵌套多层布局,尽量少用RelativeLayout布局,能用LinearLayout尽量使用。
  • 在写任何异步请求的时候都需要在脑海中注意当前异步任务未完成但是页面已经关闭的情况
  • 在写列表页的时候尽量考虑每个bindItem的时候时间复杂度,每次bindItem时候的时间复杂度尽量保持在<=O(n)。

Size optimized / 体积优化方案

  • 在多个module中尽量使用同一个compile sdk version
  • 可以用使用lint工具查找unused resource删除掉无用资源。
  • 给release包进行混淆处理,在Gradle里面配置minifyEnable = true 即可。
  • 在含有多套的图片/icon的时候尽量只使用1-2套,保证在市面上流行的机器正常运行即可,所有png都需要经过压缩。
  • 移除无用的代码和module。

Others tip / 其他提示

  • 在开发中尽量用Gradle/Jar导入项目,可以省去Java类的编译时间。
  • 一些通用性的View尽量去封装处理,比如咱们的我的个人信息里面有多个item是可以复用在多个个人信息页中。
  • 尽量不要手动解析JSON, 可以参考使用GSON或者fastJSON, 因为如果一个参数名修改,你需要修改实体类同时需要修改解析的方法。
  • 在多个Activity需要使用的方法建议写到BaseActivity中,同时需要注意是否申请多余的内存空间(若是可以考虑懒加载)。
  • 大部分复杂的异步逻辑都可以通过RxJava进行实现简化。
  • 我们的api不要放在res中,可以写在单一的java文件或者properties文件里面。
  • 在写一些可抽离的通用的View/Utils时候可以在文件名加上公司或者团队前缀,方便以后的抽离也方便后来人使用。