提交 0f559893 编写于 作者: J jessyan

improve basemodel

上级 41f93909
......@@ -136,6 +136,7 @@ Name: Contract
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import com.jess.arms.mvp.BaseView;
import com.jess.arms.mvp.IModel;
/**
* 通过Template生成对应页面的MVP和Dagger代码,请注意输入框中输入的名字必须相同
......@@ -154,7 +155,7 @@ public interface ${NAME}Contract {
}
//Model层定义接口,外部只需关心model返回的数据,无需关心内部细节,及是否使用缓存
interface Model {
interface Model extends IModel{
}
}
......
......@@ -52,6 +52,15 @@ public class WEApplication extends BaseApplication {
}
@Override
public void onTerminate() {
super.onTerminate();
if (mAppComponent != null)
this.mAppComponent = null;
if (mRefWatcher != null)
this.mRefWatcher = null;
}
/**
* 安装leakCanary检测内存泄露
*/
......
......@@ -3,6 +3,7 @@ package me.jessyan.mvparms.demo.di.component;
import android.app.Application;
import com.google.gson.Gson;
import com.jess.arms.base.AppManager;
import com.jess.arms.di.module.AppModule;
import com.jess.arms.di.module.ClientModule;
import com.jess.arms.di.module.ImageModule;
......@@ -46,4 +47,7 @@ public interface AppComponent {
//gson
Gson gson();
//用于管理所有activity
AppManager appManager();
}
......@@ -2,6 +2,7 @@ package me.jessyan.mvparms.demo.mvp.contract;
import com.jess.arms.base.DefaultAdapter;
import com.jess.arms.mvp.BaseView;
import com.jess.arms.mvp.IModel;
import java.util.List;
......@@ -20,7 +21,7 @@ public interface UserContract {
void endLoadMore();
}
//Model层定义接口,外部只需关心model返回的数据,无需关心内部细节,及是否使用缓存
interface Model {
interface Model extends IModel{
Observable<List<User>> getUsers(int lastIdQueried, boolean update);
}
}
......@@ -9,8 +9,6 @@ import io.rx_cache.EvictDynamicKey;
import io.rx_cache.Reply;
import me.jessyan.mvparms.demo.mvp.contract.UserContract;
import me.jessyan.mvparms.demo.mvp.model.api.cache.CacheManager;
import me.jessyan.mvparms.demo.mvp.model.api.cache.CommonCache;
import me.jessyan.mvparms.demo.mvp.model.api.service.CommonService;
import me.jessyan.mvparms.demo.mvp.model.api.service.ServiceManager;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import rx.Observable;
......@@ -20,27 +18,23 @@ import rx.functions.Func1;
* Created by jess on 9/4/16 10:56
* Contact with jess.yan.effort@gmail.com
*/
public class UserModel extends BaseModel<ServiceManager,CacheManager> implements UserContract.Model{
public class UserModel extends BaseModel<ServiceManager, CacheManager> implements UserContract.Model {
public static final int USERS_PER_PAGE = 10;
private CommonService mCommonService;
private CommonCache mCommonCache;
public UserModel(ServiceManager serviceManager, CacheManager cacheManager) {
super(serviceManager, cacheManager);
this.mCommonService = mServiceManager.getCommonService();
this.mCommonCache = mCacheManager.getCommonCache();
}
@Override
public Observable<List<User>> getUsers(int lastIdQueried, boolean update) {
Observable<List<User>> users = mCommonService
Observable<List<User>> users = mServiceManager.getCommonService()
.getUsers(lastIdQueried, USERS_PER_PAGE);
//使用rxcache缓存,上拉刷新则不读取缓存,加载更多读取缓存
return mCommonCache
return mCacheManager.getCommonCache()
.getUsers(users
,new DynamicKey(lastIdQueried)
,new EvictDynamicKey(update))
, new DynamicKey(lastIdQueried)
, new EvictDynamicKey(update))
.flatMap(new Func1<Reply<List<User>>, Observable<List<User>>>() {
@Override
public Observable<List<User>> call(Reply<List<User>> listReply) {
......@@ -48,4 +42,5 @@ public class UserModel extends BaseModel<ServiceManager,CacheManager> implements
}
});
}
}
......@@ -10,7 +10,7 @@ import javax.inject.Singleton;
* Contact with jess.yan.effort@gmail.com
*/
@Singleton
public class CacheManager extends BaseCacheManager {
public class CacheManager implements BaseCacheManager {
private CommonCache mCommonCache;
/**
......@@ -26,4 +26,12 @@ public class CacheManager extends BaseCacheManager {
public CommonCache getCommonCache() {
return mCommonCache;
}
/**
* 这里可以释放一些资源(注意这里是单例,即不需要在activity的生命周期调用)
*/
@Override
public void onDestory() {
}
}
......@@ -10,7 +10,7 @@ import javax.inject.Singleton;
* contact with jess.yan.effort@gmail.com
*/
@Singleton
public class ServiceManager extends BaseServiceManager {
public class ServiceManager implements BaseServiceManager {
private CommonService mCommonService;
/**
......@@ -25,4 +25,12 @@ public class ServiceManager extends BaseServiceManager {
public CommonService getCommonService() {
return mCommonService;
}
/**
* 这里可以释放一些资源(注意这里是单例,即不需要在activity的生命周期调用)
*/
@Override
public void onDestory() {
}
}
......@@ -20,4 +20,10 @@ public abstract class WEActivity<P extends BasePresenter> extends BaseActivity<P
//提供AppComponent(提供所有的单例对象)给子类,进行Component依赖
protected abstract void setupActivityComponent(AppComponent appComponent);
@Override
protected void onDestroy() {
super.onDestroy();
this.mWeApplication = null;
}
}
......@@ -29,5 +29,6 @@ public abstract class WEFragment<P extends BasePresenter> extends BaseFragment<P
if (watcher != null) {
watcher.watch(this);
}
this.mWeApplication =null;
}
}
package com.jess.arms.base;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Message;
import org.simple.eventbus.EventBus;
import org.simple.eventbus.Subscriber;
import java.util.LinkedList;
import java.util.List;
import timber.log.Timber;
/**
* 用于管理所有activity
* 可以通过直接持有AppManager对象执行对应方法
* 也可以通过eventbus post事件,远程遥控执行对应方法
* Created by jess on 14/12/2016 13:50
* Contact with jess.yan.effort@gmail.com
*/
public class AppManager {
protected final String TAG = this.getClass().getSimpleName();
public static final String APPMANAGER_MESSAGE = "appmanager_message";
public static final int START_ACTIVITY = 0;
public static final int SHOW_SNACKBAR = 1;
public static final int KILL_ALL = 2;
public static final int APP_EXIT = 3;
private Application mApplication;
//管理所有activity
public List<BaseActivity> mActivityList;
//当前在前台的activity
private BaseActivity mCurrentActivity;
public AppManager(Application application) {
this.mApplication = application;
EventBus.getDefault().register(this);
}
/**
* 通过eventbus post事件,远程遥控执行对应方法
*/
@Subscriber(tag = APPMANAGER_MESSAGE)
public void onReceive(Message message){
switch (message.what){
case START_ACTIVITY:
startActivity((Intent) message.obj);
break;
case SHOW_SNACKBAR:
break;
case KILL_ALL:
killAll();
break;
case APP_EXIT:
AppExit();
break;
}
}
/**
* 让在前台的activity,打开下一个activity
* @param intent
*/
public void startActivity(Intent intent) {
if (getCurrentActivity()!=null){
getCurrentActivity().startActivity(intent);
}
}
/**
* 让在前台的activity,打开下一个activity
* @param activityClass
*/
public void startActivity(Class activityClass) {
if (getCurrentActivity()!=null){
getCurrentActivity().startActivity(new Intent(mApplication,activityClass));
}
}
/**
* 释放资源
*/
public void release() {
EventBus.getDefault().unregister(this);
mActivityList.clear();
mActivityList = null;
mCurrentActivity = null;
mApplication = null;
}
/**
* 将在前台的activity保存
*
* @param currentActivity
*/
public void setCurrentActivity(BaseActivity currentActivity) {
this.mCurrentActivity = currentActivity;
}
/**
* 获得当前在前台的activity
* @return
*/
public BaseActivity getCurrentActivity() {
return mCurrentActivity;
}
/**
* 返回一个存储所有未销毁的activity的集合
*
* @return
*/
public List<BaseActivity> getActivityList() {
if (mActivityList == null) {
mActivityList = new LinkedList<>();
}
return mActivityList;
}
/**
* 添加Activity到集合
*/
public void addActivity(BaseActivity activity) {
if (mActivityList == null) {
mActivityList = new LinkedList<>();
}
synchronized (AppManager.class) {
if (!mActivityList.contains(activity)) {
mActivityList.add(activity);
}
}
}
/**
* 删除集合里的指定activity
*
* @param activity
*/
public void removeActivity(BaseActivity activity) {
if (mActivityList == null) {
Timber.tag(TAG).w("mActivityList == null when removeActivity(BaseActivity)");
return;
}
synchronized (AppManager.class) {
if (mActivityList.contains(activity)) {
mActivityList.remove(activity);
}
}
}
/**
* 删除集合里的指定位置的activity
*
* @param location
*/
public BaseActivity removeActivity(int location) {
if (mActivityList == null) {
Timber.tag(TAG).w("mActivityList == null when removeActivity(int)");
return null;
}
synchronized (AppManager.class) {
if (location > 0 && location < mActivityList.size()) {
return mActivityList.remove(location);
}
}
return null;
}
/**
* 关闭指定activity
*
* @param activityClass
*/
public void killActivity(Class<?> activityClass) {
if (mActivityList == null) {
Timber.tag(TAG).w("mActivityList == null when killActivity");
return;
}
for (BaseActivity activity : mActivityList) {
if (activity.getClass().equals(activityClass)) {
activity.finish();
}
}
}
/**
* 指定的activity实例是否存活
*
* @param activity
* @return
*/
public boolean activityInstanceIsLive(BaseActivity activity) {
if (mActivityList == null) {
Timber.tag(TAG).w("mActivityList == null when activityInstanceIsLive");
return false;
}
return mActivityList.contains(activity);
}
/**
* 指定的activity class是否存活(一个activity可能有多个实例)
*
* @param activityClass
* @return
*/
public boolean activityClassIsLive(Class<?> activityClass) {
if (mActivityList == null) {
Timber.tag(TAG).w("mActivityList == null when activityClassIsLive");
return false;
}
for (BaseActivity activity : mActivityList) {
if (activity.getClass().equals(activityClass)) {
return true;
}
}
return false;
}
/**
* 关闭所有activity
*/
public void killAll() {
LinkedList<BaseActivity> copy;
synchronized (AppManager.class) {
copy = new LinkedList<>(getActivityList());
}
for (BaseActivity baseActivity : copy) {
baseActivity.finish();
}
}
/**
* 退出应用程序
*/
public void AppExit() {
try {
killAll();
ActivityManager activityMgr =
(ActivityManager) mApplication.getSystemService(Context.ACTIVITY_SERVICE);
activityMgr.killBackgroundProcesses(mApplication.getPackageName());
System.exit(0);
} catch (Exception e) {
}
}
}
......@@ -3,7 +3,6 @@ package com.jess.arms.base;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
......@@ -19,8 +18,6 @@ import com.zhy.autolayout.AutoRelativeLayout;
import org.simple.eventbus.EventBus;
import java.util.LinkedList;
import javax.inject.Inject;
import butterknife.ButterKnife;
......@@ -65,13 +62,15 @@ public abstract class BaseActivity<P extends BasePresenter> extends RxAppCompatA
@Override
protected void onResume() {
super.onResume();
registReceiver();//注册广播
mApplication.getAppManager().setCurrentActivity(this);
}
@Override
protected void onPause() {
super.onPause();
unregistReceriver();
if (mApplication.getAppManager().getCurrentActivity() == this) {
mApplication.getAppManager().setCurrentActivity(null);
}
}
@Nullable
......@@ -81,11 +80,13 @@ public abstract class BaseActivity<P extends BasePresenter> extends RxAppCompatA
mApplication = (BaseApplication) getApplication();
//如果intent包含了此字段,并且为true说明不加入到list
// 默认为false,如果不需要管理(比如不需要在退出所有activity(killAll)时,退出此activity就在intent加此字段为true)
boolean isNotAdd = getIntent().getBooleanExtra(IS_NOT_ADD_ACTIVITY_LIST, false);
synchronized (BaseActivity.class) {
if (!isNotAdd)
mApplication.getActivityList().add(this);
}
boolean isNotAdd = false;
if (getIntent() != null)
getIntent().getBooleanExtra(IS_NOT_ADD_ACTIVITY_LIST, false);
if (!isNotAdd)
mApplication.getAppManager().addActivity(this);
if (useEventBus())//如果要使用eventbus请将此方法返回true
EventBus.getDefault().register(this);//注册到事件主线
setContentView(initView());
......@@ -117,13 +118,14 @@ public abstract class BaseActivity<P extends BasePresenter> extends RxAppCompatA
@Override
protected void onDestroy() {
super.onDestroy();
synchronized (BaseActivity.class) {
mApplication.getActivityList().remove(this);
}
mApplication.getAppManager().removeActivity(this);
if (mPresenter != null) mPresenter.onDestroy();//释放资源
if (mUnbinder != Unbinder.EMPTY) mUnbinder.unbind();
if (useEventBus())//如果要使用eventbus请将此方法返回true
EventBus.getDefault().unregister(this);
this.mPresenter = null;
this.mUnbinder = null;
this.mApplication = null;
}
/**
......@@ -141,32 +143,6 @@ public abstract class BaseActivity<P extends BasePresenter> extends RxAppCompatA
super.onBackPressed();
}
/**
* 注册广播
*/
public void registReceiver() {
try {
mBroadcastReceiver = new ActivityReceriver();
IntentFilter filter = new IntentFilter(ACTION_RECEIVER_ACTIVITY);
registerReceiver(mBroadcastReceiver, filter);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解除注册广播
*/
public void unregistReceriver() {
if (mBroadcastReceiver == null) return;
try {
unregisterReceiver(mBroadcastReceiver);
} catch (Exception e) {
e.printStackTrace();
}
}
protected abstract View initView();
......@@ -191,13 +167,13 @@ public abstract class BaseActivity<P extends BasePresenter> extends RxAppCompatA
Snackbar.make(view, text, isLong ? Snackbar.LENGTH_LONG : Snackbar.LENGTH_SHORT).show();
break;
case "killAll":
LinkedList<BaseActivity> copy;
synchronized (BaseActivity.class) {
copy = new LinkedList<BaseActivity>(mApplication.getActivityList());
}
for (BaseActivity baseActivity : copy) {
baseActivity.finish();
}
// LinkedList<BaseActivity> copy;
// synchronized (BaseActivity.class) {
// copy = new LinkedList<BaseActivity>(mApplication.getActivityList());
// }
// for (BaseActivity baseActivity : copy) {
// baseActivity.finish();
// }
// android.os.Process.killProcess(android.os.Process.myPid());
break;
}
......
......@@ -4,12 +4,14 @@ import android.app.Application;
import android.content.Context;
import android.content.Intent;
import com.jess.arms.di.component.DaggerBaseComponent;
import com.jess.arms.di.module.AppModule;
import com.jess.arms.di.module.BaseModule;
import com.jess.arms.di.module.ClientModule;
import com.jess.arms.di.module.ImageModule;
import com.jess.arms.http.GlobeHttpHandler;
import java.util.LinkedList;
import javax.inject.Inject;
import me.jessyan.rxerrorhandler.handler.listener.ResponseErroListener;
import okhttp3.Interceptor;
......@@ -25,10 +27,11 @@ import okhttp3.Interceptor;
*/
public abstract class BaseApplication extends Application {
static private BaseApplication mApplication;
public LinkedList<BaseActivity> mActivityList;
private ClientModule mClientModule;
private AppModule mAppModule;
private ImageModule mImagerModule;
@Inject
protected AppManager mAppManager;
protected final String TAG = this.getClass().getSimpleName();
......@@ -36,6 +39,11 @@ public abstract class BaseApplication extends Application {
public void onCreate() {
super.onCreate();
mApplication = this;
DaggerBaseComponent
.builder()
.baseModule(new BaseModule(this))
.build()
.inject(this);
this.mClientModule = ClientModule//用于提供okhttp和retrofit的单列
.buidler()
.baseurl(getBaseUrl())
......@@ -43,30 +51,37 @@ public abstract class BaseApplication extends Application {
.interceptors(getInterceptors())
.responseErroListener(getResponseErroListener())
.build();
this.mAppModule = new AppModule(this);//提供application
this.mAppModule = new AppModule(this, mAppManager);//提供application
this.mImagerModule = new ImageModule();//图片加载框架默认使用glide
}
}
/**
* 提供基础url给retrofit
*
* @return
* 程序终止的时候执行
*/
protected abstract String getBaseUrl();
@Override
public void onTerminate() {
super.onTerminate();
if (mClientModule != null)
this.mClientModule = null;
if (mAppModule != null)
this.mAppModule = null;
if (mImagerModule != null)
this.mImagerModule = null;
if (mAppManager != null) {//释放资源
this.mAppManager.release();
this.mAppManager = null;
}
if (mApplication != null)
this.mApplication = null;
}
/**
* 返回一个存储所有存在的activity的列表
* 提供基础url给retrofit
*
* @return
*/
public LinkedList<BaseActivity> getActivityList() {
if (mActivityList == null) {
mActivityList = new LinkedList<BaseActivity>();
}
return mActivityList;
}
protected abstract String getBaseUrl();
public ClientModule getClientModule() {
......@@ -82,6 +97,10 @@ public abstract class BaseApplication extends Application {
}
public AppManager getAppManager() {
return mAppManager;
}
/**
* 这里可以提供一个全局处理http响应结果的处理类,
* 这里可以比客户端提前一步拿到服务器返回的结果,可以做一些操作,比如token超时,重新获取
......@@ -107,6 +126,7 @@ public abstract class BaseApplication extends Application {
* 用来提供处理所有错误的监听
* 如果要使用ErrorHandleSubscriber(默认实现Subscriber的onError方法)
* 则让子application重写此方法
*
* @return
*/
protected ResponseErroListener getResponseErroListener() {
......
......@@ -64,6 +64,10 @@ public abstract class BaseFragment<P extends BasePresenter> extends RxFragment {
if (mPresenter != null) mPresenter.onDestroy();//释放资源
if (useEventBus())//如果要使用eventbus请将此方法返回true
EventBus.getDefault().unregister(this);
this.mPresenter = null;
this.mActivity = null;
this.mRootView = null;
this.mUnbinder = null;
}
/**
......
package com.jess.arms.di.component;
import com.jess.arms.base.BaseApplication;
import com.jess.arms.di.module.BaseModule;
import javax.inject.Singleton;
import dagger.Component;
/**
* Created by jess on 14/12/2016 13:58
* Contact with jess.yan.effort@gmail.com
*/
@Singleton
@Component(modules={BaseModule.class})
public interface BaseComponent {
void inject(BaseApplication application);
}
......@@ -3,6 +3,7 @@ package com.jess.arms.di.module;
import android.app.Application;
import com.google.gson.Gson;
import com.jess.arms.base.AppManager;
import javax.inject.Singleton;
......@@ -15,9 +16,11 @@ import dagger.Provides;
@Module
public class AppModule {
private Application mApplication;
private AppManager mAppManager;
public AppModule(Application application) {
public AppModule(Application application, AppManager appManager) {
this.mApplication = application;
this.mAppManager = appManager;
}
@Singleton
......@@ -29,4 +32,8 @@ public class AppModule {
@Singleton
@Provides
public Gson provideGson(){return new Gson();}
@Singleton
@Provides
public AppManager provideAppManager(){return mAppManager;}
}
package com.jess.arms.di.module;
import android.app.Application;
import com.jess.arms.base.AppManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
/**
* Created by jess on 14/12/2016 13:54
* Contact with jess.yan.effort@gmail.com
*/
@Module
public class BaseModule {
private Application mApplication;
public BaseModule(Application application) {
this.mApplication = application;
}
@Singleton
@Provides
public AppManager provideAppManager(){ return new AppManager(mApplication);}
}
......@@ -4,5 +4,6 @@ package com.jess.arms.http;
* Created by jess on 8/30/16 16:00
* Contact with jess.yan.effort@gmail.com
*/
public abstract class BaseCacheManager {
public interface BaseCacheManager {
void onDestory();
}
......@@ -4,6 +4,7 @@ package com.jess.arms.http;
* Created by jess on 8/30/16 15:59
* Contact with jess.yan.effort@gmail.com
*/
public abstract class BaseServiceManager {
public interface BaseServiceManager {
void onDestory();
}
......@@ -7,7 +7,7 @@ import com.jess.arms.http.BaseServiceManager;
* Created by jess on 8/5/16 12:55
* contact with jess.yan.effort@gmail.com
*/
public class BaseModel<S extends BaseServiceManager, C extends BaseCacheManager> {
public class BaseModel<S extends BaseServiceManager, C extends BaseCacheManager> implements IModel{
protected S mServiceManager;//服务管理类,用于网络请求
protected C mCacheManager;//缓存管理类,用于管理本地或者内存缓存
......@@ -16,8 +16,13 @@ public class BaseModel<S extends BaseServiceManager, C extends BaseCacheManager>
this.mCacheManager = cacheManager;
}
@Override
public void onDestory() {
mServiceManager = null;
mCacheManager = null;
if (mServiceManager != null) {
mServiceManager = null;
}
if (mCacheManager != null) {
mCacheManager = null;
}
}
}
......@@ -8,7 +8,7 @@ import rx.subscriptions.CompositeSubscription;
/**
* Created by jess on 16/4/28.
*/
public class BasePresenter<M, V extends BaseView> implements presenter {
public class BasePresenter<M extends IModel, V extends BaseView> implements presenter {
protected final String TAG = this.getClass().getSimpleName();
protected CompositeSubscription mCompositeSubscription;
......@@ -43,12 +43,12 @@ public class BasePresenter<M, V extends BaseView> implements presenter {
if (useEventBus())//如果要使用eventbus请将此方法返回true
EventBus.getDefault().unregister(this);//解除注册eventbus
unSubscribe();//解除订阅
this.mModel = null;
if (mModel != null) {
mModel.onDestory();
this.mModel = null;
}
this.mRootView = null;
}
protected void handleError(Throwable throwable) {
this.mCompositeSubscription = null;
}
/**
......
package com.jess.arms.mvp;
/**
* Created by jess on 15/12/2016 10:45
* Contact with jess.yan.effort@gmail.com
*/
public interface IModel {
void onDestory();
}
......@@ -6,7 +6,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Message;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
......@@ -24,8 +24,13 @@ import android.widget.Toast;
import com.jess.arms.base.BaseActivity;
import com.jess.arms.base.BaseApplication;
import org.simple.eventbus.EventBus;
import java.security.MessageDigest;
import static com.jess.arms.base.AppManager.APPMANAGER_MESSAGE;
import static com.jess.arms.base.AppManager.START_ACTIVITY;
/**
* Created by jess on 2015/11/23.
*/
......@@ -265,12 +270,18 @@ public class UiUtils {
* @param
*/
public static void startActivity(Intent content) {
Intent intent = new Intent(BaseActivity.ACTION_RECEIVER_ACTIVITY);
intent.putExtra("type", "startActivity");
Bundle bundle = new Bundle();
bundle.putParcelable("content", content);
intent.putExtras(bundle);
getContext().sendBroadcast(intent);
// Intent intent = new Intent(BaseActivity.ACTION_RECEIVER_ACTIVITY);
// intent.putExtra("type", "startActivity");
// Bundle bundle = new Bundle();
// bundle.putParcelable("content", content);
// intent.putExtras(bundle);
// getContext().sendBroadcast(intent);
Message message = new Message();
message.what = START_ACTIVITY;
message.obj = content;
EventBus.getDefault().post(message,APPMANAGER_MESSAGE);
}
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册