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,粘性事件需要进行手动移除,也可以通过检查,看是否存在此事件。
以上就是最新学习的一些知识,希望能给大家提供帮助。