FSS框架--让Android代码更简洁

        fss框架目的是为了更快速,更简洁,更规范地开发Android。它包括以下几个模块,开发者可以根据需要添加模块。

        fss_common:     提供了java8常用的接口,可选类型,kotlin元组,stream工具类,常用的工具函数等。

        fss_run_priority: 使用它可以实现子类根据优先级调用继承的方法。

        fss_bind:            使用它可以实现Activity或Fragment的绑定,比如layout绑定,finish方法绑定, View/OnClick绑定(类似ButterKnife),参数绑定,参数绑定到databinding变量,view绑定到intent对象等等。  

        fss_adapter:        使用它可以使得ListView,RecyclerView的适配器开发更简单。 

        GitHub地址:

                      https://github.com/gongbox/fss_common

                      https://github.com/gongbox/fss_run_priority

                      https://github.com/gongbox/fss_bind 

                      https://github.com/gongbox/fss_adapter

                      https://github.com/gongbox/fss_all

                      使用androidx:

                      https://github.com/gongbox/fss_bind_androidx

                      https://github.com/gongbox/fss_adapter_androidx

                      https://github.com/gongbox/fss_all_androidx

        使用例子:

                       https://github.com/gongbox/fss_demo

                       https://github.com/gongbox/fss_demo_androidx

接下来我们看一下fss框架各个模块的作用。

fss_common:

  先看看fss_common提供的stream工具类:

Integer[] array = streamOf("1", "7", "2", "3")  //构造一个stream对象
                .add("4")                       //添加一个元素
                .addAll("5", "6")               //添加多个元素
                //注意使用了lambda表达式,不懂得同学自行百度
                .consume(datas -> System.out.println("------------------------------------------------------"))
                .forEach(System.out::println)   //遍历打印每个元素
                .map(Integer::parseInt)         //将所有元素转为Integer类型
                .consume(datas -> System.out.println("------------------------------------------------------"))
                .forEach(System.out::println)   //遍历打印每个元素
                .filter(value -> value > 1)     //过滤小于等于1的元素
                .consume(datas -> System.out.println("------------------------------------------------------"))
                .forEach(System.out::println)   //遍历打印每个元素
                .sort(Integer::compareTo)       //排序
                .consume(datas -> System.out.println("------------------------------------------------------"))
                .forEach(System.out::println)   //遍历打印每个元素
                .toArray(Integer.class);        //转化为Integer[]类型

       上面是一个简单使用stream的例子,当然stream所包含的功能还不至于此,它还提供了max,min,removeIf,find,any等常用的功能, 因此使用stream操作集合或数组十分的方便。stream适合于需要对数据作多个处理的情况下,若是只需要过滤,转换,排序等操作,可以使用common工具函数。 下面将介绍common工具函数:

//可以是数组或集合类型
String[] datas = new String[]{"1", "7", "2", "3"};
//将所有元素转为Integer类型
List<Integer> ints = common.map(datas, Integer::parseInt);
//过滤小于等于1的元素
ints = common.filter(ints, value -> value > 1);
//排序
common.sort(ints, Integer::compareTo);

       common工具类包含了常用的对集合/数组操作的常用方法,笔者简单介绍了几个例子,如果有兴趣,大家自己再去研究下,我这里不过多写了。

       除了上面的stream,common外,fss_common还提供了java8常用的接口类,kotlin元组等功能。这些在开发中经常用到,请大 家自行了解。

fss_run_priority:

       背景:在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_run_priority的出现便解决了这个问题。

例子:

       首先需要在父类上调用 RunPriorityUtils的callAll函数注册需要子类调用的方法,如下:

  RunPriorityUtils.callAll(this, "methodName1", "methodName2", "methodName3");

      其中methodName1,methodName2,methodName3为子类需要实现的方法的方法名,注意该方法必须是无参的。另外说明一下,方法的注册顺序也是默认的方法执行顺序, 即在方法优先级相同的情况下,会先调用methodName1,然后再调用methodName2... 下面看一个Android的Activity的例子

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        //注册方法,默认情况下会先调用initView,然后调用initListener,最后调用initData
        RunPriorityUtils.callAll(this, "initView", "initListener", "initData");  
    }

    protected void initView() {
    }

    protected void initData() {
    }

    protected void initListener() {
    }

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

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

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

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

         上面的代码执行后。执行顺序是先initView,然后initListener,最后initData。

fss_bind:

        使用它可以实现Activity或Fragment的绑定,比如layout绑定,finish方法绑定, View/OnClick绑定(类似ButterKnife),参数绑定,参数绑定到databinding变量,view绑定到intent对象等等。

例子:

        一般Android项目中会有一个Activity或Fragmengt的父类,我们在父类中初始化后即可使用。如下:

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentLayout(FssBind.getLayoutId(this));  //设置布局
        FssBind.bind(this, BaseActivity.class);       //绑定
    }
    
    //这样写是为了支持databinding
     protected void setContentLayout(@LayoutRes int layoutResID) {
        setContentView(layoutResID);
    }
}

        如果使用databinding的话,可以在写一个databinding的父类,如下:

public abstract class BaseBindingActivity<VB extends ViewDataBinding> extends BaseActivity {

    protected VB binding;

    @Override
    protected void setContentLayout(int layoutResID) {
        binding = DataBindingUtil.setContentView(this, layoutResID);
    }
}

     然后我们来介绍下怎么使用 先看一个包含所有使用情况的例子:

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

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

      上面为了演示使用,将几乎所有bind框架的注解都使用到了,如果觉得复杂,那我们再来看几个简单的例子

      例子1- 比如我们有一个详情页面,这个详情页由另一个Activity跳转过来,并且向这个详情页传递了参数(key值为“EXTRA_VALUE”),详情页页面只有一个textView(id为R.id.text)以及一个返回按钮(R.id.back),详情页要求只需要显示数据并且返回就可以了,那么我们可以这么写:

@BindActivity(layout = R.layout.activity_detail, finish = R.id.back)
public class DetailActivity extends BaseBindingFssActivity<ActivityDetailBinding> {
    
    //绑定intent参数,将key值为EXTRA_VALUE的参数绑定达到value变量
    @BindParam(key = "EXTRA_VALUE")
    private Integer value;
    
    //绑定视图
    @BindView(id = R.id.text)
    private TextView textView;
    
   void initView(){
        textView.setText(value);
   }
}

       如果使用了databinding的话,那么代码又会更加简单了,假设databinding页面中使用变量value,该变量绑定到textView的text属性上:  

@BindActivity(layout = R.layout.activity_detail, finish = R.id.back)
public class DetailActivity extends BaseActivity<ActivityDetailBinding> {

    @BindBindingParam(key = "EXTRA_VALUE",  id = BR.value)
    private String value;

}

     上面的代码还可以写的更简单:  

@BindActivity(layout = R.layout.activity_detail, finish = R.id.back)
@BindBindingParam(key = "EXTRA_VALUE",  id = BR.value)
public class DetailActivity extends BaseActivity<ActivityDetailBinding> {
}

     看到没有,一行代码都没有了!!!,这就是使用Bind框架的简洁。 例子我们先看到这儿,接下来,我们总结一下Bind框架的特点。

      1. 大量运用注解,开发更简洁,规范

      2. 由于使用了反射,运行效率不高。(虽然不高,但也可以接受,除非你的应用要求特别高)

      熟悉ButterKnife的同学可能知道,BindView,BindOnClick和ButterKnife很像,我们对比一下fss_bind和butterKnife的区别:

      1. fss_bind框架中BindView视图,BindOnClick方法等修饰的属性或方法可以为任意访问修饰符,而ButterKnife必须为public修饰符

      2. ButterKnife适合绑定视图(绝大多数情况),绑定资源文件,而fss_bind除了绑定视图或点击事件外还可以绑定参数,路由等等功能
     3. ButterKnife中用到的注解不能继承,而fss_bind所使用到的注解可以被继承,这在开发模板类时十分有用
     4. ButterKnife的优势是性能,因为它没有使用反射,因此效率比较高,而fss_bind是使用反射实现的,效率不及ButterKnife。

     在本人手机上(骁龙835)测试时,一个页面一般只需要0-10ms左右,简单的一两ms,稍微复杂的6、7ms左右,本人发布的HiChat应用几乎全部使用fss_bind框架开发,使用体验与不使用fss_bind框架没有感受到区别。

     综合上面,如果你只需要ButterKnife的功能,或者追求高性能的话,可以考虑ButterKnife。否者你可以使用fss_bind框架,使用它开发会使代码更加简洁,笔者也会在后期继续优化性能。

fss_adapter:

         使用它可以使得ListView,RecyclerView的适配器开发更简单。

 类介绍:

         ListView:

                       BaseSimpleAdapter

                       CommonAdapter

                       BaseBindingSimpleSingleAdapter

                       BaseBindingSimpleAdapter

        RecyclerView:

                       BaseRecyclerViewAdapter

                       CommonRecyclerViewAdapter

                       BaseBindingRecyclerViewSingleAdapter

                       BaseBindingRecyclerViewAdapter

例子:

ListView - CommonAdapter

          继承了BaseSimpleAdapter,并提供了CommonViewHolder,不需要再写ViewHolder。子类需要实现setView方法

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);代替
            }
        };

RecyclerView - CommonRecyclerViewAdapter

        继承了BaseRecyclerViewAdapter,并提供了RecyclerViewCommonViewHolder,不需要再写ViewHolder。子类需要实现onBindView方法

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

ListView - BaseSimpleAdapter

         对BaseAdapter的封装,子类需要写ViewHolder,以及实现setView方法,注意ViewHolder需要继承自BaseViewHolder

class Adapter extends BaseSimpleAdapter<String, Adapter.ViewHolder> {

    public Adapter(Context context, List<String> datas) {
        super(context, datas, R.layout.layout_list_item);
    }

    @Override
    protected void setView(ViewHolder holder, String s, int position) {
        holder.tvText.setText(s);
    }

    static class ViewHolder extends BaseViewHolder {
        TextView tvText;

        public ViewHolder(View view) {
            super(view);
            this.tvText = findViewById(R.id.tv_text);
        }
    }
}

 也可以使用BindView绑定视图,如下: 

class BindAdapter extends BaseSimpleAdapter<String, BindAdapter.BindViewHolder> {

    public BindAdapter(Context context, List<String> datas) {
        super(context, datas, R.layout.layout_list_item);
    }

    @Override
    protected void setView(BindViewHolder holder, String s, int position) {
        holder.tvText.setText(s);
    }

    class BindViewHolder extends BaseViewHolder {
        @BindView(id = R.id.tv_text)
        TextView tvText;

        public BindViewHolder(View itemView) {
            super(itemView);
        }
    }
}

RecyclerView - BaseRecyclerViewAdapter 

         对RecyclerView.Adapter的封装,子类需要写ViewHolder,以及实现onBindView方法,注意ViewHolder需要继承自BaseRecyclerViewHolder

class Adapter extends BaseRecyclerViewAdapter<String, Adapter.ViewHolder> {

    public Adapter(Context context, List<String> datas) {
        super(context, datas, R.layout.layout_list_item);
    }

    @Override
    public void onBindView(@NonNull ViewHolder holder, String s, int position) {
        super.onBindView(holder, s, position);
        holder.tvText.setText(s);
    }

    class ViewHolder extends BaseRecyclerViewHolder {
        TextView tvText;

        public ViewHolder(View view) {
            super(view);
            this.tvText = findViewById(R.id.tv_text);
        }
    }
}

 也可以使用BindView绑定视图,如下:

class BindAdapter extends BaseRecyclerViewAdapter<String, BindAdapter.BindViewHolder> {

    public BindAdapter(Context context, List<String> datas) {
        super(context, datas, R.layout.layout_list_item);
    }

    @Override
    public void onBindView(@NonNull BindViewHolder holder, String s, int position) {
        super.onBindView(holder, s, position);
        holder.tvText.setText(s);
    }

    class BindViewHolder extends BaseRecyclerViewHolder {
        @BindView(id = R.id.tv_text)
        TextView tvText;

        public BindViewHolder(View view) {
            super(view);
        }
    }
}

 ListView - BaseBindingSimpleAdapter

         使用了databindibng的适配器,支持单个类型的layout,注意构造参数中需要传入databinding变量对应的id

class BindingAdapter extends BaseBindingSimpleAdapter<String> {

    public BindingAdapter(Context context, List<String> datas) {
        super(context, datas, BR.value, R.layout.layout_binding_list_item);
    }

    @Override
    protected void onBindView(ViewDataBinding viewDataBinding, String s, int position) {
        super.onBindView(viewDataBinding, s, position);
    }
}

RecyclerView - BaseBindingRecyclerViewAdapter 

     使用了databinding的适配器,支持多个类型的layout,注意构造参数中需要传入databinding变量对应的id   

class BindingAdapter extends BaseBindingRecyclerViewAdapter<String> {

    public BindingAdapter(Context context, List<String> datas) {
        super(context, datas, BR.value, R.layout.layout_binding_list_item);
    }

    @Override
    public void onBindView(@NonNull ViewDataBinding viewDataBinding, String str, int position) {
        super.onBindView(viewDataBinding, str, position);
    }
}

ListView - BaseBindingSimpleSingleAdapter 

       使用了databindibng的适配器,支持单个类型的layout,注意构造参数中需要传入databinding变量对应的id

class BindingSingleAdapter extends BaseBindingSimpleSingleAdapter<String, LayoutBindingListItemBinding> {

    public BindingSingleAdapter(Context context, List<String> datas) {
        super(context, datas, BR.value, R.layout.layout_binding_list_item);
    }

    @Override
    protected void onBindView(LayoutBindingListItemBinding viewDataBinding, String str, int position) {
        super.onBindView(viewDataBinding, str, position);
    }
}

RecyclerView - BaseBindingRecyclerViewSingleAdapter 

       使用了databindibng的适配器,支持单个类型的layout,注意构造参数中需要传入databinding变量对应的id

class BindingSingleAdapter extends BaseBindingRecyclerViewSingleAdapter<String, LayoutBindingListItemBinding> {

    public BindingSingleAdapter(Context context, List<String> datas) {
        super(context, datas, BR.value, R.layout.layout_binding_list_item);
    }

    @Override
    public void onBindView(@NonNull LayoutBindingListItemBinding viewDataBinding, String str, int position) {
        super.onBindView(viewDataBinding, str, position);
    }
}

 

 

 

 

 

 

 

 

 

 

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FSS私密的文件分享及传递工具程序说明 1.本程序无需数据库支持,兼容并自适应所有主流浏览器(PC端、手机端),文件生命周期记录及配置使用写PATH_UPLOAD/xxx.conf文件的方式。 2.运行环境php5.x php7.x (版本高点或低点理论上没啥问题)。 3.支持浏览器拖拽上传,可用于企业内网同事间私密互传文件。 4.为啥代码要加密?这个不想解释。 FSS私密的文件分享及传递工具程序安装配置说明 (1) 程序配置文件/config.php。 (2) PATH_UPLOAD指定文件上传路径(默认/upload目录),该目录需读写权限。(程序未限制文件上传类型,为了系统安全,请务必调整本路径为非网站路径) (3) LOG_PATH指定日志路径(默认/log),LOG_OPEN 指定是否开始日志功能,该目录需读写权限。(为了系统安全,请务必调整本路径为非网站路径) (4) 程序上传最大支持size依赖php.ini (本例以50M为参考) upload_max_filesize = 50m ; post_max_size = 50M ; (5) 如果用nginx,需在nginx.conf中http部分添加 client_max_body_size 50m; (6) SITE_URL指定网站访问路径. (7) FILE_RETAIN_DAYS 指定文件生命周期,单位天,到期后调用该文件会被自动删除;对于批量过期删除放在新文件上传时触发,当然你也可以手动删除。 (8) API_KEYID(公钥) API_SECRET(私钥) 文件签名,该值可任意修改,用于防盗链,生成后的真实下载链接有600秒生命周期。 FSS私密的文件分享及传递工具 v1.0.2新日志 1.可指定日志文件路径。 2.加入运行环境检测功能。 3.可配置文件保留天数或永久保存。 4.文件下载链接加入签名功能,防盗链。 5.文件下载加入密码功能。 6.增加文件下载次数显示。 FSS私密的文件分享及传递工具截图 相关阅读 同类推荐:站长常用源码
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值