MVP模式研究与实践

自由创新研究探索四要素闭环方法论 在复杂问题解决与产品创新实践中,'自由、创新、研究、探索'并非抽象口号,而是一套具备神经科学依据和工程可操作性的系统方法。其底层逻辑源于大脑默认模式网络(DMN)的激活机制与前额叶评估回路的协同作用,强调在容错前提下构建选择权、通过旧要素重组提升效率、以问题驱动建立三层证据链、并在模糊地带用双轴坐标定位解空间。该方法已成功应用于智能农业、工业传感、教育科技与社区服务等多场景,显著提升方案落地率与用户采纳率。本文聚焦可验证、可复用、可迭代的七步实操切片,尤其强化自由启动的感官剥夺法、研究锚定的三层证据塔、探索 阅读详情

虽然有那么多资料介绍MVP了,但是还是想把自己的实践经验分享一下。

MVP简介

相信大家对MVC都是比较熟悉了,:M-Model-模型、V-View-视图、C-Controller-控制器,MVP作为MVC的演化版本,那么类似的MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器。 从MVC和MVP两者结合来看,Controlller/Presenter在MVC/MVP中都起着逻辑控制处理的角色,起着控制各业务流程的作用。而 MVP与MVC最不同的一点是M与V是不直接关联的也是就Model与View不存在直接关系,这两者之间间隔着的是Presenter层,其负责调控 View与Model之间的间接交互,MVP的结构图如下所示,对于这个图理解即可而不必限于其中的条条框框,毕竟在不同的场景下多少会有些出入的。在 Android中很重要的一点就是对UI的操作基本上需要异步进行也就是在MainThread中才能操作UI,所以对View与Model的切断分离是 合理的。此外Presenter与View、Model的交互使用接口定义交互操作可以进一步达到松耦合也可以通过接口更加方便地进行单元测试。

MVP结构图

关于android的MVP模式其实一直没有一个统一的实现方式,不同的人由于个人理解的不同,进而产生了很多不同的实现方式,其实很难去说哪一种更好,哪一种不好,针对不同的场合,不同的实现方式都有各自的优缺点。

而我采用的MVP是Google提出的一种MVP实现方式,个人认为这种方式实现简单,更加适合android项目。传统的MVP中Model起着处理具体逻辑的功能,Presenter起着隔离和解耦的作用,而在Google的MVP中弱化了Model,Model的逻辑由Presenter来实现,spManager、dbManager可以看做是Model,由Fragment实现View实现视图的变化,Activity作为一个全局的控制者,负责创建view以及presenter实例,并将二者联系起来。官方Demo地址(不仅包含mvp架构,还包含其它一些架构,可以切换不同分支查看):https://github.com/googlesamples/android-architecture/tree/todo-mvp-clean/

下图是Google官方Demo:todo-mvp模式的架构图

从结构方面观察一下MVP模式

Google官方Demo:todo-mvp是操作本地数据,而我们实际项目中大多数是获取网络数据。我下面展示的Demo使用todomvp+retrofit+rxjava2+multimodule架构

实现步骤:

1、创建类BasePresenter,封装一些公用操作

public abstract class BasePresenter<V> {

    public V mView;
    public ApiService mRestService = RetrofitProvider.getInstance().builder().getApiService();
    CompositeDisposable mCompositeDisposable;

    /**
     * 绑定View
     *
     * @param view
     */
    public void attach(V view) {
        this.mView = view;
        if (mCompositeDisposable == null) {
            mCompositeDisposable = new CompositeDisposable();
        }
    }

    /**
     * 释放View
     */
    public void dettach() {
        this.mView = null;
        //避免内存泄漏,view销毁的时候解除,取消所有observer
        if (mCompositeDisposable != null) {
            mCompositeDisposable.clear();
        }
    }

    public void addSubscribe(Observable observable, BaseObserver observer) {
        //把所有observer都放到一个集合中
        mCompositeDisposable.add(observer);
        observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }
}

2、创建类Contract,封装获取数据和显示数据接口,相当于签订的契约,根据自己需求设计


public class HomeContract {

    public interface Presenter {

        
        void getFeedArticleList(int num);

        void getBannerInfo();


        void onLoadMore();
    }

    public interface View {

        void showArticleList(ArticleListData itemBeans);

        void showBannerList(BannerListData itemBeans);
    }
}

3、MVP中的M,实现一个Model类,存储网络数据

public class ArticleListData {
    public ListData data;

    public class ListData {
        private int curPage;
        public List<FeedArticleData> datas;
        private int offset;
        private boolean over;
        private int pageCount;
        private int size;
        private int total;

        public int getCurPage() {
            return curPage;
        }

        public void setCurPage(int curPage) {
            this.curPage = curPage;
        }


        public int getOffset() {
            return offset;
        }

        public void setOffset(int offset) {
            this.offset = offset;
        }

        public boolean isOver() {
            return over;
        }

        public void setOver(boolean over) {
            this.over = over;
        }

        public int getPageCount() {
            return pageCount;
        }

        public void setPageCount(int pageCount) {
            this.pageCount = pageCount;
        }

        public int getSize() {
            return size;
        }

        public void setSize(int size) {
            this.size = size;
        }

        public int getTotal() {
            return total;
        }

        public void setTotal(int total) {
            this.total = total;
        }

        public List<FeedArticleData> getDatas() {
            return datas;
        }

        public void setDatas(List<FeedArticleData> datas) {
            this.datas = datas;
        }

    }
        public class FeedArticleData implements Serializable {

            private String apkLink;
            private String author;
            private int chapterId;
            private String chapterName;
            private boolean collect;
            private int courseId;
            private String desc;
            private String envelopePic;
            private int id;
            private String link;
            private String niceDate;
            private String origin;
            private String projectLink;
            private int superChapterId;
            private String superChapterName;
            private long publishTime;
            private String title;
            private int visible;
            private int zan;

            public String getApkLink() {
                return apkLink;
            }

            public void setApkLink(String apkLink) {
                this.apkLink = apkLink;
            }

            public String getAuthor() {
                return author;
            }

            public void setAuthor(String author) {
                this.author = author;
            }

            public int getChapterId() {
                return chapterId;
            }

            public void setChapterId(int chapterId) {
                this.chapterId = chapterId;
            }

            public String getChapterName() {
                return chapterName;
            }

            public void setChapterName(String chapterName) {
                this.chapterName = chapterName;
            }

            public boolean isCollect() {
                return collect;
            }

            public void setCollect(boolean collect) {
                this.collect = collect;
            }

            public int getCourseId() {
                return courseId;
            }

            public void setCourseId(int courseId) {
                this.courseId = courseId;
            }

            public String getDesc() {
                return desc;
            }

            public void setDesc(String desc) {
                this.desc = desc;
            }

            public String getEnvelopePic() {
                return envelopePic;
            }

            public void setEnvelopePic(String envelopePic) {
                this.envelopePic = envelopePic;
            }

            public int getId() {
                return id;
            }

            public void setId(int id) {
                this.id = id;
            }

            public String getLink() {
                return link;
            }

            public void setLink(String link) {
                this.link = link;
            }

            public String getNiceDate() {
                return niceDate;
            }

            public void setNiceDate(String niceDate) {
                this.niceDate = niceDate;
            }

            public String getOrigin() {
                return origin;
            }

            public void setOrigin(String origin) {
                this.origin = origin;
            }

            public String getProjectLink() {
                return projectLink;
            }

            public void setProjectLink(String projectLink) {
                this.projectLink = projectLink;
            }

            public int getSuperChapterId() {
                return superChapterId;
            }

            public void setSuperChapterId(int superChapterId) {
                this.superChapterId = superChapterId;
            }

            public String getSuperChapterName() {
                return superChapterName;
            }

            public void setSuperChapterName(String superChapterName) {
                this.superChapterName = superChapterName;
            }

            public long getPublishTime() {
                return publishTime;
            }

            public void setPublishTime(long publishTime) {
                this.publishTime = publishTime;
            }

            public String getTitle() {
                return title;
            }

            public void setTitle(String title) {
                this.title = title;
            }

            public int getVisible() {
                return visible;
            }

            public void setVisible(int visible) {
                this.visible = visible;
            }

            public int getZan() {
                return zan;
            }

            public void setZan(int zan) {
                this.zan = zan;
            }
        }

}

4、MVP中的V,和Presenter进行通信并且显示网络数据

public class HomeFragment extends BaseMvpFragment<HomePresenter> implements HomeContract.View {

    @BindView(R.id.project_recyclerview)
    RecyclerView project_recyclerview;
    @BindView(R.id.banner)
    Banner banner;
    @BindView(R.id.smartRefreshLayout_home)
    SmartRefreshLayout smartRefreshLayout;
    private List<FeedArticleData> articleDataList;
    private ArticleListAdapter feedArticleAdapter;

    @Override
    public void initData(Bundle bundle) {

    }

    @Override
    public void initView() {
        initSmartRefreshLayout();
        initRecyclerView();
    }

    @Override
    public int setContentLayout() {
        return R.layout.fragment_home;
    }

    @Override
    public void reload() {
        if (mPresenter == null) return;
        mPresenter.getFeedArticleList(0);
        mPresenter.getBannerInfo();
    }

    @Override
    public HomePresenter initPresenter() {
        //创建Presenter对象
        return new HomePresenter();
    }

    @Override
    protected void loadData() {
        //Fragement懒加载,在这个地方和Presenter交互,请求网络数据
        CustomProgressDialog.show(getActivity());
        mPresenter.getFeedArticleList(0);
        mPresenter.getBannerInfo();
    }

    //显示Article数据
    @Override
    public void showArticleList(ArticleListData listData) {
        final List<FeedArticleData> newDataList = listData.data.getDatas();

        articleDataList.addAll(newDataList);
        feedArticleAdapter.notifyItemRangeInserted(articleDataList.size() - newDataList.size(), newDataList.size());
        feedArticleAdapter.notifyDataSetChanged();
        smartRefreshLayout.finishLoadMore();
    }

    //显示Banner数据
    @Override
    public void showBannerList(BannerListData itemBeans) {

        final List<String> linkList = new ArrayList<String>();
        List imageList = new ArrayList();
        List titleList = new ArrayList();
        int size = itemBeans.data.size();

        for (int i = 0; i < size; i++) {
            imageList.add(itemBeans.data.get(i).getImagePath());
            titleList.add(itemBeans.data.get(i).getTitle());
            linkList.add(itemBeans.data.get(i).getUrl());
        }
        banner.setImageLoader(new com.youth.banner.loader.ImageLoader() {
            @Override
            public void displayImage(Context context, Object path, ImageView imageView) {
                Glide.with(getActivity()).load(path).into(imageView);
            }
        });

        banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR);//设置圆形指示器与标题
        banner.setBannerAnimation(Transformer.FlipHorizontal);
        banner.setIndicatorGravity(BannerConfig.CENTER);//设置指示器位置
        banner.setDelayTime(3000);//设置轮播时间
        banner.setImages(imageList);//设置图片源
        banner.setBannerTitles(titleList);//设置标题源
        banner.start();
        banner.setOnBannerListener(new OnBannerListener() {
            @Override
            public void OnBannerClick(int position) {
                Intent intent = new Intent(getActivity(), ArticleDetailActivity.class);
                Bundle bundle = new Bundle();
                bundle.putString("url", linkList.get(position));
                intent.putExtras(bundle);
                startActivity(intent);
            }
        });
    }

    private void initRecyclerView() {
        articleDataList = new ArrayList<>();
        feedArticleAdapter = new ArticleListAdapter(getActivity(), articleDataList);
        project_recyclerview.addItemDecoration(new DividerItemDecoration(getActivity(),
                DividerItemDecoration.VERTICAL_LIST));
        project_recyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
        project_recyclerview.setAdapter(feedArticleAdapter);
        feedArticleAdapter.setOnItemClickListener(new ArticleListAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View v, int position) {
                Intent intent = new Intent(getActivity(), ArticleDetailActivity.class);
                Bundle bundle = new Bundle();
                bundle.putString("url", articleDataList.get(position).getLink());
                intent.putExtras(bundle);
                startActivity(intent);
            }
        });
    }

    //初始化下拉刷新控件
    private void initSmartRefreshLayout() {
        smartRefreshLayout.setEnableRefresh(false);
        smartRefreshLayout.setEnableLoadMore(true);
        smartRefreshLayout.setEnableScrollContentWhenLoaded(true);//是否在加载完成时滚动列表显示新的内容
        smartRefreshLayout.setEnableFooterFollowWhenLoadFinished(true);
        smartRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore(RefreshLayout refreshLayout) {
                mPresenter.onLoadMore();
            }

        });
    }

    public void scrollToTop() {
        project_recyclerview.scrollToPosition(0);
    }

    public void onResume() {
        super.onResume();

    }

    public void onDestroy() {
        super.onDestroy();
    }
}

5、MVP中的P,具体实现BasePresenter,请求网络数据

public class HomePresenter extends BasePresenter<HomeContract.View> implements HomeContract.Presenter {
    private int mCurrentPage = 0;

    //加载更多
    @Override
    public void onLoadMore() {
        ++mCurrentPage;
        Observable observable = mRestService.getFeedArticleList(mCurrentPage);
        addSubscribe(observable, new BaseObserver<ArticleListData>(false) {
            @Override
            public void onNext(ArticleListData feedArticleListData) {
                mView.showArticleList(feedArticleListData);
            }
        });
    }

    //获取文章列表数据
    @Override
    public void getFeedArticleList(int num) {
        Observable observable = mRestService.getFeedArticleList(num);
        addSubscribe(observable, new BaseObserver<ArticleListData>(true) {
            @Override
            public void onNext(ArticleListData feedArticleListData) {
                mView.showArticleList(feedArticleListData);
            }
        });
    }

    //获取banner数据
    @Override
    public void getBannerInfo() {
        Observable observable = mRestService.getBannerListData();
        addSubscribe(observable, new BaseObserver<BannerListData>(true) {

            @Override
            public void onNext(BannerListData bannerListData) {
                mView.showBannerList(bannerListData);
            }

        });


    }

}

6、实现Retrofit的封装类 RetrofitProvider

public final class RetrofitProvider {

    private Retrofit mRetrofit;
    private OkHttpClient mOkHttpClient;
    private static volatile RetrofitProvider sInstance;
    private ApiService restService;
    public static String netCachePath;
    public final String BASE_URL = "http://www.wanandroid.com/";
    private RetrofitProvider() {
    }


    public RetrofitProvider builder() {
        netCachePath= CustomApplication.context.getExternalFilesDir("net_cache").getAbsolutePath();
        if (mOkHttpClient == null) {
            mOkHttpClient = new OkHttpClient.Builder()
                    .addNetworkInterceptor(new HttpLoggingInterceptor())
                    .addNetworkInterceptor(new OnlineCacheInterceptor())//有网缓存拦截器
                    .addInterceptor(new OfflineCacheInterceptor())//无网缓存拦截器
                    .cache(new Cache(new File(netCachePath), 50 * 10240 * 1024))//缓存路径和空间设置
                    .addInterceptor(new RetryIntercepter(4))//重试
                    .addInterceptor(new GzipRequestInterceptor())//开启Gzip压缩

//                    .addInterceptor(new DefaultHeaderInterceptor())//请求连接中添加头信息
//                    .addInterceptor(new ProgressInterceptor())//请求url的进度
//                    .addInterceptor(new TokenInterceptor())//token过期,自动刷新Token
//                    .addInterceptor(new SignInterceptor())//所有的接口,默认需要带上sign,timestamp2个参数
//                    .addNetworkInterceptor(new ParamsEncryptInterceptor())//参数加密,一般针对表单中的字段和值进行加密,防止中途第三方进行窥探和篡改
.cookieJar(new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(CustomApplication.context)))
                    .connectTimeout(5, TimeUnit.SECONDS)
                    .readTimeout(5, TimeUnit.SECONDS)
                    .writeTimeout(5, TimeUnit.SECONDS)
                    .build();

        }
        if (mRetrofit == null) {
            mRetrofit = new Retrofit.Builder()
                    .client(mOkHttpClient)
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
        }
        return sInstance;
    }

    public static RetrofitProvider getInstance() {
        if (sInstance == null) {
            synchronized (RetrofitProvider.class) {
                if (sInstance == null) {
                    sInstance = new RetrofitProvider();
                }
            }
        }
        return sInstance;
    }

    public ApiService getApiService() {
        if (restService == null)
            restService = mRetrofit.create(ApiService.class);
        return restService;
    }
}

7、以上是主要代码,完整代码可以访问地址:https://github.com/gaoleicoding/MVPModel/tree/todomvp+retrofit+rxjava+multimodule

为什么使用MVP?

MVP的优点:

1.解耦

毋庸置疑这是最大的好处,通过上述例子可以看到一个页面被分成了两个部分,一个是视图的逻辑,另一个是业务逻辑。两者持有的引用都是对方的接口,因此可以随意地替换实现(页面大修改),并且单独修改view或者presenter的逻辑并不会影响另一方(小修改)。

2.代码清晰

以前的MVC模式,当一个页面的逻辑足够复杂,就会出现一个activity上千行的情况,在这样的一个类中想定位一个bug是十分困难的,有时候自己的敲的代码看着都像别人的代码,得重头捋一捋才能定位,相当耗时。而用MVP模式,一个页面的逻辑都可以从Contract类中直观的看到有哪些,找到对应逻辑的方法再进入实现类中找到问题所在,效率上不可同日而语。

3.灵活

好多MVP的实现都是用Activity来实现View,这里使用Fragment便是出于灵活的考虑,Fragment可以复用,可以替换。面对多变的需求可以更从容的应对,例如:一个页面原本是一个列表,后来要求这个页面显示2个Tab,原来的列表变为其中一个Tab。类似的情况可能很常见,如果是用Activity实现的,可能要修改activity类中的很多代码,而原本就使用Fragment和MVP的话,仅需添加一个Fragment,修改Activity假如切换Tab的逻辑,而不用修改第一个Fragment的任何逻辑,这更符合OOP的编程思想。

4.简化

开头说过,传统MVP中Model起着处理具体逻辑的功能,Presenter起着隔离和解耦的作用。这种方式实现的MVP中Presenter看上去更像一个代理类,仅仅是不让View直接访问Model。虽然这样做解耦的程度更高,但实际项目中,一个页面逻辑的修改是非常少的,仅仅在产品修改需求是才会发生,大部分情况下仅仅是修复bug之类的小修改,并需要这样彻底的解耦。从另一个方面来说,一个页面的视图逻辑和业务逻辑本就是一体的。因此,Google的MVP弱化的Model的存在,让Presenter代替传统意义上的Model,减少了因使用MVP而剧增的类。这种方式相比不适用MVP仅从1个activity,增加到了1个activity,1个fragment(view),1个presenter,1个contract(如果有传统意义上的Model,还会有1个Model的接口和1个实现类)。

5.符合功能单一原则

6.MVP模式有那么多优点,那有没有缺点呢?那也是有的,毕竟凡事都有利有弊。缺点:造成接口和类数激增,代码复杂度和学习成本高。但肯定是利大于弊所有才会备受推崇

相关优秀文章推荐

  1. MVP架构封装演变全过程:高级MVP架构封装演变全过程_让activity 实现这个接口中的方法,这就是 v 层-CSDN博客

【竞赛篇-国创(大创)结题】从立项到结题:三大项目类型成果转化与快速通关策略 本文详细解析国创(大创)项目从立项到结题的全流程,重点介绍创新训练、创业训练和创业实践三大类型的核心差异与成果转化策略。通过竞赛获奖转化、论文专利前置等实战技巧,帮助团队快速通关结题流程,并提供材料准备避坑指南与不同年级的进度管理方案,助力项目高效完成。 阅读详情

相关推荐

Android短信截取保活技术:MVP架构实现详解

MVP(Model-View-Presenter)设计模式是一种将业务逻辑、数据和视图分离的架构,它起源于Martin Fowler的描述,并且在移动应用开发中特别受欢迎,尤其是Android平台。MVP的目的是为了提高代码的可测试性和可维护性,同时使得UI和业务逻辑的分离更加彻底。核心思想在于将传统的MVC(Model-View-Controller)模式中的Controller职责进一步细化,通过Presenter组件来解耦Model与View之间的直接联系。

weixin_31800911的博客 769

什么是MVP?全面解析最小可行产品

定义MVP是指以最少的功能集构建出的产品版本,该版本足以交付给早期用户使用,并通过他们的反馈来验证产品假设,从而以最小的成本和最快的速度学习,指导后续的产品迭代。最小(Minimum):功能数量刚好满足“可行”的门槛,不多也不少。可行(Viable):必须能够解决目标用户的某个核心问题,传递基本的价值,让用户愿意使用或付费。产品(Product):是一个可交付的实体(或服务),而不仅仅是想法。起源。

xixixi7777的博客 2728

华科软院研究生第一学期的事项(奖学金、学业、考试等)

奖助 研究生补助 每月500,全年共6000元 每个月月底学院会打到银行卡里 碰上开学、过年会延后发放 17年10月底发了9、10两个月的钱 18年3月底发了2、3月的钱 学业奖学金 17届全日制每人都有 按照考研最后综合成绩排名 前16 10000 前80 8000 其他 4000 大概11月底发 注意:第一年如果有挂科的话,第二年就不能参加学业奖学金评...

sjdeak的博客 3698

产品开发方法论之MVP(Minimum Viable Product)

MVP 是一种产品开发方法论,它强调在最短时间内,以最少的资源和功能,快速推出一个可供用户使用和体验的产品版本。它的核心思想是通过尽快获得用户反馈,来指导后续的产品迭代和优化。

CherryXieのblog 2196

一文详解AUTOSAR COM ComSignal结构体

ComSignalLength指定信号的长度,以字节为单位,影响数据的解析范围和精度。比如车速信号若为UINT16类型,ComSignalLength=16。这里需要注意必须ComSignalLength与ComSignalType匹配(比如FLOAT32类型需配置ComSignalLength=32),超出实际物理值范围时需配置缩放(Scaling)参数。ComSignalType定义信号的物理数据类型,决定如何解析原始字节数据。

menghuyouyou的博客 941

基于稀疏表示字典学习的图像超分辨率-杨建超论文解析

文章:《Image Super-Resolution via Sparse Representation》 作者:杨建超 信号稀疏的定义: 令字典D的原子个数M,信号维度为N,则有以下三种关系: M = N时,D为完备的; M > N时,D为冗余的; M>>N时, D为过完备的。 图解如下: 借鉴了压缩感知的思想,通过对大量低分辨率图像和高分辨...

ycc18829026593的博客 7631

MVC与MVP架构特点与区别

(一)MVCMVC全称是Model - View - Controller,是模型(model)-视图(view)-控制器(controller)的缩写。MVC是一种框架模式而非设计模式使用 MVC,把业务逻辑抽离到 Controller 中,让 View 层专注于显示 UI。1.MVC的优点(1)首先就是理解比较容易,技术含量不高,这对开发和维护来说成本较低也易于维护与修改。(2)耦合性不高,表...

zhwadezh的博客 3451

以太网接口及POE设计

PoE标准 Power Over Ethernet 是有源以太网供电的简称 通过Cat-5电缆供电在IEEE 802.3af以太网供电标准中进行了定义。PoE标准以前限制在几瓦以内,但更新的PoE技术可实现更高的功率。例如,PoE+允许每端口功率高达25 W,而PoE++(四 对以太网供电系统)通过使用现有电缆的所有电线允许70 W到100 W的功率。与此PoE标准并行的是ADI公司定义的专有标准 LTPoE++™,该标准定义高达90W的受电设备(PD)功率规范(请参见表1)。 表1. ADI...

u010783226的专栏 1万+

深入探讨:MVC、MVP 和 MVVM 架构模式的工作原理与实践

通过对 MVC、MVP 和 MVVM 三种架构模式的深入解析,我们了解了它们各自的优缺点、适用场景以及如何在实际开发中进行合理的架构选择。掌握这些架构模式不仅有助于构建结构清晰、易于维护的应用,还能提高开发效率、增强代码的可扩展性。在未来的开发中,架构设计的灵活运用将成为开发者处理复杂项目时的核心竞争力。无论是初学者还是经验丰富的开发者,都应不断探索和实践这些架构模式,从而构建出更高效、稳定的系统。

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 3431

STRING数据库的蛋白质相互作用(PPI)网络分析

在转录调控相关的文献中,我们经常能够看到这样的蛋白质相互作用网络(protein protein interaction network,PPI network)。具体而言,这些相关的文献中首先通过RNA-seq、表达谱芯片或者蛋白质组分析等,找到了在不同分组样本间一系列的差异表达基因或蛋白。

weixin_43029125的博客 9442

FFmpeg + Qt 实现摄像头采集与 MP3 背景音乐 RTSP 推流

在直播或视频监控场景中,我们经常需要将摄像头画面与背景音乐混合后推送到 RTSP 服务器。本文将详细介绍如何使用Qt框架结合摄像头实时采集(Windows 下使用dshow,Linux 使用v4l2视频预览(显示为 QImage)视频 H.264 编码 + RTSP 推流从 MP3 文件读取音频,重采样为 AAC 编码并推流循环播放音频文件解决中文文件路径打开失败的问题文章将剖析每个技术环节的关键代码,并给出完整的类实现。

weixin_45397344的博客 498

windchill 可交付成果 文档_一个MVP版本产品的研发交付之路

前面北哥陆续总结了程序员成长过程中应具备的核心能力,Java程序员的成长之路,架构师成长之路,这篇文章分享我曾经参与的一个MVP版本产品的研发交付经历,借此聊聊项目管理的那些事。作为一个程序员,每个人都避免不了参与各种各样的产品和项目的研发支撑工作。在我曾经的工作经历中,有一个产品的研发支撑和交付工作,至今让我记忆犹新。01 背景产品的背景是,公司已经上线了一个垂直行业的互联网产品A,通过解决信息...

weixin_39831039的博客 333

全局注意机制 GAM | Global Attention Mechanism: Retain Information to Enhance Channel-Spatial Interactions

全局注意机制 GAM

Coding... 2565

android 适合mvp模式,基于MVP模式的Android应用开发研究.PDF

基于MVP模式的Android应用开发研究.PDF第26卷 第11期 电子设计工程 2018年6月Vol.26 No.11 ElectronicDesignEngineering Jun.2018基于MVP模式的Android应用开发研究倪...

weixin_29009881的博客 147

AXI_Bus_Matrix_4x4 设计

Signal Source Width(bits) Description AWID Master AWID_WIDTH 写事务ID AWADDR Master

Starry__的博客 3755

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

探索惊奇:一款基于MVP模式的Android漫威应用

探索惊奇:一款基于MVP模式的Android漫威应用 项目介绍 欢迎来到Marvel Application,一个专为漫威粉丝打造的Android客户端,它将为你展示来自Marvel.com的精彩内容。这个项目由Mohsen Mirhoseini开发,并在smava GmbH的技术评估中脱颖而出。不仅如此,该项目还被用作一系列技术教程和文章的示例代码库。 项目技术分析 这款应用采用的是先进的开...

gitblog_00078的博客 1001

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

写给我自己的2022

时间真快,2022年,总结回顾一下2021年,其实我发现,当业务我已经很熟的时候,已经没什么挑战了,反而2021,这一年的需求,遇到麻烦的归纳起来有3类,1类是自定view(当时的筛选框,动画特效,以及view需要自定的需求) 2类需求的重构(1.如何重构,用什么架构重构,这样重构后有什么好处) 3.从没接触过的技术(如何去处理,才能又快,又正确) 以上三点用通俗 易懂的话,来概括,这将是我2022年需要突破的,可以总结成以下: 1.自定义view的训练 可以说是多写 多学 多看 多总结吧,平时.

binbin 1604

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Android开发MVP模式解析

在开发Android应用时,相信很多同学遇到和我一样的情况,虽然项目刚开始构架时一个Activity里面

冥萧阳的专栏 2万+

MVP模式最佳实践(1)—MVP模式简介

.Net的盛行.Net的出现无疑是一场变革,早期开发需要用C、C++、pascal等编写CGI程序,开发WEB应用,要求的技术门槛极高(当然,我听老一辈说那时的工资也高),使用纯Asp.Net开发WEB程序,门槛低,甚至不用编写任何代码就用实现一个简单的应用(当然,个人觉得这种应用没有什么太大的价值),这给广大的WEB开发者带来了福音,许多人纷纷转向.Net的怀抱,我记得那时在学校,还装模作样

lxxlql的专栏 1181

现代软件工程个人博客作业1

但我想到像Android、微信这样的平台,需要很长时间培养生态,可能不是不是MVP能验证的。我查到经济学里“双边市场”的研究,确实强调冷启动的高成本。书中在敏捷和团队协作章节,强调了Scrum和看板,但我查到Conway定律和Team Topologies的观点,认为组织架构不到位时,敏捷仪式反而会放大摩擦。我的问题是作者的架构演化观点,是否足以覆盖数据系统的复杂需求?但我查到Goodhart定律,指标一旦成为目标就会失真,比如代码行数、PR数量,成员会“为了指标而提交无意义PR”。

m0_63680154的博客 331

android的MVP模式以及接口的理解

最近看了一下Android开发的MVP模式以及接口,深有体会。    如图是MVP的一种简单结构,源码来自网上的例子  (http://blog.csdn.net/knxw0001/article/details/39637273)  1. package com.mvp.bean; //用户数据 public class UserBean { private String m

itgoyo的博客 1192

研究MVC、MVP、MVVM三种常见的设计模式

简介 所谓的设计模式其实是一种框架结构的体呈现,目的分离应用程序的页面展示,网络数据交互,数据呈现,随着项目复杂度的不断变化,新的框架也在不断的更新迭代,从最早的MVC模式,到后面的MVP以及MVVM,均是对项目的一种重构。 MVC设计框架 这个比较简单,适合一些中小型的项目。 关键字 M Module,模型层,用户数据管理,通常是一些 javaBean, db,share...

Lenny的专栏 1751

探索技术的乐趣:EasyGank —— 基于MVP模式的优雅实践

探索技术的乐趣:EasyGank —— 基于MVP模式的优雅实践 在技术的浩瀚海洋中探索,每一件作品都承载着开发者的心血与智慧。今天,让我们一同走进由CaMnter倾力打造的开源项目——EasyGank妹纸,这不仅是一款应用,更是对现代移动开发技术的一次精彩诠释。 项目介绍 EasyGank,一个采用MVP(Model-View-Presenter)设计模式精心构建的应用,旨在提供一种高效且易于...

gitblog_00437的博客 988

.Net平台-MVP模式初探(一)

MVP模式最早由Taligent的Mike Potel在《MVP: Model-View-Presenter The Taligent Programming Model for C++ and Java》(点击这里下载)一文中提出。MVP的提出主要是为了解决MVC模式中结构过于复杂和模型-视图耦合性过高的问题。MVP的核心思想是将UI分离成View,将P Logic分离成Presenter,而业务逻辑和领域相关逻辑都分离到Model中。View和Model完全解除耦合,不再像MVC中实现一个Observe

Percy宣森 5724

MVP模式之Presenter和View解耦

前言 关于MVP模式系列的文章,前面已经写了3篇了,本来想等以后对MVP模式有了更深层次的理解后再来总结一下的,但是最近在研究Adapter和Activity或Fragment解耦的时候,突然想到了View和Presenter之间的解耦,索性就尝试了一下,然后来和大家分享一下。 郑重声明: 由于我对架构的经验不足,所以在这里只在MVP框架体系下讨论Presenter和View之间的关系解耦(...

Rookie的专栏 3365

Android架构组件与MVP模式

Android架构组件是Google推出的一套用于帮助开发者构建高质量应用的库。这些组件提供了用于管理UI、数据存储、生命周期等功能的工具,使得开发者能够更好地管理应用的状态和生命周期。例如,Lifecycle组件可以帮助开发者跟踪Activity和Fragment的生命周期状态,从而避免内存泄漏和崩溃。如Room数据库,简化了数据存储的操作,提高了数据操作的安全性和效率。MVP(Model-View-Presenter)模式是一种将业务逻辑、数据、界面显示分离的设计模式。

cao_xiang_qi8395的博客 329
上一篇: AndroidStudio 编译中遇到问题总结2
下一篇: 学Android -- 个人项目(Java+Kotlin双版本)
高的世界
高的世界 领域专家: 操作系统技术领域 领域专家: 操作系统技术领域
博客等级 码龄14年 325粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值