1
0
mirror of https://github.com/WuXiaolong/AndroidMVPSample.git synced 2025-06-06 21:34:04 +08:00
This commit is contained in:
xiaomolong 2016-09-22 10:54:43 +08:00
parent d4a48d6f25
commit ec25f14dcd
20 changed files with 271 additions and 156 deletions

View File

@ -4,13 +4,15 @@
[Android MVP+Retrofit+RxJava实践小结](http://wuxiaolong.me/2016/06/12/mvpRetrofitRxjava/)
# 推荐阅读
1[Android MVP 实例](http://wuxiaolong.me/2015/09/23/AndroidMVPSample/)
1. [Android MVP 实例](http://wuxiaolong.me/2015/09/23/AndroidMVPSample/)
2、[Android Retrofit 2.0使用](http://wuxiaolong.me/2016/01/15/retrofit/)
1. [Android Retrofit 2.0 使用-补充篇](http://wuxiaolong.me/2016/06/18/retrofits/)
3、[RxJava](http://wuxiaolong.me/2016/01/18/rxjava/)
1. [Android Retrofit 2.0使用](http://wuxiaolong.me/2016/01/15/retrofit/)
4、[RxBus](http://wuxiaolong.me/2016/04/07/rxbus/)
1. [RxJava](http://wuxiaolong.me/2016/01/18/rxjava/)
1. [RxBus](http://wuxiaolong.me/2016/04/07/rxbus/)
# 微信公众号
欢迎微信扫一扫关注:不止于技术分享,每天进步一点点。

View File

@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "23.0.2"
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.wuxiaolong.androidmvpsample"

View File

@ -1,9 +0,0 @@
package com.wuxiaolong.androidmvpsample.mvp;
public interface Presenter<V> {
void attachView(V view);
void detachView();
}

View File

@ -3,25 +3,13 @@ package com.wuxiaolong.androidmvpsample.mvp.main;
/**
* Created by WuXiaolong on 2015/9/23.
* 业务具体处理包括负责存储检索操纵数据等
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public class MainModel {
/**
* city : 北京
* cityid : 101010100
* temp : 10
* WD : 东南风
* WS : 2级
* SD : 26%
* WSE : 2
* time : 10:25
* isRadar : 1
* Radar : JC_RADAR_AZ9010_JB
* njd : 暂无实况
* qy : 1012
*/
private WeatherinfoBean weatherinfo;
public WeatherinfoBean getWeatherinfo() {

View File

@ -1,12 +1,15 @@
package com.wuxiaolong.androidmvpsample.mvp.main;
import com.wuxiaolong.androidmvpsample.mvp.BasePresenter;
import com.wuxiaolong.androidmvpsample.rxjava.ApiCallback;
import com.wuxiaolong.androidmvpsample.rxjava.SubscriberCallBack;
import com.wuxiaolong.androidmvpsample.mvp.other.BasePresenter;
import com.wuxiaolong.androidmvpsample.retrofit.ApiCallback;
/**
* Created by WuXiaolong
* on 2015/9/23.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public class MainPresenter extends BasePresenter<MainView> {
@ -14,11 +17,10 @@ public class MainPresenter extends BasePresenter<MainView> {
attachView(view);
}
public void loadData(String cityId) {
mvpView.showLoading();
addSubscription(apiStores.loadData(cityId),
new SubscriberCallBack<>(new ApiCallback<MainModel>() {
new ApiCallback<MainModel>() {
@Override
public void onSuccess(MainModel model) {
mvpView.getDataSuccess(model);
@ -30,10 +32,11 @@ public class MainPresenter extends BasePresenter<MainView> {
}
@Override
public void onCompleted() {
public void onFinish() {
mvpView.hideLoading();
}
}));
});
}
}

View File

@ -3,6 +3,10 @@ package com.wuxiaolong.androidmvpsample.mvp.main;
/**
* Created by WuXiaolong on 2015/9/23.
* 处理业务需要哪些方法
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public interface MainView {

View File

@ -1,4 +1,4 @@
package com.wuxiaolong.androidmvpsample.mvp;
package com.wuxiaolong.androidmvpsample.mvp.other;
import com.wuxiaolong.androidmvpsample.retrofit.ApiStores;
import com.wuxiaolong.androidmvpsample.retrofit.AppClient;
@ -9,21 +9,26 @@ import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
/**
* Created by WuXiaolong on 2016/3/30.
* Created by WuXiaolong
* on 2015/9/23.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public class BasePresenter<V> implements Presenter<V> {
public class BasePresenter<V> {
public V mvpView;
public ApiStores apiStores = AppClient.retrofit().create(ApiStores.class);
protected ApiStores apiStores;
private CompositeSubscription mCompositeSubscription;
@Override
public void attachView(V mvpView) {
this.mvpView = mvpView;
apiStores = AppClient.retrofit().create(ApiStores.class);
}
@Override
public void detachView() {
this.mvpView = null;
onUnsubscribe();

View File

@ -1,10 +1,17 @@
package com.wuxiaolong.androidmvpsample.mvp;
package com.wuxiaolong.androidmvpsample.mvp.other;
import android.os.Bundle;
import com.wuxiaolong.androidmvpsample.ui.BaseActivity;
/**
* Created by WuXiaolong on 2016/3/30.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public abstract class MvpActivity<P extends BasePresenter> extends BaseActivity {
protected P mvpPresenter;

View File

@ -1,15 +1,18 @@
package com.wuxiaolong.androidmvpsample.mvp;
package com.wuxiaolong.androidmvpsample.mvp.other;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;
import com.wuxiaolong.androidmvpsample.ui.BaseFragment;
/**
* A simple {@link Fragment} subclass.
* Created by WuXiaolong on 2016/3/30.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public abstract class MvpFragment<P extends BasePresenter> extends BaseFragment {
protected P mvpPresenter;

View File

@ -0,0 +1,58 @@
package com.wuxiaolong.androidmvpsample.retrofit;
import com.wuxiaolong.androidutils.library.LogUtil;
import retrofit2.adapter.rxjava.HttpException;
import rx.Subscriber;
/**
* Created by WuXiaolong
* on 2016/9/22.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public abstract class ApiCallback<M> extends Subscriber<M> {
public abstract void onSuccess(M model);
public abstract void onFailure(int code, String msg);
public abstract void onFinish();
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
//httpException.response().errorBody().string()
int code = httpException.code();
String msg = httpException.getMessage();
LogUtil.d("code=" + code);
if (code == 504) {
msg = "网络不给力";
}
if (code == 502 || code == 404) {
msg = "服务器异常,请稍后再试";
}
onFailure(code, msg);
} else {
onFailure(0, e.getMessage());
}
onFinish();
}
@Override
public void onNext(M model) {
onSuccess(model);
}
@Override
public void onCompleted() {
onFinish();
}
}

View File

@ -9,6 +9,10 @@ import rx.Observable;
/**
* Created by WuXiaolong
* on 2016/3/24.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public interface ApiStores {
//baseUrl

View File

@ -11,6 +11,10 @@ import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by WuXiaolong
* on 2016/3/24.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public class AppClient {
public static Retrofit mRetrofit;

View File

@ -1,15 +0,0 @@
package com.wuxiaolong.androidmvpsample.rxjava;
/**
* Created by oliver on 16/5/7.
*/
public interface ApiCallback<T> {
void onSuccess(T model);
void onFailure(int code, String msg);
void onCompleted();
}

View File

@ -1,44 +0,0 @@
package com.wuxiaolong.androidmvpsample.rxjava;
import retrofit2.adapter.rxjava.HttpException;
import rx.Subscriber;
/**
* Created by Administrator
* on 2016/5/18.
*/
public class SubscriberCallBack<T> extends Subscriber<T> {
private ApiCallback<T> apiCallback;
public SubscriberCallBack(ApiCallback<T> apiCallback) {
this.apiCallback = apiCallback;
}
@Override
public void onCompleted() {
apiCallback.onCompleted();
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
//httpException.response().errorBody().string()
int code = httpException.code();
String msg = httpException.getMessage();
if (code == 504) {
msg = "网络不给力";
}
apiCallback.onFailure(code, msg);
} else {
apiCallback.onFailure(0, e.getMessage());
}
apiCallback.onCompleted();
}
@Override
public void onNext(T t) {
apiCallback.onSuccess(t);
}
}

View File

@ -1,6 +1,7 @@
package com.wuxiaolong.androidmvpsample.ui;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.v7.app.ActionBar;
@ -13,9 +14,15 @@ import android.widget.TextView;
import android.widget.Toast;
import com.wuxiaolong.androidmvpsample.R;
import com.wuxiaolong.androidmvpsample.retrofit.ApiStores;
import com.wuxiaolong.androidmvpsample.retrofit.AppClient;
import butterknife.ButterKnife;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
/**
@ -28,6 +35,8 @@ import rx.subscriptions.CompositeSubscription;
*/
public class BaseActivity extends AppCompatActivity {
public Activity mActivity;
public ApiStores apiStores = AppClient.retrofit().create(ApiStores.class);
private CompositeSubscription mCompositeSubscription;
@Override
public void setContentView(@LayoutRes int layoutResID) {
@ -64,7 +73,6 @@ public class BaseActivity extends AppCompatActivity {
super.onDestroy();
}
private CompositeSubscription mCompositeSubscription;
public void onUnsubscribe() {
if (mCompositeSubscription != null) {
@ -72,37 +80,31 @@ public class BaseActivity extends AppCompatActivity {
}
}
public void addSubscription(Observable observable, Subscriber subscriber) {
if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
}
mCompositeSubscription.add(observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber));
}
public void addSubscription(Subscription subscription) {
// if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
// }
if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
}
mCompositeSubscription.add(subscription);
}
public Toolbar initToolBar(String title) {
Toolbar toolbar = initToolBar();
TextView toolbar_title = (TextView) toolbar.findViewById(R.id.toolbar_title);
toolbar_title.setText(title);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
return toolbar;
}
public Toolbar initToolBar(int title) {
Toolbar toolbar = initToolBar();
TextView toolbar_title = (TextView) toolbar.findViewById(R.id.toolbar_title);
toolbar_title.setText(title);
return toolbar;
}
public Toolbar initToolBar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
TextView toolbaTitle = (TextView) toolbar.findViewById(R.id.toolbar_title);
toolbaTitle.setText(title);
}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
@ -111,6 +113,23 @@ public class BaseActivity extends AppCompatActivity {
return toolbar;
}
public Toolbar initToolBarAsHome(String title) {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
TextView toolbaTitle = (TextView) toolbar.findViewById(R.id.toolbar_title);
toolbaTitle.setText(title);
}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
}
return toolbar;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@ -132,5 +151,27 @@ public class BaseActivity extends AppCompatActivity {
Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show();
}
public ProgressDialog progressDialog;
public ProgressDialog showProgressDialog() {
progressDialog = new ProgressDialog(mActivity);
progressDialog.setMessage("加载中");
progressDialog.show();
return progressDialog;
}
public ProgressDialog showProgressDialog(CharSequence message) {
progressDialog = new ProgressDialog(mActivity);
progressDialog.setMessage(message);
progressDialog.show();
return progressDialog;
}
public void dismissProgressDialog() {
if (progressDialog != null && progressDialog.isShowing()) {
// progressDialog.hide();会导致android.view.WindowLeaked
progressDialog.dismiss();
}
}
}

View File

@ -16,7 +16,12 @@ import rx.Subscription;
import rx.subscriptions.CompositeSubscription;
/**
* A simple {@link Fragment} subclass.
* Created by WuXiaolong
* on 2015/9/23.
* github:https://github.com/WuXiaolong/
* weibo:http://weibo.com/u/2175011601
* 微信公众号吴小龙同学
* 个人博客http://wuxiaolong.me/
*/
public class BaseFragment extends Fragment {
public Activity mActivity;

View File

@ -2,17 +2,18 @@ package com.wuxiaolong.androidmvpsample.ui;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.wuxiaolong.androidmvpsample.R;
import com.wuxiaolong.androidmvpsample.mvp.MvpActivity;
import com.wuxiaolong.androidmvpsample.mvp.main.MainModel;
import com.wuxiaolong.androidmvpsample.mvp.main.MainPresenter;
import com.wuxiaolong.androidmvpsample.mvp.main.MainView;
import com.wuxiaolong.androidmvpsample.mvp.other.MvpActivity;
import com.wuxiaolong.androidmvpsample.retrofit.ApiCallback;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
/**
* 由Activity/Fragment实现View里方法包含一个Presenter的引用
@ -27,16 +28,14 @@ public class MainActivity extends MvpActivity<MainPresenter> implements MainView
@Bind(R.id.text)
TextView text;
@Bind(R.id.mProgressBar)
ProgressBar mProgressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
//请求接口
mvpPresenter.loadData("101010100");
initToolBarAsHome("MVP+Retrofit+Rxjava");
}
@Override
@ -64,13 +63,53 @@ public class MainActivity extends MvpActivity<MainPresenter> implements MainView
@Override
public void showLoading() {
mProgressBar.setVisibility(View.VISIBLE);
showProgressDialog();
}
@Override
public void hideLoading() {
mProgressBar.setVisibility(View.GONE);
dismissProgressDialog();
}
@OnClick({R.id.button1, R.id.button2})
public void onClick(View view) {
switch (view.getId()) {
case R.id.button1:
loadData();
break;
case R.id.button2:
//请求接口
mvpPresenter.loadData("101310222");
break;
}
}
//全国+国外主要城市代码http://mobile.weather.com.cn/js/citylist.xml
private void loadData() {
showProgressDialog();
addSubscription(apiStores.loadData("101190201"),
new ApiCallback<MainModel>() {
@Override
public void onSuccess(MainModel model) {
MainModel.WeatherinfoBean weatherinfo = model.getWeatherinfo();
String showData = getResources().getString(R.string.city) + weatherinfo.getCity()
+ getResources().getString(R.string.wd) + weatherinfo.getWD()
+ getResources().getString(R.string.ws) + weatherinfo.getWS()
+ getResources().getString(R.string.time) + weatherinfo.getTime();
text.setText(showData);
}
@Override
public void onFailure(int code, String msg) {
toastShow(msg);
}
@Override
public void onFinish() {
dismissProgressDialog();
}
});
}
}

View File

@ -1,21 +1,35 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
android:orientation="vertical"
tools:context=".ui.MainActivity">
<include layout="@layout/toolbar"/>
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:text="普通写法(Retrofit+Rxjava)"/>
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:text="MVP+Retrofit+Rxjava"/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/mProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
android:layout_margin="10dp"/>
</LinearLayout>

View File

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorPrimary"
android:minHeight="?actionBarSize">
<!--android:paddingTop="@dimen/status_bar_height"-->
@ -12,5 +14,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textStyle="bold" />
android:textColor="@android:color/white"
android:textStyle="bold"/>
</android.support.v7.widget.Toolbar>

View File

@ -3,7 +3,10 @@
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@android:color/holo_blue_light</item>
<item name="colorPrimaryDark">@android:color/holo_blue_light</item>
<item name="colorAccent">@android:color/holo_blue_light</item>
<item name="colorControlNormal">@android:color/white</item>
</style>
</resources>