1
0
mirror of https://github.com/WuXiaolong/AndroidMVPSample.git synced 2025-06-07 13:54:04 +08:00
This commit is contained in:
xiaomolong 2016-06-12 14:16:27 +08:00
parent 64ebcd133f
commit 436e4a9cc7
16 changed files with 303 additions and 211 deletions

1
.idea/gradle.xml generated
View File

@ -5,7 +5,6 @@
<GradleProjectSettings> <GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />

View File

@ -8,8 +8,8 @@ android {
applicationId "com.wuxiaolong.androidmvpsample" applicationId "com.wuxiaolong.androidmvpsample"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 22 targetSdkVersion 22
versionCode 1 versionCode 20
versionName "1.0" versionName "2.0"
} }
buildTypes { buildTypes {
release { release {
@ -21,8 +21,8 @@ android {
dependencies { dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:23.3.0' compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.loopj.android:android-async-http:1.4.9' compile 'com.wuxiaolong.androidutils:androidutils:1.0.2'
compile 'com.jakewharton:butterknife:7.0.1' compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.okhttp3:logging-interceptor:3.1.2' compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
@ -30,4 +30,5 @@ dependencies {
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0' compile 'io.reactivex:rxjava:1.1.0'
} }

View File

@ -3,12 +3,19 @@ package com.wuxiaolong.androidmvpsample.mvp;
import com.wuxiaolong.androidmvpsample.retrofit.ApiStores; import com.wuxiaolong.androidmvpsample.retrofit.ApiStores;
import com.wuxiaolong.androidmvpsample.retrofit.AppClient; import com.wuxiaolong.androidmvpsample.retrofit.AppClient;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
/** /**
* Created by WuXiaolong on 2016/3/30. * Created by WuXiaolong on 2016/3/30.
*/ */
public class BasePresenter<V> implements Presenter<V> { public class BasePresenter<V> implements Presenter<V> {
public ApiStores apiStores = AppClient.retrofit().create(ApiStores.class);
public V mvpView; public V mvpView;
public ApiStores apiStores = AppClient.retrofit().create(ApiStores.class);
private CompositeSubscription mCompositeSubscription;
@Override @Override
public void attachView(V mvpView) { public void attachView(V mvpView) {
@ -19,6 +26,25 @@ public class BasePresenter<V> implements Presenter<V> {
@Override @Override
public void detachView() { public void detachView() {
this.mvpView = null; this.mvpView = null;
onUnsubscribe();
}
//RXjava取消注册以避免内存泄露
public void onUnsubscribe() {
if (mCompositeSubscription != null && mCompositeSubscription.hasSubscriptions()) {
mCompositeSubscription.unsubscribe();
}
}
public void addSubscription(Observable observable, Subscriber subscriber) {
if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
}
mCompositeSubscription.add(observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber));
} }
} }

View File

@ -12,10 +12,8 @@ import com.wuxiaolong.androidmvpsample.ui.BaseFragment;
* A simple {@link Fragment} subclass. * A simple {@link Fragment} subclass.
*/ */
public abstract class MvpFragment<P extends BasePresenter> extends BaseFragment { public abstract class MvpFragment<P extends BasePresenter> extends BaseFragment {
protected P mvpPresenter; protected P mvpPresenter;
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);

View File

@ -1,11 +0,0 @@
package com.wuxiaolong.androidmvpsample.mvp.main;
/**
* Created by WuXiaolong on 2015/9/23.
* 此接口作用是连接Model
*/
public interface IMainPresenter {
void loadDataSuccess(MainModelBean mainModelBean);
void loadDataFailure();
}

View File

@ -5,49 +5,141 @@ package com.wuxiaolong.androidmvpsample.mvp.main;
* 业务具体处理包括负责存储检索操纵数据等 * 业务具体处理包括负责存储检索操纵数据等
*/ */
public class MainModel { public class MainModel {
private String city;
private String wd;
private String ws;
private String time;
public String getCity() {
return city; /**
* 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() {
return weatherinfo;
} }
public void setCity(String city) { public void setWeatherinfo(WeatherinfoBean weatherinfo) {
this.city = city; this.weatherinfo = weatherinfo;
} }
public String getWd() { public static class WeatherinfoBean {
return wd; private String city;
private String cityid;
private String temp;
private String WD;
private String WS;
private String SD;
private String WSE;
private String time;
private String isRadar;
private String Radar;
private String njd;
private String qy;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCityid() {
return cityid;
}
public void setCityid(String cityid) {
this.cityid = cityid;
}
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getWD() {
return WD;
}
public void setWD(String WD) {
this.WD = WD;
}
public String getWS() {
return WS;
}
public void setWS(String WS) {
this.WS = WS;
}
public String getSD() {
return SD;
}
public void setSD(String SD) {
this.SD = SD;
}
public String getWSE() {
return WSE;
}
public void setWSE(String WSE) {
this.WSE = WSE;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getIsRadar() {
return isRadar;
}
public void setIsRadar(String isRadar) {
this.isRadar = isRadar;
}
public String getRadar() {
return Radar;
}
public void setRadar(String Radar) {
this.Radar = Radar;
}
public String getNjd() {
return njd;
}
public void setNjd(String njd) {
this.njd = njd;
}
public String getQy() {
return qy;
}
public void setQy(String qy) {
this.qy = qy;
}
} }
public void setWd(String wd) {
this.wd = wd;
}
public String getWs() {
return ws;
}
public void setWs(String ws) {
this.ws = ws;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
private IMainPresenter mIMainPresenter;
public MainModel(IMainPresenter iMainPresenter) {
this.mIMainPresenter = iMainPresenter;
}
} }

View File

@ -1,43 +0,0 @@
package com.wuxiaolong.androidmvpsample.mvp.main;
/**
* Created by WuXiaolong on 2015/9/23.
*/
public class MainModelBean {
private String city;
private String wd;
private String ws;
private String time;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getWd() {
return wd;
}
public void setWd(String wd) {
this.wd = wd;
}
public String getWs() {
return ws;
}
public void setWs(String ws) {
this.ws = ws;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}

View File

@ -1,20 +1,39 @@
package com.wuxiaolong.androidmvpsample.mvp.main; package com.wuxiaolong.androidmvpsample.mvp.main;
import com.wuxiaolong.androidmvpsample.mvp.BasePresenter; import com.wuxiaolong.androidmvpsample.mvp.BasePresenter;
import com.wuxiaolong.androidmvpsample.rxjava.ApiCallback;
import com.wuxiaolong.androidmvpsample.rxjava.SubscriberCallBack;
/** /**
* Created by WuXiaolong on 2015/9/23. * Created by WuXiaolong
* View和Model的桥梁它从Model层检索数据后返回给View层 * on 2015/9/23.
*/ */
public class MainPresenter extends BasePresenter { public class MainPresenter extends BasePresenter<MainView> {
public MainPresenter(MainView view) { public MainPresenter(MainView view) {
attachView(view); attachView(view);
} }
public void loadData() { public void loadData(String cityId) {
mvpView.showLoading();
addSubscription(apiStores.loadData(cityId),
new SubscriberCallBack<>(new ApiCallback<MainModel>() {
@Override
public void onSuccess(MainModel model) {
mvpView.getDataSuccess(model);
}
@Override
public void onFailure(int code, String msg) {
mvpView.getDataFail(msg);
}
@Override
public void onCompleted() {
mvpView.hideLoading();
}
}));
} }
} }

View File

@ -10,7 +10,7 @@ public interface MainView {
void getDataFail(String msg); void getDataFail(String msg);
void showProgress(); void showLoading();
void hideProgress(); void hideLoading();
} }

View File

@ -1,10 +1,20 @@
package com.wuxiaolong.androidmvpsample.retrofit; package com.wuxiaolong.androidmvpsample.retrofit;
import com.wuxiaolong.androidmvpsample.mvp.main.MainModel;
import retrofit2.http.GET;
import retrofit2.http.Path;
import rx.Observable;
/** /**
* Created by WuXiaolong * Created by WuXiaolong
* on 2016/3/24. * on 2016/3/24.
*/ */
public interface ApiStores { public interface ApiStores {
String API_SERVER_URL = "http://www.smlxt.com/supplier/supplier/app/"; //baseUrl
String API_SERVER_URL = "http://www.weather.com.cn/";
//加载天气
@GET("adat/sk/{cityId}.html")
Observable<MainModel> loadData(@Path("cityId") String cityId);
} }

View File

@ -1,5 +1,9 @@
package com.wuxiaolong.androidmvpsample.retrofit; package com.wuxiaolong.androidmvpsample.retrofit;
import com.wuxiaolong.androidmvpsample.BuildConfig;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.gson.GsonConverterFactory;
@ -13,10 +17,21 @@ public class AppClient {
public static Retrofit retrofit() { public static Retrofit retrofit() {
if (mRetrofit == null) { if (mRetrofit == null) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
// Log信息拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//设置 Debug Log 模式
builder.addInterceptor(loggingInterceptor);
}
OkHttpClient okHttpClient = builder.build();
mRetrofit = new Retrofit.Builder() mRetrofit = new Retrofit.Builder()
.baseUrl(ApiStores.API_SERVER_URL) .baseUrl(ApiStores.API_SERVER_URL)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build(); .build();
} }
return mRetrofit; return mRetrofit;

View File

@ -0,0 +1,15 @@
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

@ -0,0 +1,44 @@
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

@ -2,25 +2,14 @@ package com.wuxiaolong.androidmvpsample.ui;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.smlxt.lxts.R; import com.wuxiaolong.androidmvpsample.R;
import com.smlxt.lxts.ui.login.LoginActivity;
import com.smlxt.lxts.utils.ActivityManager;
import com.smlxt.lxts.utils.AppConstants;
import com.smlxt.lxts.utils.LogUtil;
import com.smlxt.lxts.utils.SharedPreferencesUtil;
import com.smlxt.lxts.view.CustomLoading;
import com.umeng.analytics.MobclickAgent;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import rx.Subscription; import rx.Subscription;
@ -31,14 +20,7 @@ import rx.subscriptions.CompositeSubscription;
*/ */
public class BaseFragment extends Fragment { public class BaseFragment extends Fragment {
public Activity mActivity; public Activity mActivity;
public String TAG = "wxl";
public ProgressDialog progressDialog;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_base, container, false);
}
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
@ -55,11 +37,6 @@ public class BaseFragment extends Fragment {
} }
// @Override
// public void onDestroy() {
// super.onDestroy();
// Log.d(TAG, mActivity + "=onDestroy");
// }
public void toastShow(int resId) { public void toastShow(int resId) {
Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show(); Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show();
} }
@ -68,47 +45,6 @@ public class BaseFragment extends Fragment {
Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show(); Toast.makeText(mActivity, resId, Toast.LENGTH_SHORT).show();
} }
CustomLoading customLoading;
public CustomLoading showProgressDialog() {
// progressDialog = new ProgressDialog(mActivity);
// progressDialog.setMessage("加载中");
// progressDialog.show();
// return progressDialog;
customLoading = new CustomLoading(mActivity, R.style.CustomDialog);
customLoading.show();
return customLoading;
}
public void dismissProgressDialog() {
if (customLoading != null && customLoading.isShowing()) {
customLoading.dismiss();
}
// if (progressDialog != null && progressDialog.isShowing()) {
// progressDialog.dismiss();// progressDialog.hide();会导致android.view.WindowLeaked
// }
}
public void startLogin() {
toastShow("登陆超时,请重新登录");
SharedPreferencesUtil.setString(mActivity, AppConstants.USER_PASSWORD, "");
ActivityManager.getInstance().finishAllActivity();
mActivity.startActivity(new Intent(mActivity, LoginActivity.class));
}
@Override
public void onResume() {
super.onResume();
LogUtil.d("BaseFragment onResume=" + this.getClass().getSimpleName());
MobclickAgent.onPageStart(this.getClass().getSimpleName()); //统计页面"MainScreen"为页面名称可自定义
}
@Override
public void onPause() {
super.onPause();
MobclickAgent.onPageEnd(this.getClass().getSimpleName());
}
@Override @Override
public void onDestroy() { public void onDestroy() {
@ -119,8 +55,9 @@ public class BaseFragment extends Fragment {
private CompositeSubscription mCompositeSubscription; private CompositeSubscription mCompositeSubscription;
public void onUnsubscribe() { public void onUnsubscribe() {
//取消注册以避免内存泄露
if (mCompositeSubscription != null) { if (mCompositeSubscription != null) {
mCompositeSubscription.unsubscribe();//取消注册以避免内存泄露 mCompositeSubscription.unsubscribe();
} }
} }

View File

@ -1,33 +1,37 @@
package com.wuxiaolong.androidmvpsample.ui; package com.wuxiaolong.androidmvpsample.ui;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.view.View; import android.view.View;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import com.wuxiaolong.androidmvpsample.R; import com.wuxiaolong.androidmvpsample.R;
import com.wuxiaolong.androidmvpsample.mvp.MvpActivity; import com.wuxiaolong.androidmvpsample.mvp.MvpActivity;
import com.wuxiaolong.androidmvpsample.mvp.main.MainModelBean; import com.wuxiaolong.androidmvpsample.mvp.main.MainModel;
import com.wuxiaolong.androidmvpsample.mvp.main.MainPresenter; import com.wuxiaolong.androidmvpsample.mvp.main.MainPresenter;
import com.wuxiaolong.androidmvpsample.mvp.main.MainView; import com.wuxiaolong.androidmvpsample.mvp.main.MainView;
import butterknife.Bind;
import butterknife.ButterKnife;
/** /**
* Created by WuXiaolong on 2015/9/23. * Created by WuXiaolong on 2015/9/23.
* 由Activity/Fragment实现View里方法包含一个Presenter的引用 * 由Activity/Fragment实现View里方法包含一个Presenter的引用
*/ */
public class MainActivity extends MvpActivity<MainPresenter> implements MainView { public class MainActivity extends MvpActivity<MainPresenter> implements MainView {
private ProgressBar mProgressBar;
private TextView text; @Bind(R.id.text)
private MainPresenter mMainPresenter; TextView text;
private Handler mHandler = new Handler(); @Bind(R.id.mProgressBar)
ProgressBar mProgressBar;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
initView(); ButterKnife.bind(this);
//请求接口
mvpPresenter.loadData("101010100");
} }
@Override @Override
@ -36,44 +40,30 @@ public class MainActivity extends MvpActivity<MainPresenter> implements MainView
} }
private void initView() {
text = (TextView) findViewById(R.id.text);
mProgressBar = (ProgressBar) findViewById(R.id.mProgressBar);
mMainPresenter = new MainPresenter(this);
//制造延迟效果
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mMainPresenter.loadData();
}
}, 2000);
}
@Override @Override
protected void onDestroy() { public void getDataSuccess(MainModel model) {
super.onDestroy(); //接口成功回调
mHandler.removeCallbacksAndMessages(null); MainModel.WeatherinfoBean weatherinfo = model.getWeatherinfo();
mMainPresenter.detachView(); String showData = getResources().getString(R.string.city) + weatherinfo.getCity()
} + getResources().getString(R.string.wd) + weatherinfo.getWD()
+ getResources().getString(R.string.ws) + weatherinfo.getWS()
@Override + getResources().getString(R.string.time) + weatherinfo.getTime();
public void showData(MainModelBean mainModelBean) {
String showData = getResources().getString(R.string.city) + mainModelBean.getCity()
+ getResources().getString(R.string.wd) + mainModelBean.getWd()
+ getResources().getString(R.string.ws) + mainModelBean.getWs()
+ getResources().getString(R.string.time) + mainModelBean.getTime();
text.setText(showData); text.setText(showData);
} }
@Override
public void getDataFail(String msg) {
toastShow("网络不给力");
}
@Override @Override
public void showProgress() { public void showLoading() {
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);
} }
@Override @Override
public void hideProgress() { public void hideLoading() {
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
} }

View File

@ -5,7 +5,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.1.0' classpath 'com.android.tools.build:gradle:2.1.2'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files