基于MVP构架的Socket项目

10 篇文章 0 订阅

Android中基于MVP构架的Socket实例

MVP构架简介

Android中的MVP构架主要就是对原先MVC中Controller层臃肿的代码进行提取抽象,实际上就是将Activity当中的UI逻辑,业务逻辑与数据进行隔离,因此分为了三个层次;

  • View: 视图层,在View层中只负责对数据的展示,在Android开发中通常将Activity或者Fragment作为View层;

  • Model: 数据层,负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等;

  • Presenter:连接View层与Model层的桥梁并对业务逻辑进行处理,在这层中从Model层获得所需要的数据,进行一些适当的处理后返回View层进行显示。

实例介绍

本项目的Socket作为长连接来使用,因此socket放在基类model层中,在基类model层中进行socket的收发消息操作,View层作为数据的展示与用户获取数据的操作接口,presenter层作为View层与Model层的中转,并且进行一些业务逻辑操作与线程切换。

流程序列图:

view presenter model 建立socket 通知presenter获取数据 通知model获取数据 向socket服务端获取数据并接收 向presenter发送数据 执行业务逻辑或线程切换 向view展示数据 view presenter model

项目结构:

这里写图片描述

|----包名
|   |----mvp
|   |   |----base
|   |   |       BaseModel           Model基类
|   |   |       IBaseDelegate       简化Presenter在Activity的实现
|   |   |       IBasePresenter      Presenter基类
|   |   |       IBaseView           View基类
|   |   |----model                  业务逻辑和bean
|   |   |       xxxModel
|   |   |       xxxBean
|   |   |----presenter              连接View和Model的桥梁
|   |   |       xxxPresenter
|   |   |----view                   UI界面提炼出来的接口
|   |   |       xxxView
|   |----ui
|   |   |----activity               具体Activity
|   |   |       BaseActivity        Activity基类
|   |   |       BaseMVPActivity     MVP Activity基类
|   |   |       xxxActivity
|   |   |----fragment               具体Fragment
|   |   |       BaseFragment        Fragment基类
|   |   |       xxxFragment

实例分析

mvp基类构建

基类view,在这里抽象出所有activity的通用接口

public interface IBaseView {

    /**
     * 显示加载
     */
    void showLoading();

    /**
     * 完成加载
     */
    void dismiss();
}

presenter基类,连接Model和View,定义一个限定view为IbaseView子类的泛型,抽象出绑定和解绑接口

public interface IBasePresenter<V extends IBaseView> {

    /**绑定接口*/
    void attachView(V view);

    /**释放接口*/
    void detachView();

}

基类model,使用泛型方便子类与IBasePresenter的子类绑定

public abstract class BaseModel<SubP> {

    protected SubP mPresenter;

    public BaseModel(SubP presenter) {
        this.mPresenter = presenter;
    }

}

基类代理接口,抽象出创建和获取presenter方法,使persenter和activity进行绑定,泛型P为IBasePresenter的子类,由于IBasePresenter的泛型V限定为IbaseView的子类,因此IBaseDelegate也需要定义一个限定V为IbaseView子类的泛型来传入IBasePresenter中

public interface IBaseDelegate<V extends IBaseView, P extends IBasePresenter<V>> {

    /**初始化presenter*/
    @NonNull
    P createPresenter();

    /**获取presenter*/
    @NonNull
    P getPresenter();

}

Activity基类,在这里实现通用方法

public abstract class BaseActivity extends AppCompatActivity {

    protected void startActivity(Class<?> clz) {
        Intent intent = new Intent(this, clz);
        startActivity(intent);
    }
}

MVPActivity基类,实现presenter对象的创建,获取和解绑

public abstract class BaseMVPActivity<V extends IBaseView, P extends IBasePresenter<V>> extends
        BaseActivity implements IBaseDelegate<V, P> {

    protected P mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (mPresenter == null) {
            mPresenter = createPresenter();
        }
    }

    @NonNull
    @Override
    public P getPresenter() {
        return mPresenter;
    }

    @Override
    protected void onDestroy() {
        //解除绑定
        if (mPresenter != null) {
            mPresenter.detachView();
        }
        super.onDestroy();
    }
}

mvp构架功能实现

定义功能模块的view的接口

public interface IMainView extends IBaseView {

    /**
     * 显示数据
     */
    void showData(String s);

    /**
     * 显示通知
     */
    void showMessage(String msg);
}

定义功能模块的presenter,在presenter的构造方法中新建model层

public class MainPresenter implements IBasePresenter<IMainView> {

    private IMainView mView;
    private MainModel mModel;

    public MainPresenter(IMainView mView) {
        attachView(mView);
        this.mModel = new MainModel(this);
    }

    @Override
    public void attachView(IMainView view) {
        this.mView = view;
    }

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

    public void showData(String s) {
        if (mView == null) {
            return;
        }
        mView.dismiss();
        mView.showData(s);
    }

    public void showMessage(String msg) {
        if (mView == null) {
            return;
        }
        mView.showMessage(msg);
    }

    public <T> void sendData(T data) {
        mModel.sendData(data);
    }

    public void stopSocket() {
        mModel.stopSocket();
    }
}

定义功能模块的model,在构造方法中创建封装好的socket对象,并放入线程池中运行

封装好的SocketClientThread介绍可以看这篇文章http://blog.csdn.net/lj402159806/article/details/79371526

关于线程池的介绍可以看这篇文章http://blog.csdn.net/lj402159806/article/details/79369692

public class MainModel extends BaseModel<MainPresenter> implements SocketClientResponseInterface {

    private static final String TAG = MainModel.class.getSimpleName();
    private SocketClientThread socketClientThread;

    public MainModel(MainPresenter presenter) {
        super(presenter);
        socketClientThread = new SocketClientThread("socketClientThread", this);
        ThreadPoolUtil.getInstance().addExecuteTask(socketClientThread);
    }

    @Override
    public void onSocketConnect() {
        mPresenter.showData("连接成功");
    }

    @Override
    public void onSocketReceive(Object socketResult, int code) {
        mPresenter.showData("收到消息 ,  data: " + socketResult + " , code: " + code);
    }

    @Override
    public void onSocketDisable(String msg, int code) {
        mPresenter.showMessage("连接断开 , msg: " + msg + " , code: " + code);
    }

    public <T> void sendData(T data) {
        //convert to string or serialize object
        String s = (String) data;
        if (TextUtils.isEmpty(s)) {
            mPresenter.showMessage("消息不能为空");
            return;
        }
        if (socketClientThread != null) {
            socketClientThread.addRequest(s);
        }
    }

    public void stopSocket() {
        //一定要在子线程内执行关闭socket等IO操作
        ThreadPoolUtil.getInstance().addExecuteTask(() -> {
            socketClientThread.setReConnect(false);
            socketClientThread.stopThread();
        });
        ThreadPoolUtil.getInstance().shutdown();
    }
}

Fragment基类,定义回调Activity的接口

public abstract class BaseFragment extends Fragment {

    /**
     * Activity 供Fragment回调的接口
     */
    public interface IMainCallBack {
        <T> void sendData(T data);
    }
}

view层逻辑在Fragment中实现,这里功能仅为点击按钮回调activity

public class TestFragment extends BaseFragment {

    private static final String KEY_MESSAGE = "message";
    Unbinder unbinder;
    @BindView(R.id.btn_send)
    Button mBtnSend;
    private String msg;
    private IMainCallBack activityCallBack;

    public static TestFragment newInstance(String message) {
        TestFragment fragment = new TestFragment();
        Bundle args = new Bundle();
        args.putString(KEY_MESSAGE, message);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            activityCallBack = (IMainCallBack) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement activityCallBack");
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            msg = (String) getArguments().getSerializable(KEY_MESSAGE);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_text, container, false);
        unbinder = ButterKnife.bind(this, view);
        initView();
        return view;
    }

    private void initView() {
        String text = mBtnSend.getText() + msg;
        mBtnSend.setText(text);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }

    @OnClick({R.id.btn_send})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.btn_send:
                activityCallBack.sendData(msg);
                break;
            default:
                break;
        }
    }

}

MainActivity作为多个fragment的容器,对各个fragment提供统一的mvp接口

public class MainActivity extends BaseMVPActivity<IMainView, MainPresenter> implements
        IMainView, BaseFragment.IMainCallBack {

    private static final String TAG = MainActivity.class.getSimpleName();
    @BindView(R.id.bottom_navigation_bar)
    BottomNavigationBar mBottomNavigationBar;

    private TestFragment fragment1;
    private TestFragment fragment2;
    private TestFragment fragment3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(MainActivity.this);
        initView();
    }

    private void initView() {
        fragment1 = TestFragment.newInstance("123");
        fragment2 = TestFragment.newInstance("321");
        fragment3 = TestFragment.newInstance("123321");
        mBottomNavigationBar.setTabSelectedListener(new BottomNavigationBar.SimpleOnTabSelectedListener() {
            @Override
            public void onTabSelected(int position) {
                setScrollableText(position);
            }
        });
        mBottomNavigationBar
                .addItem(new BottomNavigationItem(R.mipmap.ic_location_on_white_24dp, "Nearby").setActiveColorResource(R.color.orange))
                .addItem(new BottomNavigationItem(R.mipmap.ic_find_replace_white_24dp, "Find").setActiveColorResource(R.color.teal))
                .addItem(new BottomNavigationItem(R.mipmap.ic_favorite_white_24dp, "Categories").setActiveColorResource(R.color.blue))
                .initialise();
        setScrollableText(0);
    }

    @NonNull
    @Override
    public MainPresenter createPresenter() {
        return new MainPresenter(this);
    }

    @Override
    protected void onDestroy() {
        getPresenter().sendData("bye");
        Log.i(TAG, "onDestroy: sendData");
        getPresenter().stopSocket();
        Log.i(TAG, "onDestroy: stopSocket");
        super.onDestroy();
    }

    @Override
    public void showData(String s) {
        Log.i(TAG, "showData: " + s);
        runOnUiThread(() -> Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show());
    }

    @Override
    public void showMessage(String msg) {
        Log.i(TAG, "showMessage: " + msg);
        //runOnUiThread(() -> Toast.makeText(this, msg, Toast.LENGTH_SHORT).show());
    }

    @Override
    public void showLoading() {
    }

    @Override
    public void dismiss() {
    }

    @Override
    public <T>void sendData(T data) {
        getPresenter().sendData(data);
    }

    private void setScrollableText(int position) {
        switch (position) {
            case 0:
                getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_frag_container, fragment1).commitAllowingStateLoss();
                break;
            case 1:
                getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_frag_container, fragment2).commitAllowingStateLoss();
                break;
            case 2:
                getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_frag_container, fragment3).commitAllowingStateLoss();
                break;
            default:
                getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_frag_container, fragment1).commitAllowingStateLoss();
                break;
        }
    }
}

由于将mainActivity作为fragment的mvp容器会导致mainActivity的mvp接口过多,因此已更新为由fragment自己实现mvp功能,mainModel仅作为socket的转发端

首先抽象出一个BaseSocketModel类

/**
 * Created by gavinandre on 18-1-7.
 */
public abstract class BaseSocketModel<SubP> extends BaseModel<SubP> implements SocketClientResponseInterface {

    private static final String TAG = BaseSocketModel.class.getSimpleName();
    private static SocketClient socketClient;

    public BaseSocketModel(SubP presenter) {
        super(presenter);
        if (socketClient == null) {
            socketClient = new SocketClient(this);
        }
    }

    public <T> void sendData(T data) {
        if (socketClient != null) {
            socketClient.sendData(data);
        }
    }

    public void stopSocket() {
        if (socketClient != null) {
            socketClient.stopSocket();
            socketClient = null;
        }
    }

    @Override
    public void onSocketConnect() {
    }

    @Override
    public void onSocketReceive(Object socketResult, int code) {
    }

    @Override
    public void onSocketDisable(String msg, int code) {
    }

}

mainModel继承BaseSocketModel

/**
 * Created by gavinandre on 18-1-7.
 */
public class MainModel extends BaseSocketModel<MainPresenter> {

    private static final String TAG = MainModel.class.getSimpleName();

    public MainModel(MainPresenter presenter) {
        super(presenter);
    }

    @Override
    public void onSocketConnect() {
        //if (mPresenter != null) {
        //    mPresenter.showData("连接成功");
        //}
        EventBus.getDefault().post("连接成功");
    }

    @Override
    public void onSocketReceive(Object socketResult, int code) {
        //if (mPresenter != null) {
        //    mPresenter.showData("收到消息 ,  data: " + socketResult + " , code: " + code);
        //}
        //发送消息给childModel
        EventBus.getDefault().post("收到消息 ,  data: " + socketResult + " , code: " + code);
    }

    @Override
    public void onSocketDisable(String msg, int code) {
        //if (mPresenter != null) {
        //    mPresenter.showMessage("连接断开 , msg: " + msg + " , code: " + code);
        //}
        EventBus.getDefault().post("连接断开 ,  msg: " + msg + " , code: " + code);
    }

    @Override
    public void detachModel() {
        stopSocket();
        super.detachModel();
    }
}

在mainModel中使用EventBus将消息转发到fragment的model中,更多细节请参考完整demo

Socket通信完整实例(心跳包,客户端断线重连,服务端超时断开客户端连接)分析
https://blog.csdn.net/lj402159806/article/details/79371526

完整demo:

https://github.com/GavinAndre/MVPSocket

参考:

http://blog.csdn.net/jiujiedexiaoming/article/details/54927617

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值