Android

Android全能拦截器Interceptor

2017-01-02  本文已影响2524人  Android绝世小菜鸟

一.概述

Interceptor拦截器,当我们在做一个项目的时候,会有很多需要重新使用的方法或者功能,当然,我们一般做的是封装,或者在基类里面实现,然后子类基础,就避免了很多重复的操作,但是有时候,这些也不是很简便,还是需要做一些额外的代码操作,例如,登录失效,需要跳到登录页面重新登录的时候,有很多页面都有这个需求,一个个的去实现,又太麻烦,增添很多不必要的代码,还有当项目很多页面需要定位功能的时候,又得重复的写,像这种需求的时候,我们就可以用到拦截器了,基于Java注解的形式来使用。

先看两个人逛窑子
第一个带了杜蕾斯的

GIF.gif

第2个没带杜蕾斯的

GIF.gif

二.基类的定义和思想

  1. BaseApplication
/**
 * Created by asus on 2017/1/1.
 * Application基类,子类添加自己的拦截器
 */

public abstract class BaseApplication extends Application {
    private static Interceptors interceptors = new Interceptors();
    @Override
    public void onCreate() {
        super.onCreate();
        configInterceptor(interceptors);
    }

    public static final Interceptors getInterceptors() {
        return interceptors;
    }
    //子类实现的方法,添加自己的拦截器数组
    public abstract void configInterceptor(Interceptors interceptors);
}

2.BaseActivity

public class BaseActivity extends AppCompatActivity implements IVew {
    BaseApplication application;
    //子类实现禁止onCreate方法
    @Override
    protected final void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        application = (BaseApplication) getApplication();
        onInitView(savedInstanceState);
    }

    //禁止子类的onResume方法 并配置拦截器
    @Override
    protected final void onResume() {
        super.onResume();
        Interceptor[] globalInters = InterceptorBuilder.NULL_INTERS;
        Interceptors interceptors = application.getInterceptors();//获取拦截器集合
        if (interceptors != null) {
            globalInters = interceptors.getInterceptorArray();
        }
        Interceptor[] finalInters = InterceptorBuilder.build(globalInters, getClass());


        new Invocation(this, finalInters).invoke();
    }

    //子类获取对象
    @Override
    public Activity getViewActivity() {
        return this;
    }
    //设置主题
    @Override
    public void setWindowTheme() {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }
    @Override
    public void onInitView(Bundle savedInstanceState) {

    }
    @Override
    public void resume() {

    }
}

3.VIew接口,便于实现一些操作,例如禁止子类的onCreate等方法,使用接口的方法

/**
 * Created by asus on 2017/1/1.
 *
 * 为了方便其他地方的调用采用接口的形式
 */

public interface IVew {

    //获取子类的对象
    Activity getViewActivity();

    //设置窗口样式  会在onCreate之前调用
    void setWindowTheme();

     //初始化控件;子类不能重写onCreate
    void onInitView(Bundle savedInstanceState);

    //视图可见;子类不能重写onResume
    void resume();
}

4.每一个应用的拦截器数组

final public class Interceptors {

    private final List<Interceptor> globalActionInterceptor = new ArrayList<>();
      //添加一个初始化全局拦截器(例如定位,登录等,可以初始化全局)
    public Interceptors add(Interceptor globalInterceptor) {
        if (globalInterceptor != null)
            this.globalActionInterceptor.add(globalInterceptor);
        return this;
    }
    //获取当前应用所有的拦截器
    public Interceptor[] getInterceptorArray() {
        Interceptor[] result = globalActionInterceptor.toArray(new Interceptor[globalActionInterceptor.size()]);
        return result == null ? new Interceptor[0] : result;
    }
}

三.拦截器的定义

1.定义一个拦截器接口Interceptor

public interface Interceptor {
//并传入一个拦截器的拦截方法,做一些拦截判断操作
    void intercept(Invocation invocation);
}

2.拦截器调度Invocation

/**
 * 拦截器调度
 * Created by asus on 2017/1/1.
 */

public class Invocation {
    private IVew view;
    private Interceptor[] inters;
    private int index = 0;

    public Invocation(IVew view, Interceptor[] interceptors) {
        this.view = view;
        this.inters = interceptors;
    }

    public void invoke(){
          //如果拦截器数组有值,则回调当前拦截器的操作
        if(index<inters.length){
            inters[index++].intercept(this);
//当当前拦截器执行完之后,又调用invoke方法,执行下一个拦截器,如果还有下一个拦截器,  
//继续执行intercept,否则才去回调当前activity的resume方法
        }else if(index++==inters.length){
            view.resume();
        }
    }
    public IVew getView() {
        return view;
    }
}

3.定义自己的拦截器(我这里是伪代码登录拦截器)

public class LoginInterceptor implements Interceptor {

    @Override
    public void intercept(Invocation inv) {
        Activity viewActivity = inv.getView().getViewActivity();
        //如果登录了继续回调到invoke中执行下一个拦截器
        if(MyApplication.isLoaded()){//执行自己的操作判断,我这里是判断伪代码是否登录
            inv.invoke();
        }else{//如果没有登录就跳转到登录页面,finish当前Activity
            Intent intent = new Intent(viewActivity, LoginActivity.class);
            viewActivity.startActivity(intent);
            viewActivity.finish();
        }
    }
}

四.拦截器的使用

1.自定义注释,来构造一个拦截器,当类执行的时候,会执行到BaseActivity的onResume方法中还记得上面的onResume吗

 //禁止子类的onResume方法
    @Override
    protected final void onResume() {
        super.onResume();
        //先定义一个长度为0的数组,避免全局数组为null
        Interceptor[] globalInters = InterceptorBuilder.NULL_INTERS;
        //获取全局的拦截器集合
        Interceptors interceptors = application.getInterceptors();
        if (interceptors != null) {
            globalInters = interceptors.getInterceptorArray();
        }
        //构造所有的拦截器(包括全局的当前Activity中的注释拦截器)
        Interceptor[] finalInters = InterceptorBuilder.build(globalInters, getClass());

        new Invocation(this, finalInters).invoke();//执行全局和当前类的拦截器
    }

2.拦截器的构造(通过类注释的方法来构造,当然也可以通过获取类的方法,这样比较直观,直接在类上面来定义)

public class InterceptorBuilder {
  public static final Interceptor[] NULL_INTERS = new Interceptor[0];

  private static Map<Class<? extends Interceptor>, Interceptor> intersMap = new HashMap<>();

  /**
   * 构建 Interceptors.
   * finalInters = globalInters + classInters
   */
  public static Interceptor[] build(Interceptor[] globalInters, Class<?> targetClass) {
      //1.存入全局的拦截器,添加到Map集合中
      for (Interceptor inter : globalInters)
          intersMap.put(inter.getClass(), inter);

      //2.获取Before注释的拦截器,如果有添加到Map集合中
      Interceptor[] classInters = createInterceptors(targetClass.getAnnotation(Before.class));

      // 3.判断是否有Clear注释
      Clear clear = targetClass.getAnnotation(Clear.class);

          //① 如果为null,就说明没有Clear ,直接将全局和Before构造成一个新的拦截器数组
      if (clear == null) {
          Interceptor[] result = new Interceptor[globalInters.length + classInters.length];
          int index = 0;
          for (Interceptor inter : globalInters)
              result[index++] = inter;
          for (Interceptor inter : classInters)
              result[index++] = inter;
          return result;
      }


      Class<? extends Interceptor>[] clearInters = clear.value();

           // ② 有Clear拦截器的标志,但是后面没有拦截器参数,意味着清楚所有其他的全局拦截器
             // (全局拦截器有很多,当不需要时,clear标志清除),只保留当前类Before拦截器
      if (clearInters.length == 0)
          return classInters;

          // ③ 有Clear拦截器的标志,后面也有Clear拦截器 则删除Map中Clear指定的拦截器,返回
      Interceptor[] temp = new Interceptor[globalInters.length + classInters.length];
      int index = 0;
      for (Interceptor inter : globalInters)
          temp[index++] = inter;
      for (Interceptor inter : classInters)
          temp[index++] = inter;

      int removeCount = 0;
      for (int i=0; i<temp.length; i++) {
          for (Class<? extends Interceptor> ci : clearInters) {
              if (temp[i].getClass() == ci) {//如果全局和当前类中有Clear标志的拦截器,置为null
                  temp[i] = null;
                  removeCount++;
                  break;
              }
          }
      }

      Interceptor[] result = new Interceptor[temp.length  - removeCount];//创建一个新的所有的拦截器数组,进行返回
      index = 0;
      for (Interceptor inter : temp)
          if (inter != null)
              result[index++] = inter;
      return result;
  }

  private static Interceptor[] createInterceptors(Before beforeAnnotation) {
      //为before为null,返回长度为0的数组
      if (beforeAnnotation == null)
          return NULL_INTERS;

      Class<? extends Interceptor>[] interceptorClasses = beforeAnnotation.value();
      //before注释后面没有拦截器的时候,返回长度为0的数组
      if (interceptorClasses.length == 0)
          return NULL_INTERS;


      //如果Map集合,全局拦截器没有该类上面的拦截器,就加入Map集合
      Interceptor[] result = new Interceptor[interceptorClasses.length];
      try {
          for (int i=0; i<result.length; i++) {
              result[i] = intersMap.get(interceptorClasses[i]);
              if (result[i] == null) {
                  result[i] = (Interceptor)interceptorClasses[i].newInstance();
                  intersMap.put(interceptorClasses[i], result[i]);
              }
          }
      } catch (Exception e) {
          throw new RuntimeException(e);
      }
      return result;
  }
}

3.自定义注释(Before和Clear接口,写在一起了)

@Inherited //可继承
@Retention(RetentionPolicy.RUNTIME)//保留的时间
@Target({ElementType.TYPE, ElementType.METHOD})//作用范围,类,接口方法等
public @interface Before {
    Class<? extends Interceptor>[] value();
}

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Clear {
    Class<? extends Interceptor>[] value() default {};
}

五.简单例子来体现拦截器的好处

假如我们要去大保健(相当于我们项目中的操作,需要查看我卡里还有多少钱,但是你必须登录才可以查看),大保健需要杜蕾斯,如果不使用拦截器,你每次去一次大保健,都要去买一次杜蕾斯,很麻烦,而你使用了拦截器的话,就相当于你在口袋里面已经装好了杜蕾斯,只需要大保健的时候拿出来就ok,这样就方便了很多。接下来就是大保健的实战。。。

1.MainActivity,点击按钮,去大保健,首先必须使用Clear,清除掉,(因为在全局默认配置了拦截器),否则也会拦截掉,就会一直卡着,因为我都还没准备去呢,你就给我拦截

@Clear(LoginInterceptor.class)
public class MainActivity extends BaseActivity implements View.OnClickListener {

    @Override
    public void onInitView(Bundle savedInstanceState) {
        super.onInitView(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bt_has_login = (Button) findViewById(R.id.bt_has_login);
        Button bt_no_login = (Button) findViewById(R.id.bt_no_login);
        bt_has_login.setOnClickListener(this);
        bt_no_login.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
          //设置一个变量来处理事件,例如你的登录Token,用于判断Token有没有失效,失效则去登录
        if (view.getId() == R.id.bt_has_login) {
            MyApplication.setLoaded(true);//我有杜蕾斯
        } else if (view.getId() == R.id.bt_no_login) {
            MyApplication.setLoaded(false);//我没有杜蕾斯
        }
        go_yaozi();
    }

    //大保健
    private void go_yaozi() {
        Intent intent = new Intent(MainActivity.this, BeautifulGirlActivity.class);
        startActivity(intent);
    }
}

2.窑子来了

//在进窑子之前,判断是否有杜蕾斯,这里就会走入LoginInterceptor中
@Before(LoginInterceptor.class)
public class BeautifulGirlActivity extends BaseActivity {
    @Override
    public void onInitView(Bundle savedInstanceState) {
        super.onInitView(savedInstanceState);
        setContentView(R.layout.activity_girl);
    }
}

我们再来看看LoginInterceptor中的处理

public class LoginInterceptor implements Interceptor {

    @Override
    public void intercept(Invocation inv) {
        Activity viewActivity = inv.getView().getViewActivity();
        if(MyApplication.isLoaded()){//如果已经有杜蕾斯了,就去继续执行下一步
            inv.invoke();
        }else{//否则,回去拿杜蕾斯
            Intent intent = new Intent(viewActivity, LoginActivity.class);
            viewActivity.startActivity(intent);
            viewActivity.finish();
        }
    }
}

逛窑子逛到这里就逛完了,使用起来非常方便,当一个项目有很多地方都需要用到的时候,就可以采用这种逛窑子的方式来处理,想再逛一次窑子的可以上去重新看下逛窑子的gif图。

上一篇 下一篇

猜你喜欢

热点阅读