优雅代码养成笔记

1.本文通用约定

该约定参考自 Effective java 第二版

  • 服务端: 并不是指运行在服务器端的程序,而是在工程中,提供基本方法的部分。
  • 客户端: 并不是指运行在用户手机中的程序,而是在工程中,调用提供基本方法的部分。

编码系列

2.异常管理

代码如下

public class ExceptionUtils {

 /**
  * 对象的非空校验
  *
  * @param object  代校验的参数
  * @param message 如果参数为空时的异常堆栈信息
  * @param <T>
  * @return
  */
  public static <T> T checkoutNotNull(T object, String message) {
    if (object == null) {
        throw new NullPointerException(message);
    }
    return object;
  }
}

参考自 Retrofit源码 v2.0.0

优点

  • 空指针这样的异常,通过这种方法检测。在服务端代码段中使用。
  • 保证了服务工具的封装性(检测的代码放在服务端,符合面向对象的编程风格)
  • 保证了客户端代码的简洁性(参数校验不应该由客户端调用)
  • 保证了整体代码的可调式性。
  • 如果参数合法,返回输入参数,方便客户端处理

3.Builder模式创建可选参数对象

代码如下

public class ZMDialog {


  public static class Builder {

    private Context context;
    private String title;
    private String message;
    private String positiveMessage;
    private String negativeMessage;
    private ZMSubscriber positiveClickEvent;
    private ZMSubscriber negativeClickEvent;
    private boolean cancelable;

    public Builder(Context context) {
        this.context = context;
    }

    public Context getContext() {
        return context;
    }


    public String getTitle() {
        return title;
    }

    public Builder setTitle(String title) {
        this.title = title;
        return this;
    }

    public String getMessage() {
        return message;
    }

    public Builder setMessage(String message) {
        this.message = message;
        return this;
    }

    public String getPositiveMessage() {
        return positiveMessage;
    }

    public Builder setPositiveMessage(String positiveMessage) {
        this.positiveMessage = positiveMessage;
        return this;
    }

    public String getNegativeMessage() {
        return negativeMessage;
    }

    /**
     * 单选对话框的话,需要用这个
     *
     * @param negativeMessage
     * @return
     */
    public Builder setNegativeMessage(String negativeMessage) {
        this.negativeMessage = negativeMessage;
        return this;
    }

    public ZMSubscriber getPositiveClickEvent() {
        return positiveClickEvent;
    }

    public Builder setPositiveClickEvent(ZMSubscriber positiveClickEvent) {
        this.positiveClickEvent = positiveClickEvent;
        return this;
    }

    public ZMSubscriber getNegativeClickEvent() {
        return negativeClickEvent;
    }

    /**
     * 单选对话框的话,需要用这个
     *
     * @param negativeClickEvent
     * @return
     */
    public Builder setNegativeClickEvent(ZMSubscriber negativeClickEvent) {
        this.negativeClickEvent = negativeClickEvent;
        return this;
    }

    public boolean isCancelable() {
        return cancelable;
    }

    public Builder setCancelable(boolean cancelable) {
        this.cancelable = cancelable;
        return this;
    }

    public ZMDialog builder() {
        return new ZMDialog(this);
    }
}

private ZMDialog(final Builder zmDialogBuilder) {
    MaterialDialog.Builder materialBuilder = new MaterialDialog.Builder(zmDialogBuilder.getContext());
    materialBuilder.canceledOnTouchOutside(zmDialogBuilder.isCancelable())
            .title(zmDialogBuilder.getTitle())
            .content(zmDialogBuilder.getMessage())
            .positiveText(zmDialogBuilder.getPositiveMessage())
            .negativeText(zmDialogBuilder.getNegativeMessage())
            .onPositive(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                    zmDialogBuilder.getPositiveClickEvent().onNext(null);
                }
            })
            .onNegative(new MaterialDialog.SingleButtonCallback() {
                @Override
                public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                    zmDialogBuilder.getNegativeClickEvent().onNext(null);
                }
            })
            .build()
            .show();
 }
} 

参考自 Effective java 第二版

优点

  • 可选项参数采用了链式引入,代码优雅
  • 避免了构造方法传参不便于维护的缺陷

4.第三方的封装

代码如下

@Override
public void dealWithCustomAction(Context context, UMessage uMessage) {
    super.dealWithCustomAction(context, uMessage);

    PushMessage pushMessage = new PushMessage();
    ......//此处为公司机密        PushMessageDispatcher.getInstance().onClick(context, pushMessage);
}

参考自 朋友交流经验,朋友参考自哪里,就不知道了

优点

  • umeng收到消息后,并不直接处理,而是将消息直接推出到处理的地方,这样可以避免,更换其他推送渠道时的代码逻辑的更改
  • 用第三方的sdk时,要注意,不要在和第三方直接相关的类中处理,这样能避免更换第三方库时的逻辑重构

5.Intent、Bundle传递数据

代码如下

public class BusActivity extends BaseActivityWithToolBar   {

 private static final String KEY_TASK_ID = "TASK_ID";

 public static Intent getCallingIntent(Context context, String taskId) {
    Intent intent = new Intent();
    intent.putExtra(KEY_TASK_ID, taskId);
    intent.setClass(context, BusActivity.class);
    return intent;
 }
}

参考自idea自动生成的fragment代码,第三方开源项目(具体哪个项目忘了,不好意思)

  • intent中的key存放在服务端,客户端只关心传递的数据,降低key的耦合
  • 不再需要客户端与服务端约定key了
  • intent,bundle,map等传递数据,都可以用这种方式
  • 用了静态方法,增加内存的消耗,但,这带来了代码的简洁性和可程序的维护性,内存的牺牲是值得的

6.跳转统一管理

代码如下

 public class Navigator {

  /**
   * 跳转登陆页
   *
   * @param context
   */
    public void navigateToLogin(@NonNull Context context) {
     Intent intent = LoginActivity.getCallingIntent(context);
     context.startActivity(intent);
     }

}

参考自我任职的公司项目源码

  • Navigator必须是单例的
  • 方便管理跳转,这样客户端编写代码的时候,只要在Navigator中找对应的方法就可以了,不用漫山遍野的去找项目工程中对应的服务端文件,也没必要从繁杂的服务端文件中,找寻跳转方法
  • Navigator的引入,屏蔽了服务端的代码细节,符合面向对象的封装特性

7.android原生注解

几个常用的原生注解

参考网址 https://developer.android.com/studio/write/annotations.html

  • @Nullable Can be null.
  • @NonNull Cannot be null.
  • @StringRes References a R.string resource.
  • @DrawableRes References a Drawable resource.
  • @ColorRes References a Color resource.
  • @InterpolatorRes References a Interpolator resource.
  • @AnyRes References any type of R. resource.

  • 代码中使用这些,可以规范方法入参,问题出在编译阶段,减少运行时的异常

  • 代码量少,减少一些不必要的显示判断,代码优雅可读

8.关于6.0系统的权限适配

代码如下

权限检查

 public class PermissionHelper {

/**
 * 检查App是否有定位权限
 *
 * @param activity
 * @return true ,已授权,false,未授权
 */
public static boolean checkLocationPermission(Activity activity) {
    if (Build.VERSION.SDK_INT >= PERMISSION_LIMIT) {
        return PermissionUtils.checkGroupPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION});
    } else {
        return true;
    }
  }
}

fragment中权限请求

 public class MissionFragment extends BaseFragment {

      /**
       * fragment中权限请求方法
       */
         requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE);



      /**
       * 权限请求回调方法
       */
 @Override
           public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (locationPermissionGranted(requestCode, permissions, grantResults)) {
        navigateToMissionDetail();
    }
   }
  }

参考自

  • fragment中发出请求,在fragment中自己接收,不需要借助activity中转
  • 高内聚

9.枚举

代码如下

枚举定义

`

/**
 * 支付界面入口标示
 */
 public enum PaymentEntrance {
/**
 * 巴士车票
 */
BUS_TICKET,

/**
 * 定制巴士
 */
ZOUME_BUS,

/**
 * 当前行程:列表
 */
TRIPS_LIST,

/**
 * 当前行程:详情
 */
TRIP_DETAIL
}

`

枚举使用(服务端)

`

/**
 * 获取携带过来的数据
 * 用以初始化界面以及发送网络请求
 */
private void handleExtraParam() {
    Bundle bundle = getArguments();
    if (bundle != null && bundle.containsKey(EXTRA_PAYMENT_ENTEANCE)) {
        paymentEntrance = (PaymentEntrance) bundle.getSerializable(EXTRA_PAYMENT_ENTEANCE);
        paymentInfo = bundle.getSerializable(EXTRA_PAYMENT_INFO);

        switch (paymentEntrance) {
            case BUS_TICKET:
                refreshUI((ZMBusTicketOrder) paymentInfo);
                break;

            case ZOUME_BUS:
                refreshUI((ZouMeBusOrderParam) paymentInfo);
                break;

            case TRIPS_LIST:
            case TRIP_DETAIL:
                refreshUI((TripOrder) paymentInfo);
                break;
        }
    }
}

`

参考自 android编程实战(第二版)、effectivejava

  • 限定了入参范围(枚举规定了多少,就只能使用多少),减少客户端出错的概率
  • 比谜之数字可读性更高
  • 枚举型入参就是文档

10.位标记代替多个boolean变量

代码如下

`

private static int SELECT_STATE = 0;
private static final int TOGGLE_START_OR = 8;
private static final int TOGGLE_START_AND = 7;
private static final int TOGGLE_DESTINATION_OR = 4;
private static final int TOGGLE_DESTINATION_AND = 11;
private static final int TOGGLE_LINER_OR = 2;
private static final int TOGGLE_LINER_AND = 13;
private static final int TOGGLE_PASSENGER_OR = 1;
private static final int TOGGLE_PASSENGER_AND = 14;
public static final int CODE_SELECT_START = 1;
public static final int CODE_SELECT_DESTINATION = 2;
public static final int CODE_KEY_SOURCE_SEARCH = 5;
public static final int CODE_ADD_PASSENGER = 4;


//标志位变换控制方法
 SELECT_STATE = SELECT_STATE & TOGGLE_START_AND;
 SELECT_STATE = SELECT_STATE & TOGGLE_DESTINATION_AND;

`

参考自 android源码ApplicationInfo中标志位使用、自己总结

  • 如果在一个文件中,控制的标志位过多,而且标志位相互独立,采用boolean型变量将会使判断逻辑相当繁琐,使用int进行位运算,则会清爽很多
  • 位运算,控制过程并不会比boolean型变量麻烦太多

11.范型

代码如下

`

public interface HasComponent<C> {
C getComponent();
}

`

参考自 effective Java,自己项目源码

  • 抽象编程,有据可依(此例中,范型声明与返回值一致)
  • 编写程序时执行类型检查,让错误出现在编译阶段
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值