Android流行框架菜鸟式实践
扩展需自己过多的学习
文章目录
Evenbus (事件总线-组件间通讯)
依赖
implementation 'org.greenrobot:eventbus:3.2.0'
作用
简化组件间的通信
替换一下handle,intent,broadcast的使用
三要素
- Event事件 任意类型
- Subscribe事件订阅
在事件方法上使用Subscribe注解并指定线程模型
- Publisher事件发布者 任意线程发布
一般使用Eventbus.getdefault().post(object)
四种线程模型
- posting 事件处理和事件发布在同一个线程
- main 事件处理在ui线程
- backgroup 事件处理后台线程
若事件发布在main线程,则会创建一个后台线程;若事件发布本身在后台线程,事件处理不许再创建后台线程,在当前线程执行
- async 始终创建一个子线程来执行事件处理
使用步骤
-
定义事件类
传输数据的Bean
public class MessageEvent{}
-
注册事件
在Activity oncreate方法里面
EventBus.getDefault().register(this);
-
解除事件
在Activity ondestroy方法里面
EventBus.getDefault().unregister(this);
-
发送事件
EventBus.getDefault().post(new OneMessage("这是啥玩意"));
-
处理事件
@Subscribe(threadMode = ThreadMode.MAIN) public void eventPost(OneMessage oneMessage){ textView.setText(oneMessage.getMessage()); }
注意: 每一个Activity需要注册Evenbus之后才能处理执行事件方法,不注册可以发送事件
Retrofit (网络请求)
作用
网络请求框架的封装,基于okhttp [请求内部使用okhttp,retrofit是对请求接口的封装]
- 使用注解配置网络请求参数
- 同步 & 异步 请求
- 支持RxJava
- 多格式数据解析
使用
-
创建Java Bean [服务器返回的数据]
public class Github { private String login; private long id; private String node_id; private String avatar_url; private String gravatar_id; private String url; private String html_url; private String followers_url; private String following_url; private String gists_url; private String starred_url; private String subscriptions_url; private String organizations_url; private String repos_url; private String events_url; private String received_events_url; private String type; private boolean site_admin; private String name; private String company; private String blog; private String location; private String email; private String hireable; private String bio; private int public_repos; private int public_gists; private int followers; private int following; private Date created_at; private Date updated_at; public void setLogin(String login) { this.login = login; } public String getLogin() { return login; } public void setId(long id) { this.id = id; } public long getId() { return id; } public void setNode_id(String node_id) { this.node_id = node_id; } public String getNode_id() { return node_id; } public void setAvatar_url(String avatar_url) { this.avatar_url = avatar_url; } public String getAvatar_url() { return avatar_url; } public void setGravatar_id(String gravatar_id) { this.gravatar_id = gravatar_id; } public String getGravatar_id() { return gravatar_id; } public void setUrl(String url) { this.url = url; } public String getUrl() { return url; } public void setHtml_url(String html_url) { this.html_url = html_url; } public String getHtml_url() { return html_url; } public void setFollowers_url(String followers_url) { this.followers_url = followers_url; } public String getFollowers_url() { return followers_url; } public void setFollowing_url(String following_url) { this.following_url = following_url; } public String getFollowing_url() { return following_url; } public void setGists_url(String gists_url) { this.gists_url = gists_url; } public String getGists_url() { return gists_url; } public void setStarred_url(String starred_url) { this.starred_url = starred_url; } public String getStarred_url() { return starred_url; } public void setSubscriptions_url(String subscriptions_url) { this.subscriptions_url = subscriptions_url; } public String getSubscriptions_url() { return subscriptions_url; } public void setOrganizations_url(String organizations_url) { this.organizations_url = organizations_url; } public String getOrganizations_url() { return organizations_url; } public void setRepos_url(String repos_url) { this.repos_url = repos_url; } public String getRepos_url() { return repos_url; } public void setEvents_url(String events_url) { this.events_url = events_url; } public String getEvents_url() { return events_url; } public void setReceived_events_url(String received_events_url) { this.received_events_url = received_events_url; } public String getReceived_events_url() { return received_events_url; } public void setType(String type) { this.type = type; } public String getType() { return type; } public void setSite_admin(boolean site_admin) { this.site_admin = site_admin; } public boolean getSite_admin() { return site_admin; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setCompany(String company) { this.company = company; } public String getCompany() { return company; } public void setBlog(String blog) { this.blog = blog; } public String getBlog() { return blog; } public void setLocation(String location) { this.location = location; } public String getLocation() { return location; } public void setEmail(String email) { this.email = email; } public String getEmail() { return email; } public void setHireable(String hireable) { this.hireable = hireable; } public String getHireable() { return hireable; } public void setBio(String bio) { this.bio = bio; } public String getBio() { return bio; } public void setPublic_repos(int public_repos) { this.public_repos = public_repos; } public int getPublic_repos() { return public_repos; } public void setPublic_gists(int public_gists) { this.public_gists = public_gists; } public int getPublic_gists() { return public_gists; } public void setFollowers(int followers) { this.followers = followers; } public int getFollowers() { return followers; } public void setFollowing(int following) { this.following = following; } public int getFollowing() { return following; } public void setCreated_at(Date created_at) { this.created_at = created_at; } public Date getCreated_at() { return created_at; } public void setUpdated_at(Date updated_at) { this.updated_at = updated_at; } public Date getUpdated_at() { return updated_at; } @Override public String toString() { return "Github{" + "login='" + login + '\'' + ", id=" + id + ", node_id='" + node_id + '\'' + ", avatar_url='" + avatar_url + '\'' + ", gravatar_id='" + gravatar_id + '\'' + ", url='" + url + '\'' + ", html_url='" + html_url + '\'' + ", followers_url='" + followers_url + '\'' + ", following_url='" + following_url + '\'' + ", gists_url='" + gists_url + '\'' + ", starred_url='" + starred_url + '\'' + ", subscriptions_url='" + subscriptions_url + '\'' + ", organizations_url='" + organizations_url + '\'' + ", repos_url='" + repos_url + '\'' + ", events_url='" + events_url + '\'' + ", received_events_url='" + received_events_url + '\'' + ", type='" + type + '\'' + ", site_admin=" + site_admin + ", name='" + name + '\'' + ", company='" + company + '\'' + ", blog='" + blog + '\'' + ", location='" + location + '\'' + ", email='" + email + '\'' + ", hireable='" + hireable + '\'' + ", bio='" + bio + '\'' + ", public_repos=" + public_repos + ", public_gists=" + public_gists + ", followers=" + followers + ", following=" + following + ", created_at=" + created_at + ", updated_at=" + updated_at + '}'; } }
-
创建网络请求接口
public interface GitHubService { @GET("users/Primer1889") Call<Github> listRepos(); }
-
创建Retrofit实例
retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .baseUrl("https://api.github.com/") .build();
-
创建网络接口实例 & 配置请求参数
GitHubService service = retrofit.create(GitHubService.class); Call<Github> repos = service.listRepos();
-
发送请求
retrofit请求需要在子线程里面进行,handler满足需求,Evenbus也满足需求,当然也有其他方式,这里主要使用最简单的handle和高效的Evenbus
方式一 : 在handle里面
private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { GitHubService service = retrofit.create(GitHubService.class); Call<Github> repos = service.listRepos(); repos.enqueue(new retrofit2.Callback<Github>() { @Override public void onResponse(Call<Github> call, Response<Github> response) { Log.d(TAG, "onResponse: 响应结果"); Log.d(TAG, "onResponse: 姓名"+response.body().getName()); Log.d(TAG, "onResponse: \n"+response.body().toString()); } @Override public void onFailure(Call<Github> call, Throwable t) { Log.d(TAG, "onFailure: 响应失败"+t.toString()); } }); } };
方式二: Evenbus
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_translate); EventBus.getDefault().register(this); //http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .baseUrl("https://api.github.com/") .build(); service = retrofit.create(GitHubService.class); EventBus.getDefault().post(new GithubMessage("Primer1889")); //handler.sendMessage(new Message()); Log.d(TAG, "onCreate: 结束"); }
@Subscribe(threadMode = ThreadMode.ASYNC) public void getGithubNameMsg(GithubMessage githubMessage){ Call<Github> repos = service.listRepos(); repos.enqueue(new retrofit2.Callback<Github>() { @Override public void onResponse(Call<Github> call, Response<Github> response) { Log.d(TAG, "onResponse: 响应结果"); Log.d(TAG, "onResponse: 姓名"+response.body().getName()); Log.d(TAG, "onResponse: \n"+response.body().toString()); } @Override public void onFailure(Call<Github> call, Throwable t) { Log.d(TAG, "onFailure: 响应失败"+t.toString()); } }); }
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ASyxUpm8-1583033887636)(C:\Users\Primer4\Documents\学习笔记\1582896312476.png)]
注解
- 请求方法
@POST
等 - 标记类
@Streaming
等 - 请求参数
@Body
等
Butterknife (注解模板代码)
依赖
android {
...
// Butterknife requires Java 8.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'com.jakewharton:butterknife:10.2.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'
}
buildscript {
repositories {
mavenCentral()
google()
}
dependencies {
classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.1'
}
}
//apply plugin: 'com.android.library' 高版本的Android studio 内部集成了
apply plugin: 'com.jakewharton.butterknife'
使用
-
绑定布局
ButterKnife.bind(this);
this是指activity的Context -
点击事件
@OnClick(R.id.button) public void changeText(){ textView.setText("文字更改"); }
-
绑定控件
@BindView(R.id.text_change) public TextView textView; //一定是private
-
绑定资源
@BindString(R.string.app_name) public String changeText;
-
在fragment里面绑定布局
记得在onCreateView里面绑定布局
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fancy_fragment, container, false); ButterKnife.bind(this, view); return view; }
-
在adapter里面绑定布局
记得在ViewHolder里面绑定布局
static class ViewHolder { @BindView(R.id.title) TextView name; @BindView(R.id.job_title) TextView jobTitle; public ViewHolder(View view) { ButterKnife.bind(this, view); } }
-
多控件绑定 使用大括号包含控件集合
-
可选绑定
@Nullable和@Optional
控件不存在接不存在
GreenDao (数据库)
依赖
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
implementation 'org.greenrobot:greendao:3.2.2' // add library
}
注解
- @Entity 实体
- @Id 主键Long
@Id(autoincrement = true)设置自增长
- @NotNul 不为空
- @Transient 不生成数据表的列
- @Index 索引
- @Unique唯一约束
- @ToOne 和另一个实体关联
- @ToManny 和多个实体关联
使用
-
创建Bean
构建项目自动生成模板代码
@Entity public class User { @Id private Long id; private String name; private int age; //下面省去了 setter/getter }
-
创建 DBManager
数据库管理
Glide (图片加载-支持GIF)
依赖
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
使用
- 基本使用
Glide.with(this).load(imageURL).into(imageView);
-
recycleView Adapter中使用Glide
@Override public View getView(int position, View convertView, ViewGroup parent) { if (null == convertView) { convertView = inflater.inflate(R.layout.listview_item_image, parent, false); } Glide .with(context) .load(imageUrls[position]) .into((ImageView) convertView); return convertView; }
功能
-
必要的三个参数
- with(context)
- load(url)
- into(imageview)
-
多源加载
- 网络资源
- 本地资源
- 文件
- uri
-
缓存实现基于Picasso
- 缓存实现大小依赖设备磁盘的大小: 内存 磁盘,网络
- skipMemoryCache(true) 跳过内存缓存 [就是不会把图片缓存在内存里]
- diskCacheStrategy 磁盘缓存
-
图片占位符
- glide在加载图片的过程中imageview是空白的
- placeholder(url) 加载成功之前显示的图片
- erro(url)加载错误的时候显示的图片
-
淡入淡出
- crossFade()
- dontAnimate() 取消淡入淡出
-
缩放
- rtuesize(x,y)
- override(x,y)
- centercrop() 图片不完全显示,大小等于imageview大小
- fitcenter() 图片完全显示,大小可能不等于image view大小
-
类型转换
- asgif() 若图片url不是gif则加载失败
- asbitmap() 如果是git则会显示第一帧
-
视频
- 仅仅可以试试本地视频
-
请求优先级
priority(Priority.LOW)
-
缩略图
thumbnail
配合imageview的scaleType使用
RxAndroid (异步)
依赖
allprojects {
repositories {
maven { url "https://oss.jfrog.org/libs-snapshot" }
}
}
dependencies {
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
}
概念理解
-
响应式
- 关注结果的变化
-
观察者模式
- Observable 被观察者 [行为可发生改变]
- Observer 观察者 [知道行为改变之后做出响应动作]
- Subscribe 订阅 [关联两者的关系]
- 事件处理
- onNext 一个事件处理
- onComplete 事件处理完成
- onError 事件处理错误
-
map
.map(new Function<String, List<String>>() { @Override public List<String> apply(String query) { return mCheeseSearchEngine.search(query); } })
map
操作符对 observable 发出的每一个事件应用一次函数变换,返回另外的一个发出函数执行结果类型事件的 observable
-
filter
return textChangeObservable .filter(new Predicate<String>() { @Override public boolean test(String query) throws Exception { return query.length() >= 2; } });
filter
操作符,防抖动
, 对 observable 发出的事件进行过滤。但是决定事件该不该被过滤掉的原则不是靠判断发出的是什么事件,而是取决于何时发出的事件
-
merge
Observable<String> searchTextObservable = Observable.merge(textChangeStream, buttonClickStream);
- 接收两个或更多 observable 发出的事件,然后将它们放入一个 observable 中处理
线程模型
-
控制线程模型 [observabel的方法]
- subscribeOn
指定被观察者(Observable)自身在哪个调度器上执行
- observeOn
指定一个观察者(Observer)在哪个调度器上观察这个被观察者(Observable)
- subscribeOn
-
Schedulers.trampoline()
将任务加入一个队列,等待执行 -
Schedulers.newThread()
每次都创建新的线程执行操作; -
Schedulers.immediate()
在当前线程运行,默认为此策略; -
Schedulers.io()
: 适合在 I/O 线程的工作,例如网络请求或磁盘操作。 -
Schedulers.computation()
: 计算性的任务,比如事件轮循或者处理回调等。 -
AndroidSchedulers.mainThread()
在主线程中执行下个操作符的操作。
使用
-
创建被观察者
需要处理那些事件
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("我叫小锋锋 "+Thread.currentThread().getName()); subscriber.onCompleted(); } });
-
创建观察者
处理事件的具体逻辑
Observer<String> observer = new Observer<String>() {
//事件处理逻辑
@Override
public void onCompleted() {
Log.d(TAG, "onCompleted: 完成!");
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError: 错误");
}
@Override
public void onNext(String s) {
Log.d(TAG, "onNext: 结果 "+s);
textView.setText(s);
}
};
-
调用
指定 观察者 的线程模型 observeOn
指定 被观察者 的线程模型 subscribeOn
Subscription subscribe = observable
.subscribeOn(Schedulers.io())//指定线程模型
.doOnSubscribe(new Action0() {
@Override
public void call() {
}
})
.observeOn(AndroidSchedulers.mainThread())//指定线程模型
.subscribe(observer);//通知,观察者