淺談Android中MVP模式的運(yùn)用

演示效果:

MVP設(shè)計(jì)模式演示.gif

這里的演示效果是利用TabLayout+ViewPager+Fragment完成的,由于本篇文章不是講具體實(shí)現(xiàn),所以和MVP思想不相關(guān)的具體實(shí)現(xiàn)代碼我會(huì)忽略一部分。

前言

MVP開發(fā)模式,算是老生常談的話題了,最近一段時(shí)間也比較熱門,網(wǎng)上相關(guān)的資料不少,這里就不再做重復(fù)的描述。
這里談一下個(gè)人的一些理解:


mvc模式.png

由于Android平臺(tái)的特殊性,從MVC的角度來(lái)講,XML布局文件作為視圖層(V),Activity作為控制層(C),一些具體的業(yè)務(wù)操作,如讀寫數(shù)據(jù)庫(kù),網(wǎng)絡(luò)訪問(wèn)等作為業(yè)務(wù)邏輯層(M),單純的XML布局又不能滿足V層的需要,例如我們需要對(duì)一個(gè)控件進(jìn)行動(dòng)態(tài)的隱藏和顯示,這點(diǎn)單純的XML是辦不到的,此時(shí)我們只能在Activity里去做實(shí)現(xiàn)了,這樣子下來(lái),使得Activity既是V又是C,隨著業(yè)務(wù)的擴(kuò)展,代碼邏輯也漸漸變得復(fù)雜起來(lái),加上MVC模式的設(shè)計(jì),Model層和View層又是直接交互的,導(dǎo)致Activity的職責(zé)會(huì)變得很重,慢慢的變得臃腫不堪,不易擴(kuò)展,更不要提測(cè)試了。

mvp模式.png

既然有問(wèn)題的存在,自然就有解決問(wèn)題的辦法,此時(shí)MVP出現(xiàn)了,在我看來(lái)MVP模式其實(shí)就是從并不標(biāo)準(zhǔn)的MVC模式演化而來(lái)的,它減輕了Activity的職責(zé),簡(jiǎn)化了Activity的代碼,把復(fù)雜的邏輯交給了P層來(lái)處理,較低了系統(tǒng)的耦合度,更加方便了測(cè)試。

這樣的開發(fā)模式下來(lái),也使得各層的職責(zé)更加單一了,V層只關(guān)心用戶的輸入請(qǐng)求動(dòng)作,P層相當(dāng)于V層和M層的“信使”只關(guān)心轉(zhuǎn)發(fā)數(shù)據(jù),來(lái)自V層的請(qǐng)求數(shù)據(jù),來(lái)自M層的響應(yīng)數(shù)據(jù),而M層則只需要關(guān)心的具體的業(yè)務(wù)邏輯操作即可。

言歸正傳

說(shuō)了這么多,來(lái)點(diǎn)實(shí)戰(zhàn)吧,這里我演示一個(gè)比較常見(jiàn)的功能,列表的下拉刷新和上拉加載數(shù)據(jù)。

所涉及的開源框架:
網(wǎng)絡(luò)加載框架:Retrofit
圖片加載框架:Picasso
響應(yīng)式編程框架:Rxjava
注解框架:ButterKnife
帶有下拉刷新,上拉加載的RecyclerView:XRecyclerView
JSON數(shù)據(jù)的解析:Gson

數(shù)據(jù)來(lái)源

http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/1

這里的來(lái)源是來(lái)自GANK.IO的福利妹紙圖,然后利用GsonFormat生成JavaBean,代碼太長(zhǎng)我就不貼了。

關(guān)于基類

View層
/** * 基類View接口 
* Created by chenwei.li 
* Date: 2016-01-11
* Time: 00:22 
*/
public interface IBaseView {   
  void showLoadingDialog();  
  void cancelLoadingDialog();   
  void showErrorMsg(String errorMsg);
}

這個(gè)基礎(chǔ)View接口需要讓每個(gè)具體的業(yè)務(wù)View都去繼承實(shí)現(xiàn),里面封裝了一些常用的方法,例如我們?cè)诩虞d數(shù)據(jù)的時(shí)候都為了良好的用戶體驗(yàn),都需要顯示進(jìn)度條,或者彈出對(duì)話框來(lái)提醒用戶正在進(jìn)行,當(dāng)數(shù)據(jù)加載完畢都需要關(guān)閉這個(gè)提醒,當(dāng)加載出錯(cuò)的時(shí)候,需要提醒用戶出錯(cuò)信息。

/**
 * 基類Fragment
 * Created by chenwei.li
 * Date: 2016-01-03
 * Time: 23:52
 */
public abstract class BaseFragment extends Fragment implements IBaseFragment {

    //當(dāng)前Fragment視圖對(duì)象
    protected View mView;


    /**
     * Activity對(duì)象,避免getActivity()出現(xiàn)null
     */
    protected Activity mActivity;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.mActivity = (Activity) context;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {


        /**
         * 綁定視圖
         */
        if (mView == null) {
            mView = inflater.inflate(bindLayout(), container, false);
        }
        /**
         * 依賴注入
         */
        ButterKnife.bind(this, mView);

        /**
         * 創(chuàng)建Fragment
         */
        createFragment(savedInstanceState);

        /**
         * 初始化視圖,默認(rèn)值
         */
        initView();
        /**
         * 獲取對(duì)應(yīng)數(shù)據(jù)(網(wǎng)絡(luò),數(shù)據(jù)庫(kù))
         */
        getData();

        return mView;
    }



    @Override
    public void onDestroy() {
        super.onDestroy();
        /**
         * 解綁ButterKnife
         */
        ButterKnife.unbind(this);

    }
}
/**
 * 基類Fragment(懶加載)
 * Create by: chenwei.li
 * Date: 2016-05-26
 * time: 09:15
 * Email: lichenwei.me@foxmail.com
 */
public abstract class BaseLazyFragment extends Fragment implements IBaseFragment {


    //當(dāng)前Fragment視圖對(duì)象
    protected View mView;

    /**
     * 是否加載布局
     */
    protected boolean isPrepare;

    /**
     * 是否顯示布局
     */
    protected boolean isVisiable;

    /**
     * 是否是第一次加載
     */
    protected boolean isFirst;


    /**
     * Activity對(duì)象,避免getActivity()出現(xiàn)null
     */
    protected Activity mActivity;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.mActivity = (Activity) context;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {


        /**
         * 綁定視圖
         */
        if (mView == null) {
            mView = inflater.inflate(bindLayout(), container, false);
            isPrepare = true;
            isFirst = true;
        }

        /**
         * 依賴注入
         */
        ButterKnife.bind(this, mView);

        /**
         * 創(chuàng)建Fragment
         */
        createFragment(savedInstanceState);

        /**
         * 初始化視圖,默認(rèn)值
         */
        initView();

        return mView;
    }

    /**
     * 判斷當(dāng)前Fragment是否已經(jīng)顯示
     *
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (getUserVisibleHint()) {
            isVisiable = true;
            onVisible();
        } else {
            isVisiable = false;
        }
    }

    protected void onVisible() {
        lazy();
    }

    /**
     * 要進(jìn)行懶加載的數(shù)據(jù)
     */
    protected void lazy() {
        if (isPrepare && isVisiable && isFirst) {
            lazyLoadData();
            isFirst = false;
        }
    }

    /**
     * 需要進(jìn)行懶加載的數(shù)據(jù)
     */
    protected abstract void lazyLoadData();


    /**
     * 只需要空實(shí)現(xiàn),所有的懶加載數(shù)據(jù)都在lazyLoadData里面執(zhí)行
     */
    @Override
    public void getData() {
    }
}


上面是基礎(chǔ)類BaseFragment的封裝,實(shí)現(xiàn)了IBaseFragment接口里的方法,代碼并不復(fù)雜,大家根據(jù)注釋看下就可以理解了,這里因?yàn)槲业淖⑷肟蚣苡玫腂utterKnife,所以在創(chuàng)建Frgament的時(shí)候,我去綁定了View,當(dāng)Fragment銷毀的時(shí)候,去取消綁定。
這里根據(jù)具體業(yè)務(wù),我又多封裝了一個(gè)具有懶加載功能的Fragment,這個(gè)LazyBaseFragment和普通的Fragment區(qū)別在于,當(dāng)我們使用ViewPager去嵌套Fragment的時(shí)候,由于ViewPaer的原因,默認(rèn)它會(huì)加載當(dāng)前頁(yè)面的左右各一個(gè)頁(yè)卡,有時(shí)候用戶需要看當(dāng)前頁(yè)面并不執(zhí)行滑動(dòng)操作去看其他的,但是程序已經(jīng)加載了頁(yè)面,勢(shì)必會(huì)造成一些資源浪費(fèi),所以我根據(jù)setUserVisibleHint(boolean isVisibleToUser)和標(biāo)志位的判斷,來(lái)確定在頁(yè)面加載且用戶滑到當(dāng)前頁(yè)的時(shí)候才去加載數(shù)據(jù)的。這點(diǎn)的想法起源來(lái)自簡(jiǎn)書的APP,大家看下圖就能明白:

簡(jiǎn)書APP
簡(jiǎn)書APP

很明顯,簡(jiǎn)書也運(yùn)動(dòng)了Fragment的懶加載,這里可能有朋友會(huì)說(shuō)關(guān)于ViewPager里的setOffscreenPageLimit(int pgaeSize)方法,這個(gè)方法的作用是控制ViewPager保留當(dāng)前頁(yè)面的左右各幾個(gè)頁(yè)面的數(shù)據(jù)狀態(tài),而不讓它進(jìn)行滑動(dòng)銷毀,也可以決定ViewPager一次性加載幾個(gè)頁(yè)卡,所以把它設(shè)置為0不就解決了,其實(shí)不是的,如果你用去看過(guò)ViewPager的源碼,你就會(huì)發(fā)現(xiàn)這樣的一段代碼:

    /**
     * Set the number of pages that should be retained to either side of the
     * current page in the view hierarchy in an idle state. Pages beyond this
     * limit will be recreated from the adapter when needed.
     *
     * <p>This is offered as an optimization. If you know in advance the number
     * of pages you will need to support or have lazy-loading mechanisms in place
     * on your pages, tweaking this setting can have benefits in perceived smoothness
     * of paging animations and interaction. If you have a small number of pages (3-4)
     * that you can keep active all at once, less time will be spent in layout for
     * newly created view subtrees as the user pages back and forth.</p>
     *
     * <p>You should keep this limit low, especially if your pages have complex layouts.
     * This setting defaults to 1.</p>
     *
     * @param limit How many pages will be kept offscreen in an idle state.
     */
    public void setOffscreenPageLimit(int limit) {
        if (limit < DEFAULT_OFFSCREEN_PAGES) {
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
                    DEFAULT_OFFSCREEN_PAGES);
            limit = DEFAULT_OFFSCREEN_PAGES;
        }
        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            populate();
        }
    }

而這里的

private static final int DEFAULT_OFFSCREEN_PAGES = 1;

所以不管你是設(shè)置0,或者更小的數(shù),默認(rèn)它都是為1的,也就是默認(rèn)加載3個(gè)頁(yè)卡,保留當(dāng)前頁(yè)卡的左右頁(yè)卡狀態(tài)。

Presenter層
/**
 * 基類Presenter接口
 * Create by: chenwei.li
 * Date: 2016-05-31
 * time: 14:25
 * Email: lichenwei.me@foxmail.com
 */
public interface IBasePresenter<V extends IBaseView> {

    /**
     * V層注入引用
     * @param mvpView
     */
    void attachView(V mvpView);

    /**
     * 銷毀V層引用
     */
    void detachView();

}

這里封裝了2個(gè)方法,用來(lái)使View層的Activity和Fragment和P層的生命狀態(tài)保持一致,當(dāng)頁(yè)面銷毀的時(shí)候,這次Context上下文的引用也就沒(méi)有理由存在了,這里我們把它置為null,便于GC回收。

/**
 * 基類BasePresenter
 * Create by: chenwei.li
 * Date: 2016-05-31
 * time: 11:14
 * Email: lichenwei.me@foxmail.com
 */
public class BasePresenter<T extends IBaseView> implements IBasePresenter<T> {

    private T mMvpView;

    @Override
    public void attachView(T mvpView) {
        this.mMvpView = mvpView;
    }

    @Override
    public void detachView() {
        this.mMvpView = null;
    }

    public T getMvpView() {
        return mMvpView;
    }
}

基類Presenter,讓所有的P層繼承。

具體代碼

View層

/**
 * View層妹紙福利
 * Create by: chenwei.li
 * Date: 2016-05-26
 * time: 22:06
 * Email: lichenwei.me@foxmail.com
 */
public interface IWealView extends IBaseView {

    void getWealList(int pageSize, int currentPage);

    void onRefreshData(List<WealEntity.ResultsBean> resultsBean);

    void onLoadMoreData(List<WealEntity.ResultsBean> resultsBean);

}

這里提供了操作接口,因?yàn)樵诒卷?yè)面的業(yè)務(wù)只是單純的加載列表數(shù)據(jù),刷新數(shù)據(jù),所以這里定義了3個(gè)方法,用來(lái)滿足業(yè)務(wù)。

/**
 * 福利Fragment
 * Create by: chenwei.li
 * Date: 2016-05-25
 * time: 11:19
 * Email: lichenwei.me@foxmail.com
 */
public class WealFragment extends BaseLazyFragment implements IWealView {


    @Bind(R.id.rv_wealView)
    XRecyclerView mRvWealView;


    //福利適配器與數(shù)據(jù)源
    private WealAdapter mWealAdapter;
    private List<WealEntity.ResultsBean> mResultsBeans;

    //福利P層
    private WealPresenter mWealPresenter;

    //記錄當(dāng)前頁(yè)數(shù),默認(rèn)為1
    private int mCurrentPage = 1;


    /**
     * 懶加載數(shù)據(jù)
     */
    @Override
    protected void lazyLoadData() {
        getWealList(10, mCurrentPage);
    }

    @Override
    public int bindLayout() {
        return R.layout.fragment_weal;
    }

    @Override
    public void createFragment(Bundle savedInstanceState) {
    }



    @Override
    public void initView() {

        //注入P層
        mWealPresenter = new WealPresenter();
        mWealPresenter.attachView(this);

        //創(chuàng)建數(shù)據(jù)源,設(shè)置適配器
        mResultsBeans = new ArrayList<WealEntity.ResultsBean>();
        mWealAdapter = new WealAdapter(mResultsBeans);
        mRvWealView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
        mRvWealView.setAdapter(mWealAdapter);

        //設(shè)置動(dòng)畫,刷新樣式
        mRvWealView.setItemAnimator(new DefaultItemAnimator());
        mRvWealView.setArrowImageView(R.drawable.iconfont_downgrey);

        //監(jiān)聽(tīng)刷新數(shù)據(jù)
        mRvWealView.setLoadingListener(new XRecyclerView.LoadingListener() {
            @Override
            public void onRefresh() {
                mCurrentPage = 1;
                getWealList(10, mCurrentPage);
            }

            @Override
            public void onLoadMore() {
                getWealList(10, mCurrentPage);
            }
        });


    }


    @Override
    public void showLoadingDialog() {

    }

    @Override
    public void cancelLoadingDialog() {

    }

    /**
     * 顯示錯(cuò)誤信息
     *
     * @param errorMsg
     */
    @Override
    public void showErrorMsg(String errorMsg) {
        ToastUtil.showShort(MyApplication.getContext(), errorMsg);
    }

    /**
     * 獲取數(shù)據(jù)
     *
     * @param pageSize
     * @param currentPage
     */
    @Override
    public void getWealList(int pageSize, int currentPage) {
        mWealPresenter.getWealList(pageSize, currentPage);
        mCurrentPage++;
    }


    /**
     * 下拉刷新數(shù)據(jù)回調(diào)
     * @param resultsBean
     */
    @Override
    public void onRefreshData(List<WealEntity.ResultsBean> resultsBean) {
        mResultsBeans.clear();
        mResultsBeans.addAll(resultsBean);
        mWealAdapter.notifyDataSetChanged();
        mRvWealView.refreshComplete();
    }

    /**
     * 上拉加載數(shù)據(jù)回調(diào)
     * @param resultsBean
     */
    @Override
    public void onLoadMoreData(List<WealEntity.ResultsBean> resultsBean) {
        mResultsBeans.addAll(resultsBean);
        mWealAdapter.notifyDataSetChanged();
        mRvWealView.loadMoreComplete();
        if (resultsBean.size() < 10) {
            //當(dāng)加載新數(shù)據(jù)的條數(shù)不足10條,則關(guān)閉上拉加載
            mRvWealView.setLoadingMoreEnabled(false);
        }
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        mWealPresenter.detachView();
    }


}

這里采用了懶加載LazyFragment,當(dāng)頁(yè)面加載完畢且用戶當(dāng)前界面處于它的時(shí)候,會(huì)調(diào)用執(zhí)行l(wèi)azyData加載數(shù)據(jù),當(dāng)下拉刷新,上拉加載的時(shí)候會(huì)對(duì)應(yīng)的執(zhí)行方法,且改變當(dāng)前頁(yè)碼。這里在頁(yè)面初始化加載和銷毀的時(shí)候,分別去調(diào)用了P層的注入和銷毀方法,用來(lái)保存生命狀態(tài)一致。

Presenter層

/**
 * 獲取福利Presenter層
 * Create by: chenwei.li
 * Date: 2016-05-26
 * time: 22:20
 * Email: lichenwei.me@foxmail.com
 */
public class WealPresenter extends BasePresenter<IWealView> {

    private IWealModel iWealModel = new WealModel();


    @Override
    public void attachView(IWealView mvpView) {
        super.attachView(mvpView);
    }


    @Override
    public void detachView() {
        super.detachView();
    }

    /**
     * 根據(jù)加載數(shù)量和頁(yè)碼加載數(shù)據(jù)
     *
     * @param pageSize
     * @param currentPage
     */
    public void getWealList(int pageSize, final int currentPage) {
        iWealModel.getWealList(pageSize, currentPage, new Subscriber<WealEntity>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                getMvpView().showErrorMsg(e.getMessage());
            }

            @Override
            public void onNext(WealEntity wealEntity) {
                if (wealEntity.getResults() != null) {
                    if (currentPage == 1) {
                        getMvpView().onRefreshData(wealEntity.getResults());
                    } else {
                        getMvpView().onLoadMoreData(wealEntity.getResults());
                    }

                }
            }
        });

    }

}

這里沒(méi)什么好說(shuō)的,只是作為“信使”,傳遞了View層的請(qǐng)求給Model層,并通過(guò)Rxjava的訂閱回調(diào)對(duì)應(yīng)的方法,再次傳遞數(shù)據(jù)給View層。

Model層

/**
 * 網(wǎng)絡(luò)接口包裝類
 * Create by: chenwei.li
 * Date: 2016-05-23
 * time: 00:43
 * Email: lichenwei.me@foxmail.com
 */
public class RetrofitWapper {

    private static RetrofitWapper mRetrofitWapper;
    private Retrofit mRetrofit;

    /**
     * 將構(gòu)造函數(shù)私有化
     */
    private RetrofitWapper() {
        mRetrofit = new Retrofit.Builder().baseUrl(Constant.BASE_URL).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();
    }

    /**
     * 獲取RetrofitWapper實(shí)例(單例模式)
     *
     * @return
     */
    public static RetrofitWapper getRetrofitWapperInstance() {
        if (mRetrofitWapper == null) {
            synchronized (RetrofitWapper.class) {
            mRetrofitWapper = new RetrofitWapper();
        }
    }
        return mRetrofitWapper;
    }

    /**
     * 創(chuàng)建接口訪問(wèn)入口
     * @param service
     * @param <T>
     * @return
     */
    public <T> T create(Class<T> service) {
        return mRetrofit.create(service);
    }


    public class Constant {
        public static final String BASE_URL = "http://gank.io/api/";
    }

}

這里寫了一個(gè)幫助類,用來(lái)提供Retrofit的實(shí)例(單例),由于Retrofit底層默認(rèn)是提供Okhttp支持的,所以如果這里要對(duì)Okhttp進(jìn)行個(gè)性化定制也是很容易的,例如:

    private RetrofitWapper() {
        OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
        okHttpClient.connectTimeout(5, TimeUnit.SECONDS);
        mRetrofit = new Retrofit.Builder().client(okHttpClient.build()).baseUrl(Constant.BASE_URL).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();
    }

再來(lái)看下Retrofit的service:

/**
 * Gank.io接口類
 * Create by: chenwei.li
 * Date: 2016-05-26
 * time: 16:11
 * Email: lichenwei.me@foxmail.com
 */
public interface GankApiService {

    /**
     * 獲取福利列表
     *
     * @param pageSize
     * @param currentPage
     * @return
     */
    @GET("data/福利/{pageSize}/{currentPage}")
    Observable<WealEntity> getWealList(@Path("pageSize") int pageSize, @Path("currentPage") int currentPage);
}

Model層的業(yè)務(wù)接口及實(shí)現(xiàn):

/**
 * 獲取福利Model層接口
 * Create by: chenwei.li
 * Date: 2016-05-26
 * time: 22:31
 * Email: lichenwei.me@foxmail.com
 */
public interface IWealModel {
     void getWealList(int pageSize,int currentSize, Subscriber<WealEntity> wealEntitySubscriber);
}

/**
 * Create by: chenwei.li
 * Date: 2016-05-26
 * time: 22:28
 * Email: lichenwei.me@foxmail.com
 */
public class WealModel implements IWealModel {

    private GankApiService mGankApiService;

    /**
     * 獲取福利列表數(shù)據(jù)
     *
     * @param pageSize
     * @param currentSize
     * @param wealEntitySubscriber
     */
    @Override
    public void getWealList(int pageSize, int currentSize, Subscriber<WealEntity> wealEntitySubscriber) {
        mGankApiService = RetrofitWapper.getRetrofitWapperInstance().create(GankApiService.class);
        mGankApiService.getWealList(pageSize, currentSize).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(wealEntitySubscriber);
    }
}

這里的代碼很簡(jiǎn)單,就不再做過(guò)多的文字描述了,對(duì)于Rxjava和Retrofit不熟悉的朋友可以網(wǎng)上查看下相關(guān)資料。

最后

關(guān)于軟件開發(fā)設(shè)計(jì)模式,其實(shí)并沒(méi)有最好的選擇,只有更適合的選擇,很多時(shí)候我們拋開業(yè)務(wù)去談設(shè)計(jì),架構(gòu)都是飄渺的,我認(rèn)為開發(fā)還是需要靈活點(diǎn),不應(yīng)該被某模式某架構(gòu)所束縛,這樣變得好像是為了目的而目的,已經(jīng)脫離了設(shè)計(jì)模式最初的設(shè)計(jì)意義。
比如這個(gè)MVP,對(duì)于業(yè)務(wù)很簡(jiǎn)單的小型APP來(lái)說(shuō),有時(shí)候明明只需要幾個(gè)類就可以解決的事情,非要使用MVP,會(huì)使其多了一大堆接口,導(dǎo)致開發(fā)成本變大,但也不是全然無(wú)用,至少它的代碼層次清晰了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容