Android开发-FSS开源框架(集绑定,路由,运行优先级,适配器等)

fss

FSS框架是为了更快速,更简单,更规范进行Android开发,他包含多个子模块,开发者可根据需要引入自己需要的依赖包即可。
gitHub地址:https://github.com/gongbox/fss

  • fss-bind
    绑定框架,实现了多种绑定,大大减少Activity/Fragment代码
  • fss-router
    路由框架,更简洁地进行路由,方便进行路由管理
  • fss-adapter
    适配器,提供ListView以及RecyclerView的多种适配器,简化适配器开发
  • fss-runpriority
    运行优先级,使用它可以实现在自类中自定义调用顺序

fss-bind

绑定框架,使用它可以实现Activity或Fragment的绑定,比如layout绑定,finish方法绑定,View或点击事件绑定,参数绑定,参数绑定到databinding变量等等

  • 用法1:绑定布局文件(Activity,Fragmeng等)
 @BindActivity(R.layout.activity_bind_test)
 public class BindTestActivity extends BaseFssActivity {
 }

另外,BindActivity可以绑定退出按钮,如下:

 @BindActivity(value = R.layout.activity_bind_test, finishViewId = R.id.btn_finish)
 public class BindTestActivity extends BaseFssActivity {
 }

这样就可以在点击id为btn_finish的控件时直接调用finish方法,退出Activity

  • 用法2:绑定视图
 public class BindTestActivity extends BaseFssActivity {
     @BindView(R.id.list_view)
     private ListView listView;  //支持绑定所有类型的视图
 }
  • 用法3:绑定点击事件
 public class BindTestActivity extends BaseFssActivity {
     @BindOnClick(R.id.btn_click)
     private void click() {
         ...
     }
     //或者
     @BindOnClick(R.id.btn_click)
     private void click(View view) {
         ...
     }
     //或者
     @BindOnClick(R.id.btn_click)
     private void click(Button button) {
         ...
     }
 }

或者可以声明写在类上

 @BindOnClick(value = R.id.btn_test, onClickMethod = "test")
 public class BindTestActivity extends BaseFssActivity {
  //方法可以无参或者有一个该控件类型或父类型的参数,如private void test(Button button){},或private void click(View view){}
  private void test(){
     ...
  }
 }
  • 用法4:绑定路由
 //当用户点击id为btn_route的控件时,便可以直接跳转到BindDetailActivity页面(支持携带参数,这里先不介绍)
 @BindRoute(viewId = R.id.btn_route, toActivity = BindDetailActivity.class)  
 public class BindTestActivity extends BaseFssActivity {
 }
  • 用法5: 绑定参数(支持Activity或Fragmeng)
 public class BindTestActivity extends BaseFssActivity {
     @BindExtra(value = "value")//key值与变量名相同时可以省略为@BindExtra
     private Integer value;
 }
  • 用法6:绑定databinding变量
 public class BindTestActivity extends BaseFssActivity {
     //BindExtra除了会将A页面传过来的参数绑定到value变量上,也会将该变量绑定到布局文件中databinding变量名value的变量中
     @BindExtra(id = BR.value) 
     private String value;
 }

如果你不需要使用value变量的话,你也可以这么写,效果同上

 @BindExtra(value = "value", id = BR.value) 
 public class BindTestActivity extends BaseFssActivity {
 }

看到这儿,如果你觉得也没多简洁的话,那我们接下来看看实际使用中的几个例子。

然后我们看一个比较完整的例子:

  • 例子
//绑定layout,并且将视图中id为R.id.img_back的点击事件绑定到finish方法,如果是Fragment,注解需要改为BindFragment,并且没有finish参数
@BindActivity(value = R.layout.activity_a, finishViewId = R.id.img_back)
//绑定Route,当用户点击id为R.id.to_activity_b的view后,会跳转到ActivityB
@BindRoute(viewId = R.id.to_activity_b, toActivity = ActivityB.class)
//绑定Route,当用户点击id为R.id.to_activity_c的view后,会跳转到ActivityC,并会传递参数,参数key值为EXTRA_VALUE2,携带参数为"value":value变量值,"value2":"789","value3":[234](这里为int类型数组)
@BindRoute(viewId = R.id.to_activity_c,toActivity = ActivityC.class,
        extras = {":@value", "value2:789", "value3:(int)[234]"}
)
//绑定intent参数到databinding变量
@BindExtra(value = "EXTRA_VALUE4",  id = BR.value4)
//绑定点击事件,将id为R.id.test的view的点击事件绑定到test方法上,要求该方法没有参数或只有一个View类型的参数
@BindOnClick(value = {R.id.test}, onClickMethod = "test")
public class ActivityA extends BaseBindingActivity<ActivityABinding> {
    
    //绑定intent参数,将key值为EXTRA_VALUE的参数绑定达到value变量
    @BindExtra(value = "EXTRA_VALUE")
    private Integer value;
    
    //绑定intent参数,和上面的BindParam不同的时,除了会将变量绑定外,在使用databinding的情况下,还会将该变量值直接绑定到databinding变量
    //另外,该注解可以直接写到类上面,因为有的时候我只需要将intent传递过来的参数绑定到databinding中,而我并不关心它的值
    @BindExtra(value = "EXTRA_VALUE3",  id = BR.value3)
    private String value3;
    
    //路由参数,用于绑定路由时传递参数
    private String value2 = "123456";
    
    //绑定视图
    @BindView(value = R.id.list_view)
    private ListView listView;

    //绑定点击事件,将id为R.id.img_fun1的view的点击事件绑定到opertation方法上,注意该方法没有参数
    @BindOnClick(R.id.img_fun1)
    public void opertation() {
    }
    
    //绑定点击事件,将id为R.id.img_fun2,R.id.img_fun3的view的点击事件绑定到opertation方法上
    //注意该方法有一个参数View,该参数即为对应触发点击事件对的view
    @BindOnClick({R.id.img_fun2,R.id.img_fun3})
    public void opertation(View view) {
    }
    
    private void test(){
    }
}

以上是fss-bind的部分介绍,若想详细了解,请参考Android开发利器-FSS开源框架之绑定

fss-router

背景

在Android开发中,如果要从当前Activity跳转到下一个Activity,你可能会直接使用Intent的方式跳转,如下:

Intent intent = new Intent(this,XXXActivity.class);
intent.putExtra("name","value");  //传递参数
startActivity(intent);

或者你也可能使用阿里的ARouter路由框架,如下:

ARouter.getInstance().build("/xxx/xxx")
                    .withString("name","value")   //传递参数
                    .navigation(XXXActivity.class);

不管使用哪种方式,你都会发现如下问题:
1,路由要携带的参数有哪些?各个参数的key值是什么?哪些参数是必传?这些参数是什么意思...
2,对应的Activity是显示启动还是隐式启动,如果是隐式启动对应的action是什么,如果有requestCode,category,flags又该设置为多少
3,无法统一管理路由,到处可见的Intent与startActivity等等,路由方式很随意,哪里想跳就在哪儿写,想传什么参数就传什么。
4,代码量多,传的参数越多,要跳转的地方越多,代码量也就越多。

在这种背景下,笔者便有了灵感,写出了FssRouter路由框架,我们看看FssRouter是怎么解决这些问题的。

使用

我们先看一下使用自定义路由API的方式,使用这种方式需要声明一个接口,在接口中声明路由信息。
现在假设我们有两个Activity,分别是MainActivity,DetailActivity,
现在的代码是这样:

public class MainActivity extends AppCompatActivity {
    ...
}
public class DetailActivity extends AppCompatActivity {
    ...
}

然后我们声明一个java接口,接口名随意,这里为ITestRouteApi

@RouteApi("test") //定义为路由Api,“test”为这个路由api的分组
public interface ITestRouteApi {
  @RouteActivity(DetailActivity.class) //定义路由的目的Activity
  void navigateToDetailActivity(Context context); //第一个参数必须为Context类型
}

声明上面的接口api后,然后再编译项目,然后我们就可以使用如下的方式进行路由了。

public class MainActivity extends AppCompatActivity {
   ...
   void xxx(){
     //使用下面的方式进行路由
     FssRouteApi.TEST.navigateToDetailActivity(MainActivity.this);
   }
}

上面是一个简单的例子,我们在看看其他情况。

1,隐式意图启动

@RouteApi("test") //定义为路由Api,“test”为这个路由api的分组
public interface ITestRouteApi {
  @RouteActivity(action = "com.gongbo.fss.route.detail")
  void navigateToDetailActivity(Context context);
}

2,携带路由参数

@RouteApi("test") //定义为路由Api,“test”为这个路由api的分组
public interface ITestRouteApi {
  @RouteActivity(action = "com.gongbo.fss.route.detail")
  void navigateToDetailActivity(Context context, @Extra("value") int value); 
}

3,携带默认路由参数

@RouteApi("test") //定义为路由Api,“test”为这个路由api的分组
public interface ITestRouteApi {
  @RouteActivity(DetailActivity.class)
  @DefaultExtra(
      name = "defaultValue",
      defaultValue = "hello",
      type = String.class
  )
  void navigateToDetailActivity(Context context);
}

4,设置requestCode,category,flags,路由动画等

@RouteApi("test") //定义为路由Api,“test”为这个路由api的分组
public interface ITestRouteApi {
  @RouteActivity(
            value = DetailActivity.class,             //设置路由的目标Activity
            requestCode = 1234,                       //设置requestCode
            category = Intent.CATEGORY_DEFAULT,       //设置category
            flags = Intent.FLAG_ACTIVITY_CLEAR_TASK,  //设置falgs
            enterAnim = android.R.anim.fade_in,       //设置activity进入动画
            exitAnim = android.R.anim.fade_out        //设置activity退出动画
  )
  void navigateToDetailActivity(Context context);
}

5,携带Uri,设置type等

@RouteApi("test") //定义为路由Api,“test”为这个路由api的分组
public interface ITestRouteApi {
  @RouteActivity(action = Intent.ACTION_VIEW)
  void routeToView(Context context, Uri data);

  @RouteActivity(
            action = Intent.ACTION_GET_CONTENT,
            requestCode = 2,
            category = Intent.CATEGORY_OPENABLE,
            type = "video/*")
  void navigateToGetContent(Context context);
}

自动创建Api

上面展示了如何自定义一个路由Api,并如何进行路由。接下来我们看一种更简单的方式实现路由。
我们在的DetailActivity上声明一个注解@Route,编译项目

@Route
public class DetailActivity extends AppCompatActivity {
    ...
}

然后我们在MainActivity中便可以直接这样来跳转到DetailActivity了

public class MainActivity extends AppCompatActivity {
   ...
   void xxx(){
     //使用下面的方式进行路由
     FssRouteApi.DEFAULT.navigateToDetailActivity(MainActivity.this);
   }
}

这是因为在编译时,FssRouter会帮我们自动生成对应的路由Api,如下:


图片.png

IDefaultRouteApi.java文件的具体内容如下:

public interface IDefaultRouteApi {
  @RouteActivity(DetailActivity.class)
  void navigateToDetailActivity(Context context);
}

因此,使用@Route注解便可以帮我们自动生成路由Api,这使得我们不必自定义路由API便可以实现路由,这种方式相对更简单,使用@Route注解,你几乎可以完成上面自定义Api的所有工作。笔者也更推荐使用这种方式,以上介绍了部分fss路由框架,若想了解更多,请参考Android开发利器-FSS开源框架路由

fss-adapter

fss-adapter提供了多种适配器用法,内容较多,本文只介绍CommonAdapter
1,使用 CommonAdapter

CommonAdapter adapter = new CommonAdapter<String>(this, Arrays.asList("1", "2", "3"), R.layout.layout_list_item) {
            @Override
            protected void setView(CommonViewHolder holder, String str, int position) {
                TextView textView = holder.getView(R.id.tv_text);
                textView.setText(str);
                //可以用holder.setText(R.id.tv_text, str);代替
            }
        };

相对来说使用fss-adapter大大简化了适配器开发,如果想了解更多,请参考Android开发利器-FSS开源框架之ListView,RecyclerView适配器

fss-runpriority

背景

在Android开发中,Activity或Fragment中经常会用initView,initListener,initData三个方法来初始化,那么你可能会将这三个方法声明在父类中,然后子类继承实现即可,如下:

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ...
      initView();
      initData();
      initListener();
  }

  protected void initView() {
  }

  protected void initData() {
  }

  protected void initListener() {
  }

但如果这样做,initView,initData,initListener这三个方法的执行顺序固定了,然而有的时候我并不想以initView,initData,initListener 这样的顺序来执行,而是initView,initListener,initData或者其他顺序执行。fss_runpriority的出现便是为了解决这个问题。
然后在父类注册需要调用的方法:

//构造运行优先级方法
RunPriorityInfo runPriorityInfo = new RunPriorityInfo.Builder(this)
                .addMethod("initView") //对应方法:initView()
                //可以传任意个参数,但是要求必须存在该方法
                //.addMethod("initData", 12) 对应方法:initData(int xxx);
                //.addMethod("initData", 15L,"hello") 对应方法:initData(long xxx,String xxx);
                .addMethod("initData")
                .addMethod("initListener")
                .build();
//调用运行优先级方法,默认调用顺序为:initView() -> initData() -> initListener(),子类可使用@RunPriority注解自定义调用顺序
RunPriorityUtils.call(runPriorityInfo);

下面看一个Android的Activity的例子

class BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        //构造运行优先级方法
        RunPriorityInfo runPriorityInfo = new RunPriorityInfo.Builder(this)
                .addMethod("initView")
                .addMethod("initData")
                .addMethod("initListener")
                .build();
        //调用运行优先级方法,默认调用顺序为:initView() -> initData() -> initListener(),子类可使用@RunPriority注解自定义调用顺序
        RunPriorityUtils.call(runPriorityInfo);
    }
    
    protected void initView() {
    }

    protected void initData() {
    }

    protected void initListener() {
    }
}

然后子类就可以根据需要自定义优先级,如下:

class TestActivity extends BaseActivity {
    //声明为高优先级,会优先调用
    @RunPriority(Priority.HIGH)
    @Override
    protected void initView() {
        super.initView();
        Log.i("RunPriority", "initView");
    }

    //声明为低优先级,会最后调用
    @RunPriority(Priority.LOW)
    @Override
    protected void initData() {
        super.initData();
        Log.i("RunPriority", "initData");
    }

    //声明为普通优先级,这也是默认的优先级,因此也可以不写
    //@RunPriority(Priority.NORMAL)  
    @Override
    protected void initListener() {
        super.initListener();
        Log.i("RunPriority", "initListener");
    }
}

上面的代码执行顺序是initView>initListener>initData。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351