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,如下:
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。