MVP设计模式的优化与实践

Android 开发:从程序员到架构师的路径与策略 此外,遵循 SOLID 原则(单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则和依赖倒置原则)可以提高代码的可读性和可维护性。掌握 Android 框架、设计模式和架构原则,学习常用的架构模式,并实践软件设计原则和性能优化技巧,关注最新技术和趋势,并持续学习和实践,这些都是成为一名合格的 Android 架构师的关键步骤。Android 技术发展迅速,作为一名架构师,你需要关注最新的技术和趋势,以保持竞争力并应对快速变化的需求。选择适合你项目需求的架构模式,并结合你的经验和实际情况进行调整。 阅读详情

    APP开发最让人头疼的就是业务逻辑和UI代码混合起来,造成后期APP很难维护,新需求越来越难加入,因为依赖太多了,而且纷繁复杂。后来有人提出MVP模式,既然业务逻辑要依赖UI,那么为什么不把他们之间用一个接口隔离开呢,让业务逻辑依赖UI更新的接口而不管具体的UI是如何更新的,更新UI的具体代码则交给Activity来做。当我们进行实践的时候,问题来了,我们需要定义大量接口,而且看似架构很严谨的MVP模式在实际应用当中变得过于臃肿。好了,既然出现了这个问题,那就得解决,Presenter臃肿,有人单独提出一个Presenter分开成多个并且按功能模块划分,对于Presenter来说这样划分是很合理的。同理ViewModel。 但是IView层就还是老样子,即使我们缩减接口,并用方法参数代替要更新哪个UI也没有解决接口爆炸的问题。而且还有了新的问题,那就是我更新UI的时候Activity我并不知道是否已经走了onDestory。 MVP的设计模式根本问题在于接口爆炸,要想减少接口,那必须让业务逻辑和UI逻辑不依赖同一个接口,那尝试一下让UI依赖Model吧,也就是说不管我们业务逻辑如何变化,最终更新UI我们只需要更新Model,MVVM诞生了。

    我觉得没有必要纠结形式,MVVM其实就是观察者模式,使用观察者代替接口,而被观测的对象就是Model。我们再也不需要在UI需要更新的时候去通知接口了,当需要更新UI的时候直接通知观察者。而观察者保存在Activity当中,并且感知Activity的生命周期变化,这样观察者就可以决定是否要执行UI的更新。

    总结,我们仍然可以使用Presenter来划分我们的业务逻辑,然后当需要更新UI的时候通知观察者,即更新Model来驱动,如此Activity依赖ViewModel注册观察者, Presenter依赖ViewModel通知观察者。我认为,这应该才是MVP最佳的实践。由接口爆炸变成了观察者和被观察者爆炸,但是我们不用严格的遵循必须实现那个定死的更新UI的接口了。我们将每个业务过程当做一个状态机,随着业务流程的进行,model的状态会发生改变,这样我们通过观察者来更新UI就成为了可能, 并且这些状态不是零散的,而是随业务逻辑有规则变化的。

举个简单的demo感受一下新的MVP设计模式,以用户登录为例。

这是我们的Model,我们定义了一个登录状态。

public class MainActivityModel extends ViewModel{
    public static final int LOGIN_START   =  1;
    public static final int LOGIN_SUCCESS =  2;
    public static final int LOGIN_FAIL    = -1;
    public MutableLiveData<Integer> loginState = new MutableLiveData<>();
}

这是我们的Presenter, doLogin模拟了登录请求

public class MainActivityPresenter {

    private MainActivityModel mModel;

    public void registerViewModel(ViewModel model){
        mModel = (MainActivityModel) model;
    }


    public void doLogin(String userName, String userPswd){
        //我们使用一线程来模拟用户登录的网络请求, 这里我们就不处理方法的参数了
        new Thread(new Runnable() {
            @Override
            public void run() {
                mModel.loginState.postValue(MainActivityModel.LOGIN_START);
                try {
                    //与服务器交互耗时2s
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    mModel.loginState.postValue(MainActivityModel.LOGIN_FAIL);
                }
                mModel.loginState.postValue(MainActivityModel.LOGIN_SUCCESS);
            }
        }).start();


    }


}

这是我们的主Activity:完成了拼装,注意看我们是如何处理UI更新的


public class MainActivity extends AppCompatActivity {

    private EditText mUserNameEdit;
    private EditText mUserPswdEdit;
    private Button mLoginBtn;
    private ProgressBar mProgressBar;

    private MainActivityPresenter mPresenter;
    private MainActivityModel mModel;

    private void findView(){
        mUserNameEdit = findViewById(R.id.username_edit);
        mUserPswdEdit = findViewById(R.id.userpswd_edit);
        mLoginBtn = findViewById(R.id.login_btn);
        mProgressBar = findViewById(R.id.progress_bar);
    }

//初始化model 和presenter, 并且注册观察者
    private void initMVP(){
        mPresenter = new MainActivityPresenter();
        mModel = ViewModelProviders.of(this).get(MainActivityModel.class);
        mPresenter.registerViewModel(mModel);
        registerObservers();
    }

    private void registerObservers(){
        //为登录状态注册观察者
        mModel.loginState.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable Integer integer) {
                switch(integer){
                    case MainActivityModel.LOGIN_START:{
                        //开始登录的时候我们显示一个进度条
                        mProgressBar.setVisibility(View.VISIBLE);
                        break;
                    }
                    case MainActivityModel.LOGIN_SUCCESS:{
                        //登录成功我们隐藏进度条,并且提示用户登录成功
                        mProgressBar.setVisibility(View.GONE);
                        Toast.makeText(MainActivity.this, "login success",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    case MainActivityModel.LOGIN_FAIL:{
                        //登录成功我们隐藏进度条,并且提示用户登录失败
                        mProgressBar.setVisibility(View.GONE);
                        Toast.makeText(MainActivity.this, "login fail",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    default:{
                        mProgressBar.setVisibility(View.GONE);
                        Toast.makeText(MainActivity.this, "Unknown login state",
                                Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initMVP();
        findView();

        mLoginBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //调用presenter处理业务逻辑
                mPresenter.doLogin(mUserNameEdit.getEditableText().toString(),
                        mUserPswdEdit.getEditableText().toString());
            }
        });
    }


}

看到了吧,我们不需要实现任何接口即可实现业务逻辑和UI代码的分离,UI的更新完全依赖与业务逻辑所处的状态。

你也可以将数据Integer换成别的类型,但是应该包含一个状态用来更新UI。比如这样

public class User {
    public int state;
    public String username;
    public String userpswd;
}
public class MainActivityModel extends ViewModel{
    public static final int LOGIN_START   =  1;
    public static final int LOGIN_SUCCESS =  2;
    public static final int LOGIN_FAIL    = -1;
    public MutableLiveData<User> loginState = new MutableLiveData<>();
}

    private void registerObservers(){
        //为登录状态注册观察者
        mModel.loginState.observe(this, new Observer<User>() {
            @Override
            public void onChanged(@Nullable User user) {
                switch(user.state){
                    case MainActivityModel.LOGIN_START:{
                        //开始登录的时候我们显示一个进度条
                        mProgressBar.setVisibility(View.VISIBLE);
                        break;
                    }
                    case MainActivityModel.LOGIN_SUCCESS:{
                        //登录成功我们隐藏进度条,并且提示用户登录成功
                        mProgressBar.setVisibility(View.GONE);
                        Toast.makeText(MainActivity.this, "login success",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    case MainActivityModel.LOGIN_FAIL:{
                        //登录成功我们隐藏进度条,并且提示用户登录失败
                        mProgressBar.setVisibility(View.GONE);
                        Toast.makeText(MainActivity.this, "login fail",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    default:{
                        mProgressBar.setVisibility(View.GONE);
                        Toast.makeText(MainActivity.this, "Unknown login state",
                                Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
    }




这种模式有哪些缺点呢?首先问题出在postvalue上,postvalue是异步的,并且postvalue在实现上为了考虑效率,如果连续调用postvalue,那么post到主线程的是最后一次post的值,和我们的预期不符,那怎么办呢????  如果能全部post过去就行了

public class MainActivityPresenter {

    private MainActivityModel mModel;
    private Handler mHandler = new Handler(Looper.getMainLooper());

    public void registerViewModel(ViewModel model){
        mModel = (MainActivityModel) model;
    }


    public void doLogin(final String userName, final String userPswd){
        //我们使用一线程来模拟用户登录的网络请求, 这里我们就不处理方法的参数了


        new Thread(new Runnable() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        //mModel.loginState.postValue(new Integer(MainActivityModel.LOGIN_START));
                        mModel.loginState.setValue(MainActivityModel.LOGIN_START);
                    }
                });
                try {
                    //与服务器交互耗时2s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            //mModel.loginState.postValue(new Integer(MainActivityModel.LOGIN_FAIL));
                            mModel.loginState.setValue(MainActivityModel.LOGIN_FAIL);
                        }
                    });

                }


                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        //mModel.loginState.postValue(new Integer(MainActivityModel.LOGIN_SUCCESS));
                        mModel.loginState.setValue(MainActivityModel.LOGIN_SUCCESS);
                    }
                });

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        //mModel.loginState.postValue(new Integer(MainActivityModel.LOGIN_FINISH));
                        mModel.loginState.setValue(MainActivityModel.LOGIN_FINISH);
                    }
                });

                User user = new User();
                user.username = userName;
                user.userpswd = userPswd;
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        //mModel.user.postValue(user);
                        mModel.user.setValue(user);
                    }
                });


            }
        }).start();


    }


}

但是这样做代码太不优雅了,好多runnable,如果你用lamda代替也是很不美观,继续优化封装,我们自定义一个LiveData

public class SequencePostLiveData<T> extends MutableLiveData<T> {
    
    private Handler mHandler = new Handler(Looper.getMainLooper());
    /**
     * sequencially update value
     * @param value
     */
    public void seqPostValue(T value){

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                setValue(value);
            }
        });
    }
}

然后代码这样改写:

public class MainActivityModel extends ViewModel{
    public static final int LOGIN_START   =  1;
    public static final int LOGIN_SUCCESS =  2;
    public static final int LOGIN_FINISH  =  3;
    public static final int LOGIN_FAIL    = -1;
    public SequencePostLiveData<Integer> loginState = new SequencePostLiveData<>();
    public SequencePostLiveData<User> user = new SequencePostLiveData<>();
}
public class MainActivityPresenter {

    private MainActivityModel mModel;
    public void registerViewModel(ViewModel model){
        mModel = (MainActivityModel) model;
    }


    public void doLogin(final String userName, final String userPswd){
        //我们使用一线程来模拟用户登录的网络请求, 这里我们就不处理方法的参数了


        new Thread(new Runnable() {
            @Override
            public void run() {
                mModel.loginState.seqPostValue(MainActivityModel.LOGIN_START);
                try {
                    //与服务器交互耗时2s
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    mModel.loginState.seqPostValue(MainActivityModel.LOGIN_FAIL);
                }
                
                mModel.loginState.seqPostValue(MainActivityModel.LOGIN_SUCCESS);
                mModel.loginState.seqPostValue(MainActivityModel.LOGIN_FINISH);
                User user = new User();
                user.username = userName;
                user.userpswd = userPswd;
                mModel.user.seqPostValue(user);
            }
        }).start();
    }
}

这样代码优雅很多。 可是你会问为什么要这样写代码呢?为什么有需要连续postvalue两次的需求?

因为我们每一次postvalue都必须要求ui进行更新,由于UI在主线程运行,那么post到主线程的runnable就能顺序执行。设计SUCCESS和FINISH两个状态的初衷是我在SUCCESS状态更新UI的时候弹出了Toast, 如果这个时候我旋转屏幕那么会导致Toast又弹出来一次, LiveData是会处理像屏幕旋转这种configuration change的,并且旋转过后根据状态更新UI,保证界面跟原来一样。

具体详见Demo吧 demo下载地址,5分

https://download.youkuaiyun.com/download/mtaxot/10519198


掌握MVP设计模式:Android开发入门示例 MVP(Model-View-Presenter)模式起源于软件工程领域,旨在实现更清晰的架构分层,从而提升代码的可维护性和测试性。MVP模式通过分离用户界面(View)和业务逻辑(Model),以Presenter作为中间人,增强了模块间的独立性和重用性。在MVP架构中,接口是联系View与Presenter,以及Model与Presenter之间的桥梁。接口定义了需要实现的方法,但不指定如何实现这些方法,这使得实现可以根据实际需求灵活变更,而不影响其他模块。 阅读详情

相关推荐

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

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

weixin_31800911的博客 769

对于 MVP 应用架构的理解及其优化改造

MVP 架构 MVP架构由MVC发展而来。在MVP中,M代表Model,V代表View,P代表Presenter。 Model 负责获取数据,数据的来源可以是网络或本地数据库等; View 负责界面数据的展示,与用户进行交互; Presenter 是Model与View之间的通信的桥梁,将Model与View分离开来,也是业务进行实现的地方; 这三个层面之间的关系如下: 我们先简单用一个简单...

李斯维的博客空间 820

深入解析谷歌官方Android TV开发框架与TVWidget课程PPT

随着智能家居的普及,Android TV作为家庭娱乐系统的核心,其重要性不言而喻。它不仅改变了人们的观看习惯,也为开发者提供了新的应用平台和商业机遇。Android TV的开发框架将如何适应快速变化的市场需求,是本章将探讨的核心内容。Android TV平台支持各种类型的硬件组件,这些硬件组件是构建流畅用户体验的基础。理解这些硬件类型对于开发人员来说至关重要,因为它们决定了应用的性能和功能。常见的硬件类型包括CPU、GPU、内存、存储空间、蓝牙、Wi-Fi、红外接收器和声音系统。

weixin_42576186的博客 966

Android App开发架构之:MVP,关于网络优化你必须要知道的重点

相对于MVC架构,MVP架构对应的内容也有了调整:V层对应Activity和Fragment,或者自定义的View;P层需要自己创建,用来处理业务逻辑;M层同MVC的M,也是需要自己创建,用来处理数据的。优点View层改为Activity和Fragment,只负责UI的更新;Presenter层角色变成Controller,只负责业务逻辑处理;而Model层跟MVC架构中的Model一样,负责底层功能模块实现;

2401_83620959的博客 709

23个设计模式完整DEMO

23个设计模式完整DEMO,23个设计模式完整DEMO,23个设计模式完整DEMO

MVP设计模式demo

MVP设计模式的一个demo,简单的介绍了mvp模式的使用,代码中关于model、view、presenter层都有响应的注释。希望能够帮到大家。

MVP模式优化与进阶

MVP作为近段时间比较流行的架构,相信大家都有一定了解,所以这里不再阐述MVP的基本概念与优缺点。本文重点在于从自身项目出发,归纳整理的一些MVP的一些心得体会,如果能对大家有所帮助和启发,万分荣幸。 首先来说说使用了MVP近一年后,现在项目中MVP的变化。传统MVP模式,大家都知道是以activity或fragment为View,然后同时创建一个Presenter和Model类,并且View持

Android_BlackCat的博客 920

sram设计流程+memory compiler整理

→。

qq_50761108的博客 1万+

Java性能优化十一、设计模式优化

文章目录设计模式优化一、单例模式:如何创建单一对象优化系统性能1、什么是单例模式2、饿汉模式3、懒汉模式4、通过内部类实现懒汉模式总结二、原型模式与享元模式:提升系统性能的利器1、原型模式1.深拷贝和浅拷贝2.适用场景2、享元模式总结 设计模式优化 一、单例模式:如何创建单一对象优化系统性能 在《Design Patterns: Elements of Reusable Object-Oriented Software》一书中,有 23 种设计模式的描述,其中,单例设计模式是最常用的设计模式之一。无论是在.

小宇哥x的博客 670

SAP MM自动化进阶:STO交货单自动创建的配置与优化

本文深入解析了SAP MM模块中实现公司间库存调拨订单(STO)交货单自动创建的完整配置流程与优化策略。通过激活自动交货与绑定发货点两大核心配置,打通自动化链路。重点探讨了如何集成ATP可用性检查以智能处理库存不足等异常场景,确保自动化流程的可靠性与业务贴合度,并提供了进阶监控与问题排查方法,助力企业显著提升供应链效率。

weixin_29206669的博客 124

集成calibre到cadence virtuoso环境中 load: can‘t access file - “/opt/eda/Mentor/lib/calibre.skl“

项目场景: 设想是将Calibre集成到cadence virtuoso中,但网上的解决办法尝试过在本机上实验都有点问题,因此想记录下来我的解决办法仅供参考。 问题描述: 安装好cadence, calibre之后打开virtuoso,CIW窗口显示 *Error* load: can't access file - "/opt/eda/Mentor/lib/calibre.skl" 问题是出在calibre.skl的加载路径出错,尝试网上的在工程目录下修改.cdsinit文件,添加calibre安装

weixin_52714276的博客 1万+

设计模式 (六) 设计模式优化系列

设计模式优化系列:介绍如何优化设计模式的实现,包括如何提高设计模式的性能、如何减少设计模式的复杂度、如何提高设计模式的可维护性等

Jackchen 的博客 349

ArcGIS学习记录—SHP文件转换为KML KMZ数据,并显示面要素相应的标注

使用相应软件操作获取KMZ数据得以下发到外业调查人员,使得矢量数据能够更显而易见,可视化,让外业人员的工作减轻许多。(过程步骤是借鉴于网络上的相关人士给的建议,根据这些建议自己做出来的步骤,可能有些粗略,有问题的话可以再进行探讨)...

qq_41046162的博客 5万+

理论篇 前端MVC、MVP、MVVM思考1

  基于JAVA EE平台的后端实现中,通常使用Struts或者Srping MVC框架来实现MVC,Modal代表数据库层面的原始数据,View代表展现层面的视图元素,一个项目下若干个的大功能通过不同的URL映射进行功能分解;   后端的Controller从承担职责的角度来考虑分为两类:   1. 基于Router的路由:将项目的很多块功能分解;   2. 某一大功能下数据的展现:根据...

weixin_30550271的博客 190

西电计组实验一 存储器实验

计组实验报告 实验一 存储器实验——FPGA中LPM_ROM定制与读出实验 一.实验目的   1.掌握FPGA中lpm_ROM的设置,作为只读存储器ROM的工作特性和配置方法;   2.用文本编辑器编辑mif文件配置ROM,学习将程序代码以mif格式文件加载于lpm_ROM中;   3.在初始化存储器编辑窗口编辑mif文件配置ROM;   4.验证FPGA中mega_lpm_ROM的功能。 二.实验原理   ALTERA的FPGA中有许多可调用的LPM (Library Parameterized Modu

Polaris的博客 1万+

2026 年 3 月青少年软编等考 C/C++ 三级测试题解析

摘要 本文包含三部分内容: 单选题(10题):考察C++基础语法和数据结构知识,涉及vector、栈、队列的操作和特性。 判断题(10题):测试对动态数组、栈、队列、字符串操作的理解,包括内存管理、访问方式和函数返回值等。 编程题(1题):模拟火车站售票窗口排队场景,要求根据输入输出各窗口的排队情况,重点考查队列的实际应用和边界条件处理。 答案解析详细,涵盖常见编程考点,适合检验基础知识的掌握程度。

发布少儿编程考级的真题和优秀竞赛题解析,以及一些讲义。 247

面试怎么学,我是如何准备-Android-技术面试的,字节跳动超高难度三面Android程序员面经

学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!最后,祝愿即将跳槽和已经开始求职的大家都能找到一份好的工作,这些面试题分享在我的**Android IOC架构设计**群里,可以来群里下载,群里还有一些行业大牛,群里也会有不定时送书等活动,欢迎前来下载。原文链接:https://www.jianshu.com/p/a1a68a15ddde【附】相关架构及资料资料领取Android IOC架构设计。

m0_74931167的博客 628

【AI大模型应用开发】【LangChain系列】实战案例6:利用大模型进行文本总结的方法探索,文本Token超限怎么办?

假设有一组文档(PDF、Notion页面、客户问题等),你想要总结内容。可以利用大模型来帮你。今天来系统看下利用大模型来对文本进行总结的方法,以LangChain的使用为例。

同学小张的博客 3749

走进Android架构,体会架构师的魅力(附架构师必备技术详解)

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。资料免费领取方式:现在关注我后去我的主页加一下技术群免费获取~不论遇到什么困难,都不应该成为我们放弃的理由!如果你看到了这里,觉得文章写得不错就给个赞呗?

2401_83641443的博客 825

【AI Agent 记忆共享实战】【下篇】多 Agent 会话 Session 统一共享实战:全链路工程落地、采集归一、MCP 服务、私有化部署、源码级实战

中篇我们已经锁定最终最优架构方案: 非侵入式、外部旁路采集、只读归一、中心化存储、MCP 按需检索注入。摒弃「改 Agent 源码」「软链接互通」「原生 Session 互导」等不现实方案。本篇直接落地可上线、可简历复用、可个人私有化部署多 Agent 异构 Session专属采集器(Claude/CODex/DSH/OpenCode/Kimi/WorkBuddy/ 豆包)统一消息归一化解析层(解决所有 Schema 异构)增量同步、去重、时间戳对齐核心逻辑。

十年老程序猿,AI 疯狂研究专家,前沿硬核知识分享 476

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

AI Agent设计模式入门:7种核心模式解析与实践

AI Agent作为自主感知与决策的智能系统,其核心在于通过模块化设计模式实现复杂任务分解。从技术原理看,设计模式通过标准化交互流程(如对话链)、状态管理(如状态机)和工具扩展(如API调用)三大维度,显著提升Agent的工程化能力。在应用层面,这些模式可快速落地于客服机器人、流程自动化等场景,其中工具调用模式能直接提升40%的问题解决率。本文以Python为例,详解包括多Agent协作在内的7种生产级模式实现方案,涵盖异常处理、性能优化等关键实践。

weixin_29056701的博客 38

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Android从初级到中级,记录一次Android面试,android基础控件

(一)调整好心态心态是一个人能否成功的关键,如果不调整好自己的心态,是很难静下心来学习的,尤其是现在这么浮躁的社会,大部分的程序员的现状就是三点一线,感觉很累,一些大龄的程序员更多的会感到焦虑,而且随着年龄的增长,这种焦虑感会越来越强烈,那么唯一的解决办法就是调整好自己的心态,要做到自信、年轻、勤奋。这样的调整,一方面对自己学习有帮助,另一方面让自己应对面试更从容,更顺利。(二)时间挤一挤,制定好计划一旦下定决心要提升自己,那么再忙的情况下也要每天挤一挤时间,切记不可“两天打渔三天晒网”。

2401_84150107的博客 828

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Android基础 进阶知识点

Activity、View、Window的理解,Activity 是如何生成一个 view  LaunchMode的使用场景, 描述下MVP app换肤 模块化开发 热修复原理 框架  AndFix  tinker  robustw 常用的设计模式 三级缓存 webView与js交互  webview优化 Service与Activity之间通信的几种方式 代码质量 代码管

weixin_38450600的博客 336

android架构师路线图,Android 架构师技能图谱

# Android 架构师技能图谱## 架构与设计- 设计模式- 重构- 技术选型- 特性- 可用性- 性能- 包大小- 方法数- 文档- 技术支持- UI架构模式- MVC- MVP- MVVM## 研发工具- 集成开发环境- Android Studio- Sublime Text- 版本控制系统- svn- git- gitlab- github- mercurial- 调试工具- ADB-...

weixin_34137872的博客 192

Android面试题汇总(1),BAT面试&高级进阶

现在项目的整体设计是怎么样的降低crash率做了哪些处理怎么检测线上卡顿问题kotlin相比于java有哪些优势什么时机可以认为页面加载完成内存优化有做过哪些讲下merge和include讲下运营商DNS劫持,又是如何防止DNS劫持怎么使用Fragment的, 是采用一个Activity多个Fragment的形式么有没有使用过一些跨端技术项目合并做了哪些事情怎么检测线上卡顿怎么检测线上内存泄漏做了哪些性能优化最近研究了哪些新技术,谈谈看法何如学习提高自己的技术。

2401_84150137的博客 767

Android从初级到中级,记录一次Android面试

17.除了LruCache这个最少使用算法,还有什么其它算法的实现?有了解过FIFO算法么?18.java这方面怎么样?有了解过GC吗?内存优化性能优化这块做过吗?说下GC怎么操作的!19.那内存优化和性能分析?平时怎么做优化的,用过什么工具吗?20.那用过什么工具吗?21…最近的项目有短视频和生活服务类的。

2401_84010816的博客 797
上一篇: Linux C 整理-1
下一篇: mac搭建wxWidgets开发环境,使用xcode
mtaxot
博客等级 码龄16年 29粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值