Android组件化+MVP+Dragger2+RxJava+EventBus

Android开发规范


参考文章

学习Android开发的规范,主要学习到的点:
1、包名划分采用PBF进行分包的好处,因为同一功能代码在同一包中,所以容易删除功能,并且降低了package耦合;拥有私有作用域,一个功能不能访问另一功能的任何东西;包大小体现出功能的问题,包太大说明此功能需要进行重构。
2、命名规范主要需要记住的是静态字段命名以s开头,非静态字段以m开头,其他的规范都比较熟悉。
3、代码样式规范主要学习到Activities 和 Fragments 的传参,直接使用AndroidStudio写好的Live Templates,输入starter或者newInstance来生成启动器。
4、版本统一规范,可以在build.gradle文件中使用ext来定义全局变量

MVP


Google官方出品的架构项目,属于MVC的演化版本,MVC中Activity的作用既像View又像Controller,演化之后,出现了Presenter,将Activity完全视为View层,Presenter则负责View和Model层之间的交互。MVC中Controller没有完全让Model和View断开联系,Model和View可以进行交互,MVP则让两者完全解耦。
MVP简化了Activity的代码,将业务逻辑的相关代码提取到Presenter层中进行处理。同时MVP中虽然增加了很多的类,但是使代码变得很清晰。

组件化开发


参考文章
组件化架构包括三层,基础层主要是封装一些常用的操作,不同的组件都可以进行引用;组件层包含各种功能组件,每个组件都是一个module;应用层来引用不同的组件实现最终的业务功能。
组件化开发需要解决的问题:
1.每个组件都是一个整体,开发过程中需要满足组件单独运行和调试的要求。解决方法是:
在组件module中添加gradle.properties配置文件,在文件中添加一个boolean类型的变量,在build.gradle中通过这个布尔值来判断需要单独调试运行还是集成调试,然后修改apply plugin的值、是否需要配置applicationId,以及使用的Manifest文件的调整。
2、组件之间的相互调用和数据传递,界面跳转
创建ComponentBase模块,供基础层依赖,在其中定义组件中需要对外提供访问的Service接口和空实现的类,然后在组件中进行具体实现,并将实现这些方法的类的对象添加到ComponentBase提供的ServiceFactory中,其他组件就可以通过调用ServiceFactory获取想要调用的方法和数据。
组件间的界面跳转使用第三方的ARouter来实现组件间的路由功能,在Application将它初始化,就可以通过配置的路由来实现界面跳转。
3、主项目访问组件中的Fragment
一种方式可以直接通过反射来进行Fragment的初始化,并传递给Activity。
另一种方式和上述ServiceFactory方式相同,在Service接口中添加获取Fragment的方法,并在组件的实现类中返回Fragment对象,这样就可以通过ServiceFactory来获取Fragment。
4、集成调试时,如果依赖多个组件,如何实现依赖其中一部分就编译通过
这个问题通过上边问题的解决已经得到了解决,组件间没有直接的关联,都是通过ComponentBase的Service接口来实现,由于其中默认提供了空实现,所以即使被调用的组件没有初始化,调用也不会出现异常,只是调用了一个空的实现。

Dagger2


参考文章
Dagger2是一个依赖注入框架,注入方式是通过apt插件在编译阶段生成对应的注入代码。依赖注入的目的是为了降低程序的耦合,耦合产生的原因就是因为类之间的依赖,通过依赖注入来解决类之间的依赖问题。
如何引入Dagger2就不详细说明了,首先引入一段简单的在MVP中实现了依赖注入代码,虽然看起来比直接实例化更加复杂,但是这种方式通过添加一些辅助类解决了程序的耦合问题,去除了类之间的直接依赖。

public class MainActivity extends AppCompatActivity implements MainContract.View {
    @Inject
    MainPresenter mainPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         //初始化
         DaggerMainComponent.builder()
                .mainModule(new MainModule(this))
                .build()
                .inject(this);
        //调用Presenter方法加载数据
         mainPresenter.loadData();
    }

}

public class MainPresenter {
    private MainContract.View mView;
    
    @Inject
    MainPresenter(MainContract.View view) {
        mView = view;
    }    
    public void loadData() {
        //调用model层方法,加载数据
    }

@Module
public class MainModule {
    private final MainContract.View mView;

    public MainModule(MainContract.View view) {
        mView = view;
    }

    @Provides
    MainView provideMainView() {
        return mView;
    }
}

@Component(modules = MainModule.class)
public interface MainComponent {
    void inject(MainActivity activity);
}

public interface MainContract {
    interface View extends IView {
    }

    interface Presenter extends IPresenter {
        void loadData();
    }

    interface Model extends IModel {
    }
}

然后我们rebuild一下项目,通过生成的DaggerMainComponent来实现注入,在MainActivity添加如下代码:

DaggerMainComponent.builder()
               .mainModule(new MainModule(this))
               .build()
               .inject(this);

看完可能一脸懵,为什么MainActivity用@Inject注解就完成了mainPresenter的实例化,他们究竟是怎么产生的关系。
首先有几个注解需要了解一下:

  • @Inject 带有此注解的属性或构造方法将参与到依赖注入中,Dagger2会实例化有此注解的类
  • @Module 带有此注解的类,用来提供依赖,里面定义一些用@Provides注解的以provide开头的方法,这些方法就是所提供的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖。
  • @Component 用来将@Inject和@Module联系起来的桥梁,从@Module中获取依赖并将依赖注入给@Inject

理解了这几个含义就容易理解他们之间的关系,首先MainActivity想要依赖MainPresenter,然后发现MainPresenter构造函数有@Inject注解,可以实现实例化,但是里边有一个参数MainContract.View,因此需要通过MainModule中的provideMainView来提供依赖,作为MainModule的构造函数参数传入。
想要更深的理解,可以看上方提供的参考文章的源码讲解,讲解的很清晰,通过生成的类之间的关系,实现了注入的过程。
最核心的部分就是DaggerMainComponent.builder中的initialize方法

@SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideMainViewProvider = MainModule_ProvideMainViewFactory.create(builder.mainModule);

    this.mainPresenterProvider = MainPresenter_Factory.create(provideMainViewProvider);

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainPresenterProvider);
  }

以及MainActivity_MembersInjector的injectMembers方法

@Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mainPresenter = mainPresenterProvider.get();
  }

MainPresenter_Factory通过MainModule_ProvideMainViewFactory的get方法获取到MainContract.View对象,MainModule_ProvideMainViewFactory的get方法则是通过传入的通过传入的mainModule的provideMainView方法来获取。
最后在DaggerMainComponent 的inject方法的实现中调用MainActivity_MembersInjector的injectMembers的方法中,injectMembers方法实现了将MainPresenter_Factory 的get方法实例化的mainPresenter赋值给MainActivity中的mainPresenter,从而实现了mainPresenter的实例化。

查找带有@Inject注解的参数是否可以注入,有两种方式。
第一种方式是直接查看构造函数,如果有@Inject注解则直接实例化;
第二种是 通过@Module注解的类中的@Provides看是否有需要的依赖。
注:如果有@Inject的构造函数中还需要其他参数,同样按照上述两种方式进行查找。

不看源码解释的确实有点绕口,感兴趣的可以去参考文章中查看更为详细的说明。

RxJava


RxJava是一个基于事件流,实现异步操作的库,逻辑简洁,实现优雅,使用简单等都是RxJava的优点。
Rxjava的原理是基于一种扩展的观察者模式,总共包括四个角色:

角色作用
被观察者(Observable)产生事件
观察者(Observer)接收事件,并给出响应动作
订阅(Subscribe)连接 被观察者 & 观察者
事件(Event)被观察者 & 观察者沟通的载体

被观察者通过订阅将事件发送给观察者,观察者接收到事件并执行相应操作。
Observable中常用到的操作符:

  • observeOn:主要功能是指定观察者(Observer)在哪个线程执行,多次执行的话都会进行切换。
  • subscribeOn:指定自身(Observable)在哪个线程执行。如果多次调用,只有第一次调用生效,之后的调用不再切换,与调用的位置没有关系。除了指定自身的执行位置还可以指定doOnSubcribe执行的位置。
  • doOnSubscribe:事件被订阅之前会调用的方法,如果调用此方法之后又调用了subscribeOn方法,那么它也会切换到新的线程中执行。
  • doOnNext:观察者被通知之前的回调方法,执行onNext()前调用。
  • compose:对当前被观察者进行操作,并返回一个新的被观察者。和map不同,map知识改变被观察者发布的事件和序列,compose则是直接对当前Observable进行操作。
  • map:将被观察者,转换成新的被观察者对象,并且发送给观察者,观察者会收到新的被观察者并处理。
  • subcribe:连接观察者和被观察者,观察者如果想要收到被观察者发送的数据,就必须要使用subcribe来订阅被观察者。里边可以实现观察者用来组合的一些方法,包括:onNext,onError,onCompleted,如果不传参数,将只发生订阅,观察者接收不到任何数据和通知。

EventBus


EventBus主要功能是简化组件之间的通信,同样是使用观察者模式,有效的将事件的发送和接收进行分离,实现解耦。
主要包括事件的订阅者(接收方),事件的发布者(发送发),通过传递事件实现两者的通信。
基本的用法就是:
首先自定义一个事件类,用来传递事件;
其次需要在订阅者和发布者中都进行注册,并且在页面销毁等不需要的时候取消注册;
发送事件通过调用post方法,将发送的事件保存到事件队列;
在接收方通过@Subscribe注解来接收事件类的对象,注解中需要指定线程模型,并进行相应的处理。
线程模型总共分为四种:

  • POSTING (默认) 表示事件处理函数的线程跟发布事件的线程在同一个线程。
  • MAIN 表示事件处理函数的线程在主线程,因此在这里不能进行耗时操作。
  • BACKGROUND 表示事件处理函数的线程在后台线程,因此不能进行UI操作。如果发布事件的线程是主线程,那么事件处理函数将会开启一个后台线程,如果发布事件的线程是在后台线程,那么事件处理函数就使用该线程。
  • ASYNC 表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个线程运行,同样不能进行UI操作。

如果想要在事件发送之后订阅还可以接收到事件,那就需要用到粘性事件,粘性事件需要通过postSticky方法来发送,接收是需要在注解中添加sticky=true,粘性事件需要进行手动移除,也可以通过检查,看是否存在此事件。

以上就是最新学习的一些知识,希望能给大家提供帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ant Design Pro React 提供了 Upload 组件来实现上传功能。以下是实现上传的步骤: 1. 导入 Upload 组件和其他必要的组件: ``` import { Upload, message } from 'antd'; import { InboxOutlined } from '@ant-design/icons'; ``` 2. 定义上传组件的属性和状态: ``` const { Dragger } = Upload; const props = { name: 'file', multiple: true, action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', onChange(info) { const { status } = info.file; if (status !== 'uploading') { console.log(info.file, info.fileList); } if (status === 'done') { message.success(`${info.file.name} file uploaded successfully.`); } else if (status === 'error') { message.error(`${info.file.name} file upload failed.`); } }, }; class UploadComponent extends React.Component { state = { fileList: [], }; handleChange = ({ fileList }) => this.setState({ fileList }); render() { const { fileList } = this.state; return ( <Dragger {...props} fileList={fileList} onChange={this.handleChange}> <p className="ant-upload-drag-icon"> <InboxOutlined /> </p> <p className="ant-upload-text">Click or drag file to this area to upload</p> <p className="ant-upload-hint"> Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files </p> </Dragger> ); } } ``` 3. 在 render() 方法中渲染上传组件: ``` render() { return ( <div> <UploadComponent /> </div> ); } ``` 这样就可以实现一个基本的上传组件。此外,Ant Design Pro React 还提供了其他的上传组件和功能,可根据具体的需求进行选择和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值