mvp
java
retrofit
gson
okhttp
對MVP的文字描述介紹
MVC(Model - View - Controller)
- Model : 數(shù)據(jù)(JavaBean實(shí)體類,用于保存實(shí)例數(shù)據(jù))
- View : UI界面牺陶,和用戶交互(向用戶展示數(shù)據(jù)以及接收用戶的輸入)
- Controller : 更新UI界面和數(shù)據(jù)實(shí)例
例如:View層接受用戶的輸入狈涮,然后通過Controller修改對應(yīng)的Model實(shí)例渠羞;同時(shí)躏吊,當(dāng)Model實(shí)例的數(shù)據(jù)發(fā)生變化的時(shí)候秸侣,需要修改UI界面赤屋,可以通過Controller更新界面园骆。(View層也可以直接更新Model實(shí)例的數(shù)據(jù)仪芒,而不用每次都通過Controller唁影,這樣對于一些簡單的數(shù)據(jù)更新工作會(huì)變得方便許多。)
MVP
MVP把Activity中的UI邏輯抽象成View接口掂名,把業(yè)務(wù)邏輯抽象成Presenter接口据沈,Model類還是原來的Model。
在MVP模式中Activity的功能就是響應(yīng)生命周期和顯示界面饺蔑,具體其他的工作都丟到了Presenter層中進(jìn)行完成锌介,Presenter其實(shí)是Model層和View層的橋梁。
- M(model) :數(shù)據(jù)層,用來放數(shù)據(jù)的處理(比如網(wǎng)絡(luò)請求孔祸,緩存等)
- V(view) : 負(fù)責(zé)UI具體實(shí)現(xiàn)展現(xiàn)隆敢。比如Presenter派發(fā)過來一個(gè)動(dòng)作是showDialog顯示進(jìn)度命令,那么我們這個(gè)View就負(fù)責(zé)實(shí)現(xiàn)具體UI
- P(presenter) : 負(fù)責(zé)處理業(yè)務(wù)邏輯代碼崔慧,處理Model數(shù)據(jù)拂蝎,然后將處理完的數(shù)據(jù)分發(fā)到View層
關(guān)于android的MVP模式其實(shí)一直沒有一個(gè)統(tǒng)一的實(shí)現(xiàn)方式,不同的人由于個(gè)人理解的不同惶室,進(jìn)而產(chǎn)生了很多不同的實(shí)現(xiàn)方式温自,其實(shí)很難去說哪一種更好,哪一種不好皇钞,針對不同的場合悼泌,不同的實(shí)現(xiàn)方式都有各自的優(yōu)缺點(diǎn)。
在這里夹界,我介紹的MVP是Google提出的一種MVP實(shí)現(xiàn)方式馆里。
APP——Dreamer
這個(gè)app要實(shí)現(xiàn)的是類似于“周公解夢”的查詢功能,點(diǎn)擊卡片可以看詳情
手?jǐn)]代碼?墒痢p佟!
準(zhǔn)備工作
- 在 build.gradle(Module: app )里添加依賴并 sync
- 下載GsonFormat 插件复斥,便于后續(xù)根據(jù)拿到的 json 數(shù)據(jù)直接生成使用該插件生成類
- api 接口(此api接口僅供本人自己使用哦~)
- android manifests 中添加網(wǎng)絡(luò)權(quán)限
ps
下面以此app的search為例子講 MVP 框架
1.Contract
加入了契約類來統(tǒng)一管理view與presenter的所有的接口慢哈,這種方式使得view與presenter中有哪些功能,一目了然永票,維護(hù)起來也方便卵贱,實(shí)例如下:
package com.example.chenshuyu.dreamer.search;
import...
public interface DreamerSearchContract {
interface DreamerSearchUIView{
//當(dāng)網(wǎng)絡(luò)錯(cuò)誤等原因獲取搜索結(jié)果沒有成功時(shí)
void onError();
//成功獲得搜索結(jié)果,且結(jié)果不為空時(shí)
void updateRV(List<Dreamer.DataBean> dataBeans);
//成功獲得搜索結(jié)果侣集,但是并沒有搜出來東西時(shí)
void onNull();
}
interface DreamerSearchPresenter{
//根據(jù)搜索輸入的獲keyword獲得搜索結(jié)果的
void getSearchDream(String keyword);
}
}
2.Model
package com.example.chenshuyu.dreamer.search;
import ...
public class DreamSearchModel {
private Retrofit retrofit = new Retrofit.Builder()
//設(shè)置數(shù)據(jù)解析器
.addConverterFactory(GsonConverterFactory.create())
//設(shè)置網(wǎng)絡(luò)請求的Url地址
.baseUrl("https://api.shenjian.io/")
.build();
// 創(chuàng)建網(wǎng)絡(luò)請求接口的實(shí)例
private RetrofitService api = retrofit.create(RetrofitService.class);
//通過model層的update方法獲得網(wǎng)絡(luò)請求拿到的數(shù)據(jù)
public Call<Dreamer> update(String keyword){
return api.getSearch("cfcde6656c3d1b67ecbecf400592d05e",keyword);
}
}
3.Presenter
package com.example.chenshuyu.dreamer.search;
/**
* presenter接口的具體實(shí)現(xiàn)類
*/
public class DreamSearchPresenterImpl implements DreamerSearchContract.DreamerSearchPresenter {
/**
* presenter應(yīng)該持有 view 層和 model 層的引用
* 這樣才能完成兩層之間的邏輯交互
* 同時(shí)使 view 層和 model 層完全隔離開來
*/
private DreamerSearchContract.DreamerSearchUIView searchUIView;
private DreamSearchModel dreamSearchModel = new DreamSearchModel();
/**
* presenter 層對應(yīng)的類持有的 view 層對應(yīng)的類是沒有辦法在 presenter 內(nèi)部實(shí)例化的(此時(shí)的view是有方法但是沒有具體實(shí)現(xiàn)的接口)
* view 層的具體實(shí)現(xiàn)是 activity 繼承 view 層键俱,并重寫 view 層的所有方法,即 activity 就是 view 層
* 故成員對象 view 的實(shí)例化對象是在activity中傳給presenter的
* 所以 presenter 的構(gòu)造函數(shù)中應(yīng)該傳入 view
* model 層是有具體實(shí)現(xiàn)類的世分,并且已經(jīng)在 presenter 類的內(nèi)部實(shí)例化了编振,這樣才能拿到 model 的具體數(shù)據(jù),進(jìn)行操作
* @param searchUIView
*/
public DreamSearchPresenterImpl(DreamerSearchContract.DreamerSearchUIView searchUIView){
this.searchUIView = searchUIView;
}
/**
* view 層和 model 層的邏輯交互臭埋,根據(jù)model的數(shù)據(jù)踪央,執(zhí)行相關(guān)的view層操作
* @param keyword
*/
@Override
public void getSearchDream(String keyword) {
Call<Dreamer> call = dreamSearchModel.update(keyword);
call.enqueue(new Callback<Dreamer>() {
//發(fā)送網(wǎng)絡(luò)請求成功
@Override
public void onResponse(Call<Dreamer> call, Response<Dreamer> response) {
Dreamer dreamer = response.body();
if (dreamer.getData() == null){
searchUIView.onNull();
}else {
searchUIView.updateRV(dreamer.getData());
}
}
//沒有成功
@Override
public void onFailure(Call<Dreamer> call, Throwable t) {
searchUIView.onError();
t.printStackTrace();
}
});
}
}
4.View
package com.example.chenshuyu.dreamer.search;
import...
public class SearchActivity extends AppCompatActivity implements DreamerSearchContract.DreamerSearchUIView{
private String keyword;
private EditText editText;
private ImageView imageView;
private RecyclerView recyclerView;
private SearchAdapter searchAdapter;
private LinearLayout linearLayout;
private List<Dreamer.DataBean> dataBeans = new ArrayList<>();
private DreamerSearchContract.DreamerSearchPresenter presenter = new DreamSearchPresenterImpl(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
initId();
initRV();
linearLayout.setVisibility(View.GONE);
editText.setHint("請輸入你想搜索的關(guān)鍵字");
// 點(diǎn)擊搜索,從EditTex獲得搜索keyword瓢阴,并通過presneter獲得搜索結(jié)果
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
keyword = editText.getText().toString();
presenter.getSearchDream(keyword);
}
});
}
// 綁定控件
private void initId(){
editText = findViewById(R.id.search_edit);
imageView = findViewById(R.id.search_img);
recyclerView = findViewById(R.id.search_rv);
linearLayout = findViewById(R.id.search_no);
}
// 初始化recyclerview
private void initRV(){
LinearLayoutManager linearLayout = new LinearLayoutManager(this);
linearLayout.setOrientation(LinearLayoutManager.VERTICAL);
searchAdapter = new SearchAdapter(dataBeans,this);
recyclerView.setLayoutManager(linearLayout);
recyclerView.setAdapter(searchAdapter);
}
// 重寫view的方法
@SuppressLint("CheckResult")
@Override
public void onError() {
linearLayout.setVisibility(View.GONE);
Toasty.error(this,"你的網(wǎng)絡(luò)崩潰了畅蹂,5555~",Toast.LENGTH_LONG).show();
}
@Override
public void updateRV(List<Dreamer.DataBean> dataBeanArrayList) {
linearLayout.setVisibility(View.GONE);
searchAdapter.update(dataBeanArrayList);
}
@Override
public void onNull() {
dataBeans.clear();
searchAdapter.update(dataBeans);
linearLayout.setVisibility(View.VISIBLE);
}
}
代碼架構(gòu)
- 每一個(gè)activity就是一個(gè)mvp框架搭建起來的
- entity用來存放數(shù)據(jù)請求獲得的類
- service 統(tǒng)一管理網(wǎng)絡(luò)請求的接口
想看完整代碼的大兄弟和小仙女,可以從github上clone荣恐,在此附上我的倉庫地址~:
https://github.com/chenshuyuhhh/Dreamer.git