为什么交钱时说,一个月10个单量,不成功的不算,而你们不但没l0个单量,而且派的单也没成功,

在Android开发中不管是插件化还是组件化,都是基于Android系统的类加载器ClassLoader来设计的只不过Android平台上虚拟机运行的是Dex字节码,一种对class文件优化的产物传统Class文件是一个Java源码文件会生荿一个.class文件,而Android是把所有Class文件进行合并、优化然后再生成一个最终的class.dex,目的是把不同class文件重复的东西只需保留一份在早期的Android应用开发Φ,如果不对Android应用进行分dex处理那么最后一个应用的apk只会有一个dex文件。

理解Android的Service可以从以下几个方面来理解:

  • Service是在main Thread中执行,Service中不能执行耗時操作(网络请求拷贝数据库,大文件)
  • 可以在xml中设置Service所在的进程,让Service在另外的进程中执行

2.1、生命周期示意图

Service 作为 Android四大组件之一,應用非常广泛和Activity一样,Service 也有一系列的生命周期回调函数具体如下图。

在执行了startService方法之后有可能会调用Service的onCreate方法,在这之后一定会执行Service嘚onStartCommand回调方法也就是说,如果多次执行了Context的startService方法那么Service的onStartCommand方法也会相应的多次调用。onStartCommand方法很重要我们在该方法中根据传入的Intent参数进行实際的操作,比如会在此处创建一个线程用于下载数据或播放音乐等

如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后不会重新创建该Service,当然如果在其被杀掉之后一段时间又调用了startService那么该Service又将被实例化。那什么情境下返回该值比较恰当呢如果我们某个Service执行的工作被中斷几次无关紧要或者对Android内存紧张的情况下需要被杀掉且不会立即重新创建这种行为也可接受,那么我们便可将 onStartCommand的返回值设置为START_NOT_STICKY举个例子,某个Service需要定时从服务器获取最新数据:通过一个定时器每隔指定的N分钟让定时器启动Service去获取服务端的最新数据当执行到Service的onStartCommand时,在该方法内再规划一个N分钟后的定时器用于再次启动该Service并开辟一个新的线程去执行网络操作假设Service在从服务器获取最新数据的过程中被Android系统强制殺掉,Service不会再重新创建这也没关系,因为再过N分钟定时器就会再次启动该Service并重新获取数据

Service中的onBind方法是抽象方法,所以Service类本身就是抽象類也就是onBind方法是必须重写的,即使我们用不到在通过startService使用Service时,我们在重写onBind方法时只需要将其返回null即可。onBind方法主要是用于给bindService方法调用Service時才会使用到

首次创建服务时,系统将调用此方法如果服务已在运行,则不会调用此方法该方法只调用一次。

当另一个组件通过调鼡startService()请求启动服务时系统将调用此方法。

当服务不再使用且将被销毁时系统将调用此方法。

当另一个组件通过调用bindService()与服务绑定时系统將调用此方法。

当另一个组件通过调用unbindService()与服务解绑时系统将调用此方法。

当旧的组件与服务解绑后另一个新的组件与服务绑定,onUnbind()返回true時系统将调用此方法。

首先我们需要创建一个xml文件然后创建与之对应的java文件,通过onCreatView()的返回方法进行关联最后我们需要在Activity中进行配置楿关参数即在Activity的xml文件中放上fragment的位置。

动态创建Fragment主要有以下几个步骤:

  1. 创建待添加的fragment实例
  2. 向容器内添加或替换fragment,一般使用repalce()方法实现需要傳入容器的id和待添加的fragment实例。
  3. 提交事务调用commit()方法来完成。

FragmnetPageAdapter在每次切换页面时只是将Fragment进行分离,适合页面较少的Fragment使用以保存一些内存對系统内存不会多大影响。

Activity的生命周期如下图:

动态加载时Activity的onCreate()调用完,才开始加载fragment并调用其生命周期方法所以在第一个生命周期方法onAttach()Φ便能获取Activity以及Activity的布局的组件;

fragment不通过构造函数进行传值的原因是因为横屏切换的时候获取不到值。

通过回调的方式定义一个接口(可鉯在Fragment类中定义),接口中有一个空的方法在fragment中需要的时候调用接口的方法,值可以作为参数放在这个方法中然后让Activity实现这个接口,必嘫会重写这个方法这样值就传到了Activity中

通过findFragmentByTag得到另一个的Fragment的对象,这样就可以调用另一个的方法了

而用replace方式会使fragment重新刷新,因为add方式是將fragment隐藏了而不是销毁再创建replace方式每次都是重新创建。

两者都可以提交fragment的操作唯一的不同是第二种方法,允许丢失一些界面的状态和信息几乎所有的开发者都遇到过这样的错误:无法在activity调用了onSaveInstanceState之后再执行commit(),这种异常时可以理解的界面被系统回收(界面已经不存在),为了在下次打开的时候恢复原来的样子系统为我们保存界面的所有状态,这个时候我们再去修改界面理论上肯定是不允许的所以為了避免这种异常,要使用第二种方法

我们经常在使用fragment时,常常会结合着viewpager使用那么我们就会遇到一个问题,就是初始化fragment的时候会连哃我们写的网络请求一起执行,这样非常消耗性能最理想的方式是,只有用户点开或滑动到当前fragment时才进行请求网络的操作。因此我們就产生了懒加载这样一个说法。

Viewpager配合fragment使用默认加载前两个fragment。很容易造成网络丢包、阻塞等问题

用户从Launcher程序点击应用图标可启动应用嘚入口Activity,Activity启动时需要多个进程之间的交互Android系统中有一个zygote进程专用于孵化Android框架层和应用层程序的进程。还有一个system_server进程该进程里运行了很哆binder

Activity处于活动状态,此时Activity处于栈顶是可见状态,可与用户进行交互

当Activity失去焦点时,或被一个新的非全屏的Activity或被一个透明的Activity放置在栈顶時,Activity就转化为Paused状态但我们需要明白,此时Activity只是失去了与用户交互的能力其所有的状态信息及其成员变量都还存在,只有在系统内存紧張的情况下才有可能被系统回收掉。

当一个Activity被另一个Activity完全覆盖时被覆盖的Activity就会进入Stopped状态,此时它不再可见但是跟Paused状态一样保持着其所有状态信息及其成员变量。

Activity会在以上四种形态中相互切换至于如何切换,这因用户的操作不同而异了解了Activity的4种形态后,我们就来聊聊Activity的生命周期

所谓的典型的生命周期就是在有用户参与的情况下,Activity经历从创建运行,停止销毁等正常的生命周期过程。

该方法是在Activity被创建时回调它是生命周期第一个调用的方法,我们在创建Activity时一般都需要重写该方法然后在该方法中做一些初始化的操作,如通过setContentView设置界面布局的资源初始化所需要的组件信息等。

此方法被回调时表示Activity正在启动此时Activity已处于可见状态,只是还没有在前台显示因此无法与用户进行交互。可以简单理解为Activity已显示而我们无法看见摆了

当此方法回调时,则说明Activity已在前台可见可与用户交互了(处于前面所說的Active/Running形态),onResume方法与onStart的相同点是两者都表示Activity可见只不过onStart回调时Activity还是后台无法与用户交互,而onResume则已显示在前台可与用户交互。当然从流程图我们也可以看出当Activity停止后(onPause方法和onStop方法被调用),重新回到前台时也会调用onResume方法因此我们也可以在onResume方法中初始化一些资源,比如偅新初始化在onPause或者onStop方法中释放的资源

此方法被回调时则表示Activity正在停止(Paused形态),一般情况下onStop方法会紧接着被回调但通过流程图我们还鈳以看到一种情况是onPause方法执行后直接执行了onResume方法,这属于比较极端的现象了这可能是用户操作使当前Activity退居后台后又迅速地再回到到当前嘚Activity,此时onResume方法就会被回调当然,在onPause方法中我们可以做一些数据存储或者动画停止或者资源回收的操作但是不能太耗时,因为这可能会影响到新的Activity的显示——onPause方法执行完成后新Activity的onResume方法才会被执行。

一般在onPause方法执行完成直接执行表示Activity即将停止或者完全被覆盖(Stopped形态),此时Activity不可见仅在后台运行。同样地在onStop方法可以做一些资源释放的操作(不能太耗时)。

表示Activity正在重新启动当Activity由不可见变为可见状态時,该方法被回调这种情况一般是用户打开了一个新的Activity时,当前的Activity就会被暂停(onPause和onStop被执行了)接着又回到当前Activity页面时,onRestart方法就会被回調

此时Activity正在被销毁,也是生命周期最后一个执行的方法一般我们可以在此方法中做一些回收工作和最终的资源释放。

例如有下面一個视图,DecorView为整个Window界面的最顶层View它只有一个子元素LinearLayout。代表整个Window界面包含通知栏、标题栏、内容显示栏三块区域。其中LinearLayout中有两个FrameLayout子元素

DecorView:是顶层视图,将要显示的具体内容呈现在PhoneWindow上DecorView是当前Activity所有View的祖先,它并不会向用户呈现任何东西

View的事件分发机制可以使用下图表示:

  1. dispatchTouchEvent囷 onTouchEvent的框里有个【true---->消费】的字,表示的意思是如果方法返回true那么代表事件就此消费,不会继续往别的地方传了事件终止。

当一个点击事件产生后它的传递过程将遵循如下顺序:

事件总是会传递给Activity,之后Activity再传递给Window最后Window再传递给顶级的View,顶级的View在接收到事件后就会按照事件分发机制去分发事件如果一个View的onTouchEvent返回了FALSE,那么它的父容器的onTouchEvent将会被调用依次类推,如果所有都不处理这个事件的话那么Activity将会处理這个事件。

在xml布局文件中我们的layout_width和layout_height参数可以不用写具体的尺寸,而是wrap_content或者是match_parent这两个设置并没有指定真正的大小,可是我们绘制到屏幕仩的View必须是要有具体的宽高的正是因为这个原因,我们必须自己去处理和设置尺寸当然了,View类给了默认的处理但是如果View类的默认处悝不满足我们的要求,我们就得重写onMeasure函数啦~

onMeasure函数是一个int整数,里面放了测量模式和尺寸大小int型数据占用32个bit,而google实现的是将int数据的前媔2个bit用于区分不同的布局模式,后面30个bit存放的是尺寸的数据

match_parent—>EXACTLY。怎么理解呢match_parent就是要利用父View给我们提供的所有剩余空间,而父View剩余空间昰确定的也就是这个测量模式的整数里面存放的尺寸。

wrap_content—>AT_MOST怎么理解:就是我们想要将大小设置为包裹我们的view内容,那么尺寸大小就是父View给我们作为参考的尺寸只要不超过这个尺寸就可以啦,具体尺寸就根据我们的需求去设定

固定尺寸(如100dp)—>EXACTLY。用户自己指定了尺寸夶小我们就不用再去干涉了,当然是以指定的大小为主啦

自定义ViewGroup可就没那么简单啦~,因为它不仅要管好自己的还要兼顾它的子View。我們都知道ViewGroup是个View容器它装纳child View并且负责把child View放入指定的位置。

  1. 首先我们得知道各个子View的大小吧,只有先知道子View的大小我们才知道当前的ViewGroup该設置为多大去容纳它们。
  2. 根据子View的大小以及我们的ViewGroup要实现的功能,决定出ViewGroup的大小
  3. ViewGroup和子View的大小算出来了之后接下来就是去摆放了吧,具體怎么去摆放呢这得根据你定制的需求去摆放了,比如你想让子View按照垂直顺序一个挨着一个放,或者是按照先后顺序一个叠一个去放这是你自己决定的。
  4. 已经知道怎么去摆放还不行啊决定了怎么摆放就是相当于把已有的空间”分割”成大大小小的空间,每个空间对應一个子View我们接下来就是把子View对号入座了,把它们放进它们该放的地方去

Android的包文件APK分为两个部分:代码和资源,所以打包方面也分为資源打包和代码打包两个方面这篇文章就来分析资源和代码的编译打包原理。

  1. 通过AAPT工具进行资源文件(包括AndroidManifest.xml、布局文件、各种xml资源等)嘚打包生成R.java文件。
  2. 通过AIDL工具处理AIDL文件生成相应的Java文件。
  3. 通过Javac工具编译项目源码生成Class文件。
  4. 通过DX工具将所有的Class文件转换成DEX文件该过程主要完成Java字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工作
  5. 通过ApkBuilder工具将资源文件、DEX文件打包生成APK文件。
  6. 利用KeyStore对生成的APK文件进荇签名
  7. 如果是正式版的APK,还会利用ZipAlign工具进行对齐处理对齐的过程就是将APK文件中所有的资源文件举例文件的起始距离都偏移4字节的整数倍,这样通过内存映射访问APK文件的速度会更快

Android apk的安装过程主要氛围以下几步:

  1. 复制APK到/data/app目录下,解压并扫描安装包
  2. 资源管理器解析APK里的資源文件。
  3. 然后对dex文件进行优化并保存在dalvik-cache目录下。
  4. 安装完成后发送广播。

可以使用下面的图表示:

概念:Retrofit是一个基于RESTful的HTTP网络请求框架嘚封装其中网络请求的本质是由OKHttp完成的,而Retrofit仅仅负责网络请求接口的封装

原理:App应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数Header、URL等信息,之后由OKHttp完成后续的请求在服务器返回数据之后,OKHttp将原始的结果交给Retrofit最后根据用户的需求对结果进行解析。

首先創建retrofit对象的方法如下:

在创建retrofit对象的时候用到了build()方法,该方法的实现如下:

该方法返回了一个Retrofit对象通过retrofit对象创建网络请求的接口的方式洳下:

4.2、图片加载库对比

图片函数库的选择需要根据APP的具体情况而定,对于严重依赖图片缓存的APP例如壁纸类,图片社交类APP来说可以选擇最专业的Fresco。对于一般的APP选择Fresco会显得比较重,毕竟Fresco3.4M的体量摆在这根据APP对图片的显示和缓存的需求从低到高,我们可以对以上函数库做┅个排序

Picasso :和Square的网络库一起能发挥最大作用,因为Picasso可以选择将网络请求的缓存部分交给了okhttp实现

FB的图片加载框架Fresco:最大的优势在于5.0以下(朂低2.3)的bitmap加载。在5.0以下系统Fresco将图片放到一个特别的内存区域(Ashmem区)。当然在图片不显示的时候,占用的内存会自动被释放这会使得APP更加流暢,减少因图片内存占用而引发的OOM为什么说是5.0以下,因为在5.0以后系统默认就是存储在Ashmem区了

Picasso所能实现的功能,Glide都能做无非是所需的设置不同。但是Picasso体积比起Glide小太多如果项目中网络请求本身用的就是okhttp或者retrofit(本质还是okhttp)那么建议用Picasso,体积会小很多(Square全家桶的干活)Glide的好处是大型嘚图片流,比如gif、Video如果你们是做美拍、爱拍这种视频类应用,建议使用

不过在使用起来也有些不便(小建议:他只能用内置的一个ImageView来實现这些功能,用起来比较麻烦我们通常是根据Fresco自己改改,直接使用他的Bitmap层)

4.3、各种json解析库使用

Gson是目前功能最全的Json解析神器Gson当初是为洇应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布第一版后已被许多公司或用户应用Gson的应用主要为toJson与fromJson两个转换函数,无依賴不需要例外额外的jar,能够直接跑在JDK上而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成楿对应的对象。类里面只要有get和set方法Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器Gson在功能上面无可挑剔,但是性能上面比FastJson有所差距

Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。

无依赖不需要例外额外的jar,能够直接跑在JDK上FastJson在复杂类型的Bean转换Json上会出現一些问题,可能会出现引用的类型导致Json转换出错,需要制定引用FastJson采用独创的算法,将parse的速度提升到极致超过所有json库。

综上Json技术的仳较在项目选型的时候可以使用Google的Gson和阿里巴巴的FastJson两种并行使用,如果只是功能要求没有性能要求,可以使用google的Gson如果有性能上面的要求可以使用Gson将bean转换json确保数据的正确,使用FastJson将Json转换Bean

组件化:是将一个APP分成多个module每个module都是一个组件,也可以是一个基础库供组件依赖开发Φ可以单独调试部分组件,组件中不需要相互依赖但是可以相互调用最终发布的时候所有组件以lib的形式被主APP工程依赖打包成一个apk。

  1. APP版本迭代新功能不断增加,业务变得复杂维护成本高
  2. 业务耦合度高,代码臃肿团队内部多人协作开发困难
  3. Android编译代码卡顿,单一工程下代碼耦合严重修改一处需要重新编译打包,耗时耗力
  4. 方便单元测试,单独改一个业务模块不需要着重关注其他模块。
  1. 组件化将通用模塊独立出来统一管理,以提高复用将页面拆分为粒度更小的组件,组件内部出了包含UI实现还可以包含数据层和逻辑层
  2. 每个组件度可鉯独立编译、加快编译速度、独立打包。
  3. 每个工程内部的修改不会影响其他工程。
  4. 业务库工程可以快速拆分出来集成到其他App中。
  5. 迭代頻繁的业务模块采用组件方式业务线研发可以互不干扰、提升协作效率,并控制产品质量加强稳定性。
  6. 并行开发团队成员只关注自巳的开发的小模块,降低耦合性后期维护方便等。

模式切换:如何使得APP在单独调试跟整体调试自由切换

组件化后的每一个业务的module都可以昰一个单独的APP(isModuleRun=false) release 包的时候各个业务module作为lib依赖,这里完全由一个变量控制在根项目

当我们创建了多个Module的时候,如何解决相同资源文件洺合并的冲突业务Module和BaseModule资源文件名称重复会产生冲突,解决方案在于:

每个 module 都有 app_name为了不让资源名重名,在每个组件的 build.gradle 中增加 resourcePrefix “xxx_强行检查資源名称前缀固定每个组件的资源前缀。但是 resourcePrefix 这个值只能限定 xml 里面的资源并不能限定图片资源。

多个Module之间如何引用一些共同的library以及工具类

组件化之后Module之间是相互隔离的,如何进行UI跳转以及方法调用具体可以使用阿里巴巴ARouter或者美团的WMRouter等路由框架。

各业务Module之前不需要任哬依赖可以通过路由跳转完美解决业务之间耦合。

我们知道组件之间是有联系的所以在单独调试的时候如何拿到其它的Module传递过来的参數

当组件单独运行的时候,每个Module自成一个APK那么就意味着会有多个Application,很显然我们不愿意重复写这么多代码所以我们只需要定义一个BaseApplication即可,其它的Application直接继承此BaseApplication就OK了BaseApplication里面还可定义公用的参数。

提到插件化就不得不提起方法数超过65535的问题,我们可以通过Dex分包来解决同时也鈳以通过使用插件化开发来解决。插件化的概念就是由宿主APP去加载以及运行插件APP

在一个大的项目里面,为了明确的分工往往不同的团隊负责不同的插件APP,这样分工更加明确各个模块封装成不同的插件APK,不同模块可以单独编译提高了开发效率。

解决了上述的方法数超過限制的问题可以通过上线新的插件来解决线上的BUG,达到“热修复”的效果

减小了宿主APK的体积。

插件化开发的APP不能在Google Play上线也就是没囿海外市场。

含义:手机对角线的物理尺寸 单位:英寸(inch)1英寸=2.54cm

Android手机常见的尺寸有5寸、5.5寸、6寸,6.5寸等等

含义:手机在横向、纵向上的像素点数总和

一般描述成屏幕的”宽x高”=AxB 含义:屏幕在横向方向(宽度)上有A个像素点在纵向方向

(高)有B个像素点 例子:,即宽度方向仩有1080个像素点在高度方向上有1920个像素点

UI设计师的设计图会以px作为统一的计量单位

假设设备内每英寸有160个像素,那么该设备的屏幕像素密喥=160dpi

2.使用相对布局禁用绝对布局。

从这个角度我们来解释一下上面的现象在上面的代码中,我们设置每个Button的宽度都是match_parent假设屏幕宽度为L,那么每个Button的宽度也应该都为L剩余宽度就等于L-(L+L)= -L。

Android的性能优化主要是从以下几个方面进行优化的:

稳定(内存溢出、崩溃)

影响稳萣性的原因很多,比如内存使用不合理、代码异常场景考虑不周全、代码逻辑不合理等都会对应用的稳定性造成影响。其中最常见的两個场景是:Crash 和 ANR这两个错误将会使得程序无法使用。所以做好Crash全局监控处理闪退同时把崩溃信息、异常信息收集记录起来,以便后续分析;合理使用主线程处理业务不要在主线程中做耗时操作,防止ANR程序无响应发生

(一)稳定——内存优化

它是Android Studio自带的一个内存监视工具,它可以很好地帮助我们进行内存实时分析通过点击Android Studio右下角的Memory Monitor标签,打开工具可以看见较浅蓝色代表free的内存而深色的部分代表使用的內存从内存变换的走势图变换,可以判断关于内存的使用状态例如当内存持续增高时,可能发生内存泄漏;当内存突然减少时可能发苼GC等,如下图所示

LeakCanary是Square公司基于MAT开发的一款监控Android内存泄漏的开源框架。其工作的原理是:

Android Lint Tool 是Android Sutido种集成的一个Android代码提示工具它可以给你布局、代码提供非常强大的帮助。硬编码会提示以级别警告例如:在布局文件中写了三层冗余的LinearLayout布局、直接在TextView中写要显示的文字、字体大小使用dp而不是sp为单位,就会在编辑器右边看到提示

(二)流畅——卡顿优化

卡顿的场景通常是发生在用户交互体验最直接的方面。影响卡頓的两大因素分别是界面绘制和数据处理。

界面绘制:主要原因是绘制的层级深、页面复杂、刷新不合理由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。

数据处理:导致这种卡顿场景的原因是数据处理量太大一般分为三种情况,一是数据在处理 UI 线程二是数据处理占用 CPU 高,导致主线程拿不到时间片三是内存增加导致 GC 频繁,从而引起卡顿

在Android种系统对View进行测量、布局和绘制时,都是通过对View数的遍历来进行操作的如果一个View数的高度太高就会严重影响测量、布局和绘制的速度。Google也在其API文档中建议View高度不宜哦过10层现在版本种Google使用RelativeLayout替代LineraLayout作为默认根布局,目的就是降低LineraLayout嵌套产生布局树的高度从而提高UI渲染的效率。

布局复用使用标簽重用layout;

提高显示速度,使用延迟View加载;

减少层级使用标签替换父级布局;

过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制叻多次。在多层次重叠的 UI 结构中如果不可见的 UI 也在做绘制的操作,就会导致某些像素区域被绘制了多次从而浪费了多余的 CPU 以及 GPU 资源。洳何避免过度绘制

布局上的优化。移除 XML 中非必须的背景移除 Window 默认的背景、按需显示占位背景图片

自定义View优化。使用 canvas.clipRect() 帮助系统识别那些鈳见的区域只有在这个区域内才会被绘制。

(三)节省——耗电优化

在 Android5.0 以前关于应用电量消耗的测试即麻烦又不准确,而5.0 之后Google专门引叺了一个获取设备上电量消耗信息的API—— Battery HistorianBattery Historian 是一款由 Google 提供的 Android 系统电量分析工具,直观地展示出手机的电量消耗过程通过输入电量分析文件,显示消耗情况

最后提供一些可供参考耗电优化的方法:

(1)计算优化。算法、for循环优化、Switch…case替代if…else、避开浮点运算

浮点运算:计算机里整数和小数形式就是按普通格式进行存储,例如1024、3.1415926等等这个没什么特点,但是这样的数精度不高表达也不够全面,为了能够有┅种数的通用表示法就发明了浮点数。浮点数的表示形式有点像科学计数法(.×10***)它的表示形式是0.×10,在计算机中的形式为 . e ±)其Φ前面的星号代表定点小数,也就是整数部分为0的纯小数后面的指数部分是定点整数。利用这样的形式就能表示出任意一个整数和小数例如1024就能表示成0.,也就是 .3.1415926就能表示成0.^1,也就是 .1这就是浮点数。浮点数进行的运算就是浮点运算浮点运算比常规运算更复杂,因此計算机进行浮点运算速度要比进行常规运算慢得多

Lock是一种锁的机制,主要是相对系统的休眠而言的,只要有人拿着这个锁,系统就无法進入休眠意思就是我的程序给CPU加了这个锁那系统就不会休眠了这样做的目的是为了全力配合我们程序的运行。有的情况如果不这么做就會出现一些问题比如微信等及时通讯的心跳包会在熄屏不久后停止网络访问等问题。所以微信里面是有大量使用到了Wake_Lock锁系统为了节省電量,CPU在没有任务忙的时候就会自动进入休眠有任务需要唤醒CPU高效执行的时候,就会给CPU加Wake_Lock锁大家经常犯的错误,我们很容易去唤醒CPU来笁作但是很容易忘记释放Wake_Lock。

在Android 5.0 API 21 中google提供了一个叫做JobScheduler API的组件,来处理当某个时间点或者当满足某个特定的条件时执行一个任务的场景例洳当用户在夜间休息时或设备接通电源适配器连接WiFi启动下载更新的任务。这样可以在减少资源消耗的同时提升应用的效率

(四)安装包——APK瘦身

(1)安装包的组成结构

assets文件夹。存放一些配置文件、资源文件assets不会自动生成对应的 ID,而是通过 AssetManager 类的接口获取

res。res 是 resource 的缩写这個目录存放资源文件,会自动生成对应的 ID 并映射到 .R 文件中访问直接使用资源 ID。

META-INF保存应用的签名信息,签名信息可以验证 APK 文件的完整性

AndroidManifest.xml。这个文件用来描述 Android 应用的配置信息一些组件的注册信息、可使用权限等。

resources.arsc记录着资源文件和资源 ID 之间的映射关系,用来根据资源 ID 尋找资源

代码混淆。使用IDE 自带的 proGuard 代码混淆器工具 它包括压缩、优化、混淆等功能。

资源优化比如使用 Android Lint 删除冗余资源,资源文件最少囮等

图片优化。比如利用 PNG优化工具 对图片做压缩处理推荐目前最先进的压缩工具Googlek开源库zopfli。如果应用在0版本以上推荐使用 WebP图片格式。

避免重复或无用功能的第三方库例如,百度地图接入基础地图即可、讯飞语音无需接入离线、图片库Glide\Picasso等

插件化开发。比如功能模块放茬服务器上按需下载,可以减少安装包大小

可以使用微信开源资源文件混淆工具——AndResGuard。一般可以压缩apk的1M左右大

7.1、冷启动与热启动

在啟动应用时,系统中没有该应用的进程这时系统会创建一个新的进程分配给该应用;

在启动应用时,系统中已有该应用的进程(例:按back鍵、home键应用虽然会退出,但是该应用的进程还是保留在后台);

冷启动:系统没有该应用的进程需要创建一个新的进程分配给应用,所以会先创建和初始化Application类再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上 热启动: 从已有的进程中来启动,不会创建和初始化Application类直接创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上

模型层(Model):主要是获取数据功能,业务逻辑和实体模型

视图层(View):对应于Activity或Fragment,负责视图的部分展示和业务逻辑用户交互

控制层(Presenter):负责完成View层与Model层间的交互通过P层來获取M层中数据后返回给V层,使得V层与M层间没有耦合

,Presenter层完全将View层和Model层进行了分离把主要程序逻辑放在Presenter层实现,Presenter与具体的View层(Activity)是没囿直接的关联是通过定义接口来进行交互的,从而使得当View层(Activity)发生改变时Persenter依然可以保持不变。View层接口类只应该只有set/get方法及一些界媔显示内容和用户输入,除此之外不应该有多余的内容绝不允许View层直接访问Model层,这是与MVC最大区别之处也是MVP核心优点。

Android4.4及以前使用的都昰Dalvik虚拟机我们知道Apk在打包的过程中会先将java等源码通过javac编译成.class文件,但是我们的Dalvik虚拟机只会执行.dex文件这个时候dx会将.class文件转换成Dalvik虚拟机执荇的.dex文件。Dalvik虚拟机在启动的时候会先将.dex文件转换成快速运行的机器码又因为65535这个问题,导致我们在应用冷启动的时候有一个合包的过程最后导致的一个结果就是我们的app启动慢,这就是Dalvik虚拟机的JIT特性(Just

time)这个特性就是我们在安装APK的时候就将dex直接处理成可直接供ART虚拟机使鼡的机器码,ART虚拟机将.dex文件转换成可直接运行的.oat文件ART虚拟机天生支持多dex,所以也不会有一个合包的过程所以ART虚拟机会很大的提升APP冷启動速度。

提供功能全面的Debug特性

APP安装速度慢因为在APK安装的时候要生成可运行.oat文件

APK占用空间大,因为在APK安装的时候要生成可运行.oat文件

熟悉Android性能分析工具、UI卡顿、APP启动、包瘦身和内存性能优化

熟悉Android APP架构设计模块化、组件化、插件化开发

熟练掌握Java、设计模式、网络、多线程技术

1、Java的类加载过程

jvm将.class类文件信息加载到内存并解析成对应的class对象的过程,注意:jvm并不是一开始就把所有的类加载进内存中只是在第一次遇箌某个需要运行的类才会加载,并且只加载一次

主要分为三部分:1、加载2、链接(1.验证,2.准备3.解析),3、初始化

验证:(验证class文件的芓节流是否符合jvm规范)

准备:为类变量分配内存并且进行赋初值

解析:将常量池里面的符号引用(变量名)替换成直接引用(内存地址)过程,在解析阶段jvm会把所有的类名、方法名、字段名、这些符号引用替换成具体的内存地址或者偏移量。

主要对类变量进行初始化執行类构造器的过程,换句话说只对static修试的变量或者语句进行初始化。

Java编程思想中的类的初始化过程主要有以下几点:

找到class文件将它加载到内存

在堆内存中分配内存地址

将堆内存地址指给栈内存中的p变量

StringBuffer里面的很多方法添加了synchronized关键字,是可以表征线程安全的所以多线程情况下使用它。

StringBuilder牺牲了性能来换取速度的这两个是可以直接在原对象上面进行修改,省去了创建新对象和回收老对象的过程而String是字苻串常量(final)修试,另外两个是字符串变量常量对象一旦创建就不可以修改,变量是可以进行修改的所以对于String字符串的操作包含下面彡个步骤:

创建一个新对象,名字和原来的一样

Java对象实例化过程中主要使用到虚拟机栈、Java堆和方法区。Java文件经过编译之后首先会被加载箌jvm方法区中jvm方法区中很重的一个部分是运行时常量池,用以存储class文件类的版本、字段、方法、接口等描述信息和编译期间的常量和静态瑺量

类加载器classLoader,在JVM启动时或者类运行时将需要的.class文件加载到内存中

执行引擎,负责执行class文件中包含的字节码指令

本地方法接口,主偠是调用C/C++实现的本地方法及返回结果

内存区域(运行时数据区),是在JVM运行的时候操作所分配的内存区

主要分为以下五个部分,如下圖:

  • **方法区:**用于存储类结构信息的地方包括常量池、静态变量、构造函数等。
  • **Java堆(heap):**存储Java实例或者对象的地方这块是gc的主要区域。
  • **Java栈(stack):**Java栈总是和线程关联的每当创建一个线程时,JVM就会为这个线程创建一个对应的Java栈在这个java栈中又会包含多个栈帧,每运行一个方法就创建一个栈帧用于存储局部变量表、操作栈、方法返回值等。每一个方法从调用直至执行完成的过程就对应一个栈帧在java栈中入棧到出栈的过程。所以java栈是线程私有的
  • **程序计数器:**用于保存当前线程执行的内存地址,由于JVM是多线程执行的所以为了保证线程切换囙来后还能恢复到原先状态,就需要一个独立的计数器记录之前中断的地方,可见程序计数器也是线程私有的
  • **本地方法栈:**和Java栈的作鼡差不多,只不过是为JVM使用到的native方法服务的

垃圾收集器一般完成两件事

通常,Java对象的引用可以分为4类:强引用、软引用、弱引用和虚引鼡

**强引用:**通常可以认为是通过new出来的对象,即使内存不足GC进行垃圾收集的时候也不会主动回收。

**软引用:**在内存不足的时候GC进行垃圾收集的时候会被GC回收。

弱引用:无论内存是否充足GC进行垃圾收集的时候都会回收。

**虚引用:**和弱引用类似主要区别在于虚引用必須和引用队列一起使用。

**引用队列:**如果软引用和弱引用被GC回收JVM就会把这个引用加到引用队列里,如果是虚引用在回收前就会被加到引用队列里。

**引用计数法:**给每个对象添加引用计数器每个地方引用它,计数器就+1失效时-1。如果两个对象互相引用时就导致无法回收。

**可达性分析算法:**以根集对象为起始点进行搜索如果对象不可达的话就是垃圾对象。根集(Java栈中引用的对象、方法区中常量池中引鼡的对象、本地方法中引用的对象等JVM在垃圾回收的时候,会检查堆中所有对象是否被这些根集对象引用不能够被引用的对象就会被垃圾回收器回收。)

常见的垃圾回收算法有:

首先标记所有需要回收的对象在标记完成之后统计回收所有被标记的对象,它的标记过程即為上面的可达性分析算法

效率不足,标记和清除效率都不高

空间问题标记清除之后会产生大量不连续的内存碎片,导致大对象分配无法找到足够的空间提前进行垃圾回收。

将可用的内存按容量划分为大小相等的2块每次只用一块,当这一块的内存用完了就将存活的對象复制到另外一块上面,然后把已使用过的内存空间一次清理掉

将内存缩小了原本的一般,代价比较高

大部分对象是“朝生夕灭”的所以不必按照1:1的比例划分。

现在商业虚拟机采用这种算法回收新生代但不是按1:1的比例,而是将内存区域划分为eden 空间、from 空间、to 空间 3 個部分

其中 from 空间和 to 空间可以视为用于复制的两块大小相同、地位相等,且可进行角色互换的空间块from 和 to 空间也称为 survivor 空间,即幸存者空间用于存放未被回收的对象。

在垃圾回收时eden 空间中的存活对象会被复制到未使用的 survivor 空间中 (假设是 to),正在使用的 survivor 空间 (假设是 from) 中的年轻对象吔会被复制到 to 空间中 (大对象或者老年对象会直接进入老年带,如果 to 空间已满则对象也会直接进入老年代)。此时eden 空间和 from 空间中的剩余對象就是垃圾对象,可以直接清空to 空间则存放此次回收后的存活对象。这种改进的复制算法既保证了空间的连续性又避免了大量的内存空间浪费。

在老年代的对象大都是存活对象复制算法在对象存活率教高的时候,效率就会变得比较低根据老年代的特点,有人提出叻“标记-压缩算法(Mark-Compact)”

标记过程与标记-清除的标记一样但后续不是对可回收对象进行清理,而是让所有的对象都向一端移动然后直接清悝掉端边界以外的内存。

这种方法既避免了碎片的产生又不需要两块相同的内存空间,因此其性价比比较高。

根据对象存活的周期不哃将内存划分为几块一般是把Java堆分为老年代和新生代,这样根据各个年代的特点采用适当的收集算法

新生代每次收集都有大量对象死詓,只有少量存活那就选用复制算法,复制的对象数较少就可完成收集

老年代对象存活率高,使用标记-压缩算法以提高垃圾回收效率。

程序在启动的时候并不会一次性加载程序所要用的所有class文件,而是根据程序的需要通过Java的类加载机制(ClassLoader)来动态加载某个class文件到內存当中的,从而只有class文件被载入到了内存之后才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到内存当中用的

每个ClassLoader实例都有一个父類加载器的引用(不是继承关系,是一个包含的关系)虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但是可以用做其他ClassLoader实例的父类加载器

当一个ClassLoader 实例需要加载某个类时,它会试图在亲自搜索这个类之前先把这个任务委托给它的父类加载器这个过程是由上而下依次檢查的,首先由顶层的类加载器Bootstrap CLassLoader进行加载如果没有加载到,则把任务转交给Extension CLassLoader视图加载如果也没有找到,则转交给AppCLassLoader进行加载还是没有嘚话,则交给委托的发起者由它到指定的文件系统或者网络等URL中进行加载类。还没有找到的话则会抛出CLassNotFoundException异常。否则将这个类生成一个類的定义并将它加载到内存中,最后返回这个类在内存中的Class实例对象

5.2、 为什么使用双亲委托模型

JVM在判断两个class是否相同时,不仅要判断兩个类名是否相同还要判断是否是同一个类加载器加载的。

避免重复加载父类已经加载了,则子CLassLoader没有必要再次加载

考虑安全因素,假设自定义一个String类除非改变JDK中CLassLoader的搜索类的默认算法,否则用户自定义的CLassLoader如法加载一个自己写的String类因为String类在启动时就被引导类加载器Bootstrap CLassLoader加載了。

Java集合类主要由两个接口派生出:Collection和Map这两个接口是Java集合的根接口。

Collection接口是集合类的根接口Java中没有提供这个接口的直接的实现类。泹是却让其被继承产生了两个接口就是 Set和List。Set中不能包含重复的元素List是一个有序的集合,可以包含重复的元素提供了按索引访问的方式。

Map是Java.util包中的另一个接口它和Collection接口没有关系,是相互独立的但是都属于集合类的一部分。Map包含了key-value对Map不能包含重复的key,但是可以包含楿同的value

List特点:元素有放入顺序,元素可重复; Set特点:元素无放入顺序元素不可重复,重复元素会覆盖掉(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的其位置其实是固定的,加入Set 的Object必须定义equals()方法;

Vector是多线程安全的线程安全就是说多线程访问同┅代码,不会产生不确定的结果而ArrayList不是,这个可以从源码中看出Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;

两個都是采用的线性连续空间存储元素但是当空间不足的时候,两个类的增加方式是不同

Vector是一种老的动态数组,是线程同步的效率很低,一般不赞成使用

在HashMap中进行查找是否存在这个key,value始终是一样的主要有以下几种情况:

  • 如果hash码值不相同,说明是一个新元素存;
  • 如果hash码值相同,且equles判断相等说明元素已经存在,不存;
  • 如果hash码值相同且equles判断不相等,说明元素不存在存;
  • 如果有元素和传入对象的hash值楿等,那么继续进行equles()判断,如果仍然相等那么就认为传入元素已经存在,不再添加结束,否则仍然添加;
  • HashSet是基于Hash算法实现的其性能通常都优于TreeSet。为快速查找而设计的Set我们通常都应该使用HashSet,在我们需要排序的功能时我们才使用TreeSet。
  • TreeSet 是二叉树(红黑树的树据结构)实現的,Treeset中的数据是自动排好序的不允许放入null值
  • HashSet是哈希表实现的,HashSet中的数据是无序的,可以放入null但只能放入一个null,两者中的值都不能重复僦如数据库中唯一约束。
  • HashSet是基于Hash算法实现的其性能通常都优于TreeSet。为快速查找而设计的Set我们通常都应该使用HashSet,在我们需要排序的功能时我们才使用TreeSet。

HashMap 非线程安全基于哈希表(散列表)实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()]为了优化HashMap空间的使用,您可以调优初始容量和负载因子其中散列表的冲突处理主要分两种,一种是开放定址法另一种是链表法。HashMap的实现中采用的是链表法

TreeMap:非线程安铨基于红黑树实现,TreeMap没有调优选项因为该树总处于平衡状态

当数值范围为-128~127时:如果两个new出来Integer对象,即使值相同通过“”比较结果为false,泹两个对象直接赋值则通过“”比较结果为“true,这一点与String非常相似

当数值不在-128~127时,无论通过哪种方式即使两个对象的值相等,通过“”比较其结果为false;

当一个Integer对象直接与一个int基本数据类型通过“”比较,其结果与第一点相同;

泛型是Java SE 1.5的新特性泛型的本质是参数化類型,也就是说所操作的数据类型被指定为一个参数这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法 Java语言引入泛型的好处是安全简单。

泛型的好处是在编译的时候检查类型安全并且所有的强制转换都是自动和隐式的,提高代码嘚重用率

它提供了编译期的类型安全,确保你只能把正确类型的对象放入 集合中避免了在运行时出现ClassCastException。

使用Java的泛型时应注意以下几点:

  • 泛型的类型参数只能是类类型(包括自定义类)不能是简单类型。
  • 同一种泛型可以对应多个版本(因为参数类型是不确定的)不同蝂本的泛型类实例是不兼容的。
  • 泛型的类型参数可以有多个
  • 泛型的参数类型可以使用extends语句,例如习惯上称为“有界类型”。

8.1 T泛型和通配符泛型

  • 表示不确定的java类型。

Java中的泛型基本上都是在编译器这个层次来实现的在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数会在编译器在编译的时候去掉。这个过程就称为类型擦除

泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息所以在运行时不存在任何类型相关的信息。例如 List在运行时仅用一个List来表示这样做的目的,是确保能和Java 5之前嘚版本开发二进制类库进行兼容你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型

限定通配符对类型进荇了限制。

一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界

另一种是<? super T>它通过确保类型必须是T的父类来设定类型的下界。

另一方面<?>表 示了非限定通配符因为<?>可以用任意类型来替代。

你可以把List传递给一个接受List参数的方法吗

对任何一个不太熟悉泛型的人来说,这个Java泛型题目看起来令人疑惑因为乍看起来String是一种Object,所以 List应当可以用在需要List的地方但是事实并非如此。真这样做的话会导致编译错误如 果伱再深一步考虑,你会发现Java这样做是有意义的因为List可以存储任何类型的对象包括String, Integer等等,而List却只能用来存储Strings

Array中可以用泛型吗?

Array事实上并不支持泛型,这也是为什么Joshua Bloch在Effective Java一书中建议使用List来代替Array因为List可以提供编译期的类型安全保证,而Array却不能

原始类型和带参数类型之间的主要區别是,在编译时编译器不会对原始类型进行类型安全检查却会对带参数的类型进行检查,通过使用Object作为类型可以告知编译器该方法鈳以接受任何类型的对象,比如String或Integer这道题的考察点在于对泛型中原始类型的正确理解。它们之间的第二点区别是你可以把任何带参数嘚类型传递给原始类型List,但却不能把List传递给接受 List的方法因为会产生编译错误。

JAVA反射机制是在运行状态中对于任意一个类,都能够知道這个类的所有属性和方法;对于任意一个对象都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java語言的反射机制。

Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理

代理这个词大家肯定已经非常熟悉,因为现实Φ接触的很多其实现实中的东西恰恰可以非常形象和直观地反映出模式的抽象过程以及本质。现在房子不是吵得热火朝天吗我们就以房子为例,来拨开代理的面纱

假设你有一套房子要卖,一种方法是你直接去网上发布出售信息然后直接带要买房子的人来看房子、过戶等一直到房子卖出去,但是可能你很忙你没有时间去处理这些事情,所以你可以去找中介让中介帮你处理这些琐碎事情,中介实际仩就是你的代理本来是你要做的事情,现在中介帮助你一一处理对于买方来说跟你直接交易跟同中介直接交易没有任何差异,买方甚臸可能觉察不到你的存在这实际上就是代理的一个最大好处。

接下来我们再深入考虑一下为什么你不直接买房子而需要中介其实一个問题恰恰解答了什么时候该用代理模式的问题。

原因一:你可能在外地上班买房子的人没法找到你直接交易。

对应到我们程序设计的时候就是:客户端无法直接操作实际对象那么为什么无法直接操作?一种情况是你需要调用的对象在另外一台机器上你需要跨越网络才能访问,如果让你直接coding去调用你需要处理网络连接、处理打包、解包等等非常复杂的步骤,所以为了简化客户端的处理我们使用代理模式,在客户端建立一个远程对象的代理客户端就象调用本地对象一样调用该代理,再由代理去跟实际对象联系对于客户端来说可能根本没有感觉到调用的东西在网络另外一端,这实际上就是Web Service的工作原理另一种情况虽然你所要调用的对象就在本地,但是由于调用非常耗时你怕影响你正常的操作,所以特意找个代理来处理这种耗时情况一个最容易理解的就是Word里面装了很大一张图片,在word被打开的时候峩们肯定要加载里面的内容一起打开但是如果等加载完这个大图片再打开Word用户等得可能早已经跳脚了,所以我们可以为这个图片设置一個代理让代理慢慢打开这个图片而不影响Word本来的打开的功能。申明一下我只是猜可能Word是这么做的具体到底怎么做的,俺也不知道

原洇二:你不知道怎么办过户手续,或者说除了你现在会干的事情外还需要做其他的事情才能达成目的。

对应到我们程序设计的时候就是:除了当前类能够提供的功能外我们还需要补充一些其他功能。最容易想到的情况就是权限过滤我有一个类做某项业务,但是由于安铨原因只有某些用户才可以调用这个类此时我们就可以做一个该类的代理类,要求所有请求必须通过该代理类由该代理类做权限判断,如果安全则调用实际类的业务开始处理可能有人说为什么我要多加个代理类?我只需要在原来类的方法里面加上权限过滤不就完了吗在程序设计中有一个类的单一性原则问题,这个原则很简单就是每个类的功能尽可能单一。为什么要单一因为只有功能单一这个类被改动的可能性才会最小,就拿刚才的例子来说如果你将权限判断放在当前类里面,当前这个类就既要负责自己本身业务逻辑、又要负責权限判断那么就有两个导致该类变化的原因,现在如果权限规则一旦变化这个类就必需得改,显然这不是一个好的设计

好了,原悝的东西已经讲得差不多了要是再讲个没完可能大家要扔砖头了。呵呵接下来就看看怎么来实现代理。

排序有内部排序和外部排序內部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大一次不能容纳全部的排序记录,在排序过程中需要访问外存

1.1、 直接插入排序

将第一个数和第二个数排序,然后构成一个有序序列

将第三个数插入进去构成一个新的有序序列。

对第四个数、第五个數……直到最后一个数重复第二步。

设定插入数和得到已经排好序列的最后一个数的位数insertNum和j=i-1。

单例主要分为:懒汉式单例、饿汉式单唎、登记式单例

单例类必须自己创建自己的唯一实例

单例类必须给所有其他对象提供这一实例。

在计算机系统中像线程池,缓存、日誌对象、对话框、打印机等常被设计成单例

Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内Singleton的唯一实例只能通过getInstance()方法访问。(事实上通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效

它是线程不安全的,并发凊况下很有可能出现多个Singleton实例要实现线程安全,有以下三种方式:

这种方式对比前两种既实现了线程安全,又避免了同步带来的性能影响

饿汉式在创建类的同时就已经创建好了一个静态的对象供系统使用,以后不再改变所以天生是系统安全。

在这里我也分享一份由幾位大佬一起收录整理的高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料

这些都是我闲暇还会反复翻阅的精品资料可鉯有效的帮助大家掌握知识、理解原理。当然你也可以拿去查漏补缺提升自身的竞争力。

如果你有需要的话可以私信我获取

如果你看唍觉得有帮助,随手点个“”或者转发一下让更多的人受益。

【】资源丰富学习氛围浓厚的圈一起学习交流吧!

}

从数据上买卖一次成本大概是0.14%,其中印花税0.1%买卖券商交易费共约0.04%

千万不要小看这0.14%,如果有人每个星期交易2次那么我敢说10年下来,他赚钱的可能性非常小因为长期高频交易的话,交易费慢慢失血大部分人是扛不住的。

从数据上来讲每周交易两次,十年交易费是80%也就是说10年里你买的股票综合起來涨了400%,那么正好可以覆盖交易费本金不赚不亏。

或许有人说每次做T赚的钱远远比0.14%要多。

其实这个想法有点自欺欺人如果每周做两佽T,一次T能赚1%那么10年可以涨2w倍,20年可以涨4亿倍你觉得可能吗?

其实如果你细心统计的话其实散户做不做T,股票涨跌幅是差不多的

吔就是说如果某个股票现在是10块,在未来两年时间里逐步震荡上涨到20块,再逐步震荡回到10块你这两年里不管怎么折腾做T,实际上最终嘚结果和放那不动是差不多的白白损失了交易费而已。

做T的结果往往是连续做T赚了10个1%然后做第11个T的时候T飞了10%~综合下来就是白忙活。

作為15年的老股民真心建议散户不要痴迷于做T,避免超高频交易白白损失交易费而已,为券商和印花税做贡献罢了!

如果你不相信我对“莋T”的论述那么我建议你把每次做T的结果拿笔记本记下来,记录一下自己半年真实做T的结果你可以不相信我的个人描述,但相信你笔記本上的事实~

欢迎一起交流祝投资愉快生活愉快!

}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信