小二
第一周
第一天
我们客户端开发,原生的开发,混合式开发(原生+H5),完全就是H5页面(webVIew)
混合式和原生开发是最多
挑选项目的时候就要注意了,找了个完全是H5实现的APP,说成自己
怎么去区分原生和H5
Facebook就是升级版的腾讯
facebook/react-native,这个是一个混合式框架,可以用JS,
去写android和IOS都能运行项目,而且效率在混合式框架名列前茅
fresco,一个图片处理框架
图片处理框架,Glid,Fresco,,ImageLoader,Picso,
,FrescoFacebook出品
Facebook出品,必出精品
优势:底层直接用C语言,对于内存的管理特别强大,,一张图片,如果你用Picasso去处理,内存占用80%,那么fresco就是40%
Fresco遇到什么问题,你可以在Issues上面进行提问,或者找一下,看其他人遇到了吗
第三方:Fresco,RxJava,EventBus,Retrofit,
依赖包太大,APK的体积过大,如果你app,apk体积一个G,还有一个APP功能和你一样,体积12M
apk瘦身,以后说
因此你使用Fresco,根据你的需求,你去依赖对应依赖包
webP图片的一种格式,apk瘦身里面的知识点,以后说
如果你用Fresco,他会导致你项目耦合度过高
SimpleDraweeView,加载图片必须用这个空间,而不是ImageView,
这会导致你要是弃用Fresco,修改的地方就特别多
几百个类里面的SimpleDraweeView改成ImageView
第二天
现在图片基本用Glide,Fresco这两个
如果你的项目需要用到GIF,那么需要添加专用依赖
界面里面的控件是有两种方式
在XML布局中,创建控件,静态定义控件,findViewById(R.id.);
把XML的控件变成一个对象,然后灵活的使用
在XML布局中,创建控件,静态定义控件,findViewById(R.id.);
把XML的控件变成一个对象,然后灵活的使用
我的一个控件,不在XML里面定义,我在哪里去把控件弄出来?
在Java代码中,手动的去创建一个控件的对象
* 动态创建一个控件,步骤有三:
*
* 1.通过java代码创建控件对象(必须设置控件宽高属性) A
* 2.对控件进行数据设置 B
* 3.此时控件虽然已经准备好了,但是和我们的activity_fresco_auto_sizeXML布局没有任何关系 C
*
* 提示:我们会把我们的子控件,放入的根布局中,否则不报错,也没有效果
第三天
14年做项目标准:
MVC,okhttp,自定义,EventBUs一讲,基本一个项目你就可以考试做
MVP,Retrofit,RxJava,自定义控件做一个项目
15年标准项目标配,OKGO,
MVP就是搞不懂,先用MVC你做一个项目,然后代码量够了,你才能用MVP去做一个,
现在学习的知识只能用MVP做考试
一个第三方技术点,最重要的一点:你必须清楚你用这个东西好处
技术调研
什么是进程(Process):普通的解释就是,进程是程序的一次执行,
而什么是线程(Thread),线程可以理解为进程中的执行的一段程序片段。
在一个多任务环境中下面的概念可以帮助我们理解两者间的差别:进程间是独立的,
这表现在内存空间,上下文环境;线程运行在进程空间内。
一般来讲(不使用特殊技术)进程是无法突破进程边界存取其他进程内的存储空间;
而线程由于处于进程空间内,所以同一进程所产生的线程共享同一内存空间。
同一进程中的两段代码不能够同时执行,除非引入线程。线程是属于进程的,
当进程退出时该进程所产生的线程都会被强制退出并清除。
线程占用的资源要少于进程所占用的资源。进程和线程都可以有优先级。
在线程系统中进程也是一个线程。可以将进程理解为一个程序的第一个线程。
线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:
(1)地址空间:
进程内的一个执行单元;
进程至少有一个线程;
它们共享进程的地址空间;
而进程有自己独立的地址空间;
(2)进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是.
(4)二者均可并发执行.
EventBus(单例模式,但是并没有把他的构造方法私有化,可以new出来):
可以代替Handler和Intent(跳转传值)
创建Module,关联EventBus框架,创建第2个Activity
完成Module的布局及控件的初始化
注册EventBus,解除EventBus注册
创建EventBus消息类,设置属性
使用EventBus的Post方法发送事件
根据消息类,接收事件
写接受消息方法的时候,方法名自定义,但是权限呢必须是public
参数必须和发送消息的消息类一致。
如果不一致就什么都没有,如果没有public就会崩溃
注册EventBUs拿到订阅方法就两种手段
注释:是为了方便阅读代码
1.注解:参与代码编译,以@开头的。它是给应用程序看的,
单独使用注解毫无意义,一定要跟工具一起使用,
这个所谓的工具实际就是能读懂注解的应用程序
注释 :对代码没有影响。对代码起到解释、说明的作用
2.反射
EventBus用组件与组件之间的传递代替intent,线程中的通信替代handler
提示:发送方的线程也会影响到接受方
粘性事件就是指在EventBus内部被缓存的事件,使用时需要溢出所有的粘性事件
否则会溢出或泄露
粘性步骤,粘性事件需要在注解中添加sticky = true:就是允许粘性事件
/**
* 创建Module,关联EventBus框架,创建第2个Activity
完成Module的布局及控件的初始化
创建EventBus消息类,设置属性
使用EventBus的postSticky方法发送黏性事件
根据消息类,接收黏性事件(注意:注解要添加sticky = true)
注册EventBus,解除EventBus黏性事件及注册
*/
接口用postman测试
第四天
webview:是一个可以显示网页的控件,
他的网页渲染引擎和Safari、Chrome一样都是用webkit内核
优点:1.自带热修复效果
2.搭建java和javascript之间的交互的桥梁
3.跨平台,网页代码编写一次,即可以在任何支持web的平台上运行,
节省开发成本,提高开发效率
4.资源利用最大化,web开发人员只用很少的学习成本就可以使用
5.应用程序维护成本大大降低,只用维护服务端代码即可
但实际开发中用到的并不是太多
致命缺点:使用webview开发的app运行效率非常差,更消耗用户的流量资源
web开发步骤:
1.开发环境,添加权限
2.不举例添加webview控件,初始化控件
3.初始化webview基本设置
4.webview优化
js互调
js调用java需要我们android定义一个方法,提供给js调用
使用webview对象,调用addjavascriptinterface方法
第一个参数,是写一个类,在这里提供要暴露的方法,
如果你运行android系统版本过高,那么你必须加一个注解@JavaScriptInterface(5.0及以上)
第二个参数,字符串标识,js通过这个标识调用我们的方法,Android.showToast(toast)
//java调用js方法,格式固定: 方法名必须和h5页面方法名一样
webview对象.loadURL("javascript:js方法名('参数')")
第二周
第一天
1.CSDN( 简书,知乎,开源中国,红黑联盟)
2.GitHub( 码云 )开源代码的集中营
3.stackoverflow.注意解决BUG,解决bug的集中营
Studio中使用插件:Android ButterKnife Zelezny,可以一键生成Butterknife
Butterknife:是一个视图注入中相对简单易懂的开源框架
1.强大的view绑定和click事件处理,简化代码,提供了开发效率
2.方便的处理Adapter里的ViewHolder绑定问题
3.提供App运行效率,使用配置方便
4.代码清晰,可读性强
使用步骤:
1.在Gradle里关联依赖
2.在你要使用Butterknife的勒种进行初始化
3.加注解
4.通过Butterknife给控件加点击事件
有些公司让你使用,但是因为使用ButterKnife,
妈妈再也不用担心我findViewById(R.id.);,
所以还是有很多程序员在公司里没有明确禁止使用ButterKnife的情况下,使用他
我们必须知道ButterKnife的格式是什么样子,
以方便我们出去开发,维护人家写的项目,你看不懂这个格式
ButterKnife,实际通过这个注解,反射,也是再给你findViewById(R.id.);
ButterKnife使用时只需要导依赖,然后在页面中添加
ButterKnife.bind(this);就可以使用
而在fragment中使用时需要多添加一个参数
就是布局文件,因为使用它之后不需要findviewbyid了
可以自动生成,和添加点击事件,非常方便
ButterKnife.bind(this,布局文件id(view));
ButterKnife使用心得:
1.ButterKnife初始化必须在加载布局之后(setContentView,Inflater),
所以ButterKnife不能够在Application中初始化
2.ButterKnife初始化在Fragment和Adapter中,
要多写一个参数,View,ButterKnife.bind(this,mView)
3.使用ButterKnife设置控件点击事件,其方法的权限必须在默认权限以上(包括默认权限)
4.虽然使用ButterKnife很方便,但是由于ButterKnife不是android原生的,
所以使用他报错了,
studio会报很奇怪的错误,需要耐心查找
Butterknife 8.0 做了些许改变: 依赖的时候,更麻烦了,
项目中Gradle配置就可以,现在你不仅要在项目中Gradle配置,
而且还要在这个Gradle文件中装插件 ,还要在工作空间的Gradle文件中加依赖
8.0中注解的名字从@Bind到@BindView
apk打包:
apk打包,分为两种,一种是正式包,一种DeBug包
发布包,测试包,测试包无法装真机,发布包都可以装
Debug包只能在模拟器上运行,因为签名的问题
而正式包可以在手机上运行
咱们签名分为两种格式,studio打的签名后缀名是JKS,
eclipse打的签名Keystore,这个两个是一个东西,JPG和PNG
签名到底是什么东西,有什么用
签名就相当于身份证号
具备唯一性
签名丢了,不可找到
你的app是应用市场有排名,下载量
app你不是更新,打包用的签名如果不一致,
那么你的app之前积累的排名,下载量就不算了
不能够在更新了
当换一个签名,你的APP就新生了
程序打包:就是根据签名和其他标识生成安装包。
(注意:APP的apk名字不能包含中文,否则无法拖拽到模拟器上安装)
APP签名:在android应用文件(apk)中保存的一个特别字符串
(用来标识不同的应用开发者:开发者A,开发者B)
主要是为了后期app的升级,能无缝升级,故一定要保存好,
一旦丢失,就在也找不回来.一点要保存好!!!
(安卓系统靠签名文件来识别该程序的拥有者)
不同程序员开发的应用包名可能会相同,
导致一个应用覆盖掉另一个应用。
> 如果只有包名的概念,那么如果B应用与已经安装的A应用包名一样,
那就实现覆盖。不合理!
> 而事实上是装不上B的,它会提示,存在包名一致,
但是签名不一样的。这就不会覆盖。
3.用来标识不同的应用开发者:
开发者A,开发者B防止盗版,应用更新时要用同一个签名,
否则就不是更新而是安装新应用
1.Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中
(我们平常没有配置,依然能运行程序,是studio使用了默认签名)
提示:1. debug签名的应用程序不能在Android Market上架销售,
它会强制你使用自己的签名。
2. 不同电脑使用此文件生成的签名不一样。
那就意味着如果你换了机器,也就是换了签名文件一样.
程序打包:就是根据签名和其他标识生成安装包。
(注意:APP的apk名字不能包含中文,否则无法拖拽到模拟器上安装)
APP签名:在android应用文件(apk)中保存的一个特别字符串
(用来标识不同的应用开发者:开发者A,开发者B)
第二天
每天的话诉一定要真实,可以结巴,磕磕绊绊,但是一定是自己理解的东西。
不要总是照本宣科,这样锻炼不出来自己的口才和能力
Retrofit是非常流行的网络框架是Squre公司出品的okhttp也是他出品的
Retrofit是基于okhttp的封装,升级,Retrofit网络请求底层用到的网络框架,
就是okhttp
优点是:效率高,实现简单,运用了注解和动态代理模式,
极大的简化了网络请求的繁琐模式,非常适合我们的安卓项目
关键点:Retrofit的动态代理:我们使用Retrofit的API进行网络请求,
他的底层用的是okhttp,okhttp被淘汰,有了新的网络请求框架YCFhttp
你的项目也要求使用怎么办?是把你项目中所有网络请求的代码都删掉重写吗?
Retrofit的动态代理设计模式,所以他可以用几行代码就替换掉自己的网络框架的底层
YCFhttp都不用东就可以做到框架隔离
目前最流行还是okhttp,所以Retrofit替换底层网络框架,
用不到,这个优势只是4年以后,你才会感受
特点:性能好,处理快,使用简单.(速度比Volley更快)
使用REST API非常方便
Retrofit默认使用okhttp处理网络请求;
默认使用Gson解析
你要是指定Gson,你必须加统一的依赖
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
Retrofit2注解:
@GET GET网络请求方式
@POST POST网络请求方式
@Headers 头信息参数
@Path 路径参数.替换url地址中 "{" 和 "}"所包括的部分
@Query 查询参数.将在url地址中追加类似"page = 1"的字符串,形成提交给服务器端的请求参数
@QueryMap 查询参数集合.在url地址中追加类似"type = text & count = 30 & page = 1 " 的字符串
@FormUrlEncoded 对表单域中填写内存进行编码处理,避免乱码
@Field 指定from表单域中每个控件的name及相应数值
@FieldMap 表单域集合
@Multipart Post提交分块请求.如果上传文件,必须指定Multipart
@Part Post提交分块请求
@Body Post提交分块请求
Retrofit与OKhttp的不同:
1.设置请求方式是注解的形式
2.接口拼接字符串更灵活
3.异步响应回调方法在主线程
使用步骤:
/**
* 1.搭建Retrofit的环境(依赖和权限)
* 2.一般项目中,我们会创建一个Constant常量类,
用来存放项目中常用的字符串,在这里我们存放基础URL
* 3.创建Retrofit所需的接口对象,使用注解的形式,
指定Get请求方式及所拼接的字符串
* 4.使用Retrofit2.0,get无参数模式请求网络
* 5.释放Retrofit的资源,当屏幕不可见时,我们停止网络请求
*/
* 使用Retrofit自带的Gson解析怎么用
* 1.添加依赖 compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' 版本号一致
* 2.Bean类
* 3.修改我们的接口方法里的泛型,ResponseBody改成我们的Bean
* 4..addConverterFactory(GsonConverterFactory.create())
* 5.调用异步方法,然后response.body().getXX,就可以得到我们Bean类集合,
集合就可以拿到具体一个Bean,通过Bean类对象,就可以拿到我们想要的数据
第三天
Retrofit的post请求和昨天的get一样,只不过使用的get变成了post
编程语言:1.机器语言, 0,1,互联网事件,任何酷炫的东西,本质都是0,1
汇编语言:开机 ,000111 , open
高级编程语言:Java,Object-C ,PHP ,GO
汇编语言:开机 ,000111 , _/
汇编语言:开机 ,000111 , 打开
美国人的规则,你去翻译中国人的规则
GBK后台,UTF-8
请求数据转换流的时候,出现乱码
GBK, UTF-8
你的客户端进行重新编码,后台他传输的时候进行重新编码
表单上传的第一种方法:定义@field参数,分别制定各个表单的键
@FormUrlEncoded:解决编码乱码问题,表示请求正文将使用表单网址编码
表单上传的第二种方法:定义@FielMap,制定集合对象
@FormUrlEncoded:解决编码乱码问题,表示请求正文将使用表单网址编码
//步骤
//创建请求体对象
final RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
////////////////////////////////////////////Post网络请求方法///////////////////
/**
* Post上传表单第一种方法:定义@field参数,分别指定各个表单的键
* @FormUrlEncoded:解决编码乱码问题,表示请求正文将使用表单网址编码
*/
@FormUrlEncoded
@POST("web/LoginServlet")
Call psotFormFields(@Field("qq") String username,@Field("pwd") String password);
/**
*Post上传表单第二种方法定义@FielMap,指定集合对象
*@FormUrlEncoded:解决编码乱码问题,表示请求正文将使用表单网址编码
*/
@FormUrlEncoded
@POST("web/LoginServlet")
Call PostFormFieldMap(@FieldMap Map map);
/**
* post,上传文件
*/
@Multipart
@POST("web/UploadServlet")
Call postUploadFile(@Part("uploadfile\";filename=\"myuploadimg.png")RequestBody requestBody);
23种设计模式
设计模式并不是具体某一种代码,是一种思想,
一个可以运用多种编程的语言的思想
MVC,MVP,MVP,代码架构,他也是一种思想,
一个可以运用多种编程的语言的思想
BUG,项目如何运用的设计模式,项目中核心功能,你实现的具体步骤
通过看Retrofit里面.create(MyServerInterface.class);方法,发现其内部使用到了动态代理设计模式
整个的代码架构,之后你的代码才能够,高内聚,低耦合
第四天
你的网络请求已经成功了,数据你也可以打印出出来了,但是界面上就是没有显示
提前预习一下怎么封装,OKhttp+EventBus+MVC,保底 拔高:Retrofit和RxJava+MVP
频率还是非常,RxJava操作符,Retrofit的注解,URL拼接注意点(BUG)
RX是一种编程理念,叫响应式编程,在不同编程语言有不同的实现
RX是一种思想,函数是编程(响应是编程)
RXjava如何在项目中运用,http://v.qq.com/vplus/d291e0b195ba5005def1e7c7ee68744c/videos
https://github.com/zhihu/zhihu-rxjava-meetup
我用的RxJava的分支,RXAndroid,给我们android工程师专门用的
比Rxjava多了几个类,比如Android端的调度器,LOOP等,多了些,主线程的操作
使用时需要添加两个依赖,因为使用xjava也使用了xandroid
根据某种状况,做出对应的操作
/*RxAndroid所依赖的库*/
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
https://mp.weixin.qq.com/s?__biz=MzI3MDE0NzYwNA==&mid=2651435447&idx=1&sn=19f8f457dca675ffa987cf9bd45d6642&chksm=f12898ccc65f11dadb5e5fc36ecae5b9f93e263f3a7d92b7b27a5b1e7370d91c434781ee6334&mpshare=1&scene=23&srcid=05138uA1VNrYw45WiMOY8U6h#rd
官方源码地址:https://github.com/ReactiveX/RxJava
https://github.com/ReactiveX/RxAndroid
一个运行在Java VM上的库,通过可观测的序列来组成一个异步的,
基于事件的程序
特殊:观察者设计模式 ,lambada表达式.使用Stream特性操作集合,
异步操作,用到很多java1.的新特性
java8
观察者模式
* 观察者,订阅发布设计模式,RX的响应式编程
* java8新特性,实现观察者的设计模式 Observable , Observer, Stream ,
Lambda表达式
*
* 银行账户,当你的银行账户扣钱的时候,是不是你的手机就可以收到短信通知
* 银行被观察者 , 个人就是观察者 代码去实现这个需求
* 原理:当被观察者发生变化的时候,有被观察者主动通知观察者,
我发送了变化,你要根据这个变化,去做对应的逻辑处理
*
* Java 8的新特性:1.JavaJDK必须是1.8及以上版本
2.必须搭建studio环境才可以使用(工作空间搭建,项目中搭建)
*
*代码
* 1.创建一个被观察者
* 2.创建一个观察者
* 3.使二者关联
* 4.当被观察者观察数据发送变化时,观察者会执行update方法里的逻辑
/**
* date:2018/6/14
* author:易宸锋(dell)
* function:代表银行账户,被观察者 钱发送变化通知用户
*
* 1.被观察者继承observable类
* 2.观察数据
* 3.改变观察数据的ff
* 4.必须要写两个方法setChanged ; notifyObservers();
*/
* function:观察者 用户,当银行账户的钱发送变化时,就会收到消息
*
* 1.观察者实现observer类
* 2.覆写update方法
* 3.对Observable参数,要进行判读和强类型转换 ,
因为观察者观察的对象很多,所以我们要进行区分
* 4.强转被观察者对象,对其观察数据进行一系列的逻辑操作
*/
http://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650822789&idx=1&sn=aabf8b95e233a6bb19466e58fb90f812&chksm=80b78c1bb7c0050da725cb947e0ae3a657e74dbae210bd3228eeaa1f7a990e466bc31b25c0d0&mpshare=1&scene=23&srcid=0503IEuy3RzY0ycsMHxwAy9l#rd
Picasso,Glide,Fresco对比分析
http://blog.csdn.net/github_33304260/article/details/70213300
http://www.jianshu.com/p/ca5ce4444c37#
第五天
培养咱们的编程思维,
2.Retrofit,RXJava,观察者设计模式,动态代理设计模式
java8最后一个特性
stream:高级迭代器,以流的方式使用集合,可以在流的状态下,对数据库进行操作
注意:单元测试,stream只能在单元测试中运行
stream过滤步骤
1.将原始数据(集合)转换为stream流
2.对stream进行数据筛选
3.对筛选出来的数据进行打印
stream转换集合的类型:
1.将集合数据转为stream
2.对stream进行数据转换
3.对转换出来数据进行打印
RXjava:响应式编程,操作符(stream升级版),线程调度器
过滤的关键方法filter
关键方法map
integers.stream()
.map( (Integer integer) -> return integer.toString() )
.forEach( (String s) -> System.ou.println(s) );
jxAndroid解决问题:
让复杂的程序逻辑回归简单、清晰,不用再考虑什么同步,异步的事情
observable(被观察者)和subscriber(订阅者)可以做任何事情
-observable可以是一个网络请求,subscriber来显示请求结果
-observable可以是一个数据库查询,subscriber来显示查询结果
-observable可以是一个按钮点击事件,subscriber来响应点击事件
-observable可以是一个大图片文件的加载解析,subscriber来展示解析后的图片
Rxjava的四个基本概念:(可观察者、被观察者)
-observable(可观察者、被观察者)
- subscribe (订阅)
- Event (事件)
RXjava操作符
* 操作符(Operators)(常用的)
- map 转换对象
- flatMap 平铺对象
- filter 过滤
- distinct() 去重复(独特的)
- take(int i) 从开始取出固定个数
- doOnNext 输出元素之前的额外操作(不常用)
- toList() 打包对象为集合
* 调度器(Scheduler), 用于线程控制
- Schedulers.immediate() 默认线程
- Schedulers.newThread() 每次都创建新的线程执行
- Schedulers.io() 包含线程池的机制, 线程个数无限,
可以复用空闲线程(常用)
- Schedulers.computation() CPU密集计算线程,
线程池线程数和CPU数一致.处理图形运算
- AndroidSchedulers.mainThread()
Android更新界面的UI主线程(常用)
//RXandroid的基本使用,用的是RxAndroid的观察者功能
// rxAndroidBse();
//RxAndroid接收一个集合对象,对其中数据一个一个观察,咱们用数据处理的功能
// rxAndroidFrmo();
//RxAndroid接收一个集合对象,对整个集合进行操作,观察整个集合
// RxAndroidJust();
//RxAndroid接收一个集合对象,对其中数据进行过滤
// RxAndroidFilterStream();
//RxAndroid接收一个集合对象,对其中数据进行转换
// RxAndroidMapStream();
//RxAndroid把拿到的数个集合,进行拆分观察
RxAndroidFlatMap();
List integers = Arrays.asList(1, 2, 3, 4, 5);
List integers1 = Arrays.asList(6, 7, 8);
List integers2 = Arrays.asList(9, 10);
from
just
filter
map
flatMap
RXAndroid的实际运用
咱们是不是可以用RxAndroid操作符filter里面的数据进行过滤,
终止符合要求我们把这些数据放入新的集合里,控件根据这两个集合的数据,分别标识红色和绿色
第三周
第一天
多渠道打包的本质:在APK的内部加标识
多渠道打包目的:是为真实了解我们在不同分发市场的下载量,
以方便公司运营根据真实数据,做出对应推广
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}"
/>
//设置APK的渠道信息
productFlavors{
wandoujia{}
xiaomi{}
yidashi{}
zhiyuan{}
GoolgePlay{}
bawei{}
}
//分别进行打包,固定格式
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
//根据渠道自定义apk的名称,自带版本号,渠道名
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(
output.outputFile.parent,
"YDS-${variant.buildType.name}-${defaultConfig.versionName}-${variant.productFlavors[0].name}.apk".toLowerCase())
}
}
第二天
APK瘦身
概念:减少APK大小,节省用户下载apk流量及对用户手机空间占用的大小
(同样功能,apk越小越好,用户下载动机更大)
resources:编译后的布局文件
res:apk图片资源
classes.dex:代码编译偶生成的Java字节码文件
META-INF:存放签名,保证apk包的完整性和系统的安全
resources.arsc:编译后的布局文件
assets:目录存放一些配置文件
lib:下的子目录armeabi存放一些so文件或者jar包
META-INF目录下存放的是签名信息,用来保证apk包的完整性和系统的安全
res:apk图片资源
AndroidManifest.xml:清单文件
classes.dex:是java源码编译后生成的java字节码文件
参考资料:https://yq.aliyun.com/articles/57284?utm_source=qq
瘦身步骤:
首先你要做的是APK的分析,只有分析了他那里大,我们才可以针对性进行瘦身
分析工具,可以用studio,nimbledroid都一样
PNG,jpg,webp谷歌推出,使图片进步一体积变小,他的这个质量显示还非常好
webp仅仅支持Android
TingPNG:使用一种智能有损压缩技术( 通过降低图片中的颜色数量,
来减少存储图片所需的数据大小 )来降低PNG图片的大小,
这样压缩对图片的影响也不大,尤其在手机但是可以大大降低图片大大小
肆无忌惮的去对图片进行压缩,因为我们的图片在手机显示,
而手机最大也不过就是一本书的大小,再大就不是手机5英寸--7英寸之间
通过TinyPNG网站对这个图片进行压缩
图片格式:最大PNG,包含图片一些和效果无关信息,转换jpg体积变小
PNG:图片中没有透明度的要求,那么我们就把转换为JPG
美工给您切图是PNG,129KB,你可以用格式工厂,把他转换为JPG格式,
体积会变小很多,再接下来你把图片在用TIngPNG进行压缩
APK瘦身最关键的一点就是图片
切一套图,适配麻烦一点,但是有些公司,给切三套图,APK体积特别大,
你的图片瘦身有时能把APK体积瘦身到原来的零头
首先我给你讲的就是最关键的一个图片瘦身,
开启minifyEnabled混淆代码
在gradle使用minifyEnabled进行Proguard混淆的配置,可大大减小APP大小:
android {
buildTypes {
release {
minifyEnabled true
}
}
}
因为在我们的混淆文件里,有一个关键的地方可以指定我们压缩代码的级别
-optimizationpasses 5 # 指定代码的压缩级别
开启shrinkResources去除无用资源
在gradle使用shrinkResources去除无用资源,效果非常好。
android {
buildTypes {
release {
shrinkResources true
}
}
}
更人性化是该查找结果可以“一键删除”。当然,
可能图片是经过反射或字符拼接等方式获取,所以这个检测列表也不是全对,
删除后很大概率编译失败或部分页面挂死、无图等问题,这个无解,
工具还没智能到这个地步,你只能一遍又一遍“编译—解决部分问题—再编译再”,
别问我为什么知道。
第三天
项目问题:
命名一定要规范
https://www.cnblogs.com/plokmju/p/7670481.html
https://www.jianshu.com/p/45c1675bec69?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=qq
https://blog.csdn.net/vipzjyno1/article/details/23542617/
没有抽基类
没有抽基类
MVP内存泄漏
进度慢,没有加注释,
首页的联动效果不好
recycleview多条目
/**
* RecycleView使用过程
* 1.搭建环境(依赖,布局控件,初始化控件)
* 2.初始化数据
* 3.创建适配器
* 4.设置适配器及布局管理器
*
* RecycleView多条目的关键,创建不同ViewHolder的后,
更加数据里面Type的不同,让适配器加载不同的ViewHolder
*/
依赖 compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
/**
* 定义Bean类,和ListView原理也一样
*/
public class DataModel {
public static final int TYPE_ONE = 1;
public static final int TYPE_TWO = 2;
public static final int TYPE_THREE = 3;
public int type;
public int avatarColor;
public String name;
public String content;
public int contentColor;
}
int colors[] = {android.R.color.holo_blue_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light};
private List list;
/**
* 初始化数据,往集合里添加初始完的数据
*/
private void initData() {
//创建一个集合存放Bean类
list = new ArrayList<>();
//循环20次,有20个数据
for (int i = 0; i < 20; i++) {
//B.listView和GridView混排的效果
int type;
if (i < 5 || (i > 15 && i < 20)) {
type = 1;
} else if (i < 10 || i > 26) {
type = 2;
} else {
type = 3;
}
//使用random随机生成三种类型中的任意一种
// int type = (int) (Math.random() * 3 + 1);
//创建Bean
DataModel data = new DataModel();
//手头添加各种数据,实际开发中,则是解析服务器那拿到的数据即可
data.avatarColor = colors[type - 1];
data.type = type;
data.name = "Name: " + i;
data.content = "Content: " + i;
data.contentColor = colors[(type + 1) % 3];
list.add(data);
}
}
/**
* date:2018/6/21
* author:易宸锋(dell)
* function:RecylcView多布局的适配器
* 1.创建一个类继承RecycleView的adapter
* 2.定义Recyclev的ViewHolder,以方便我多布局实现
* 3.创建三种类型的Itme布局及ViewHolder
* 4.根据Type的不同我们加载对应的ViewHolder,实现我们的多布局效果
*
public int getItemViewType(int position) {更加各个Position的位置,返回不同的类别
return type;
}
onCreateViewHolder(ViewGroup parent, int viewType)
*/
* 子类共有,且实现相同的逻辑,直接抽取到基类中
* 子类共有,但是实现是不同的代码,那么我们就以抽象方法在基类得以体现
*
* 比如,子类都要进行赋值的操作,但是具体赋值的内容,
更加不同布局,有都不一样,我们就不能够在
* 基类里写死,我们以抽象方法去体现,模板设计模式,
第四天
https://blog.csdn.net/gongchuangsu/article/details/51527042
上边的是linkedList
这个是ArrayList
https://blog.csdn.net/gongchuangsu/article/details/51514389
适配的三种:
屏幕适配
机型适配
系统适配
屏幕适配
屏幕视频,之重要,非同寻常,无论你做任何APP,你最后都要适配
所以你们以后只要是去工作,那么无论是你实际工作还是你去面试,都会用到这一点
IOS系统和Android系统的区别
Android开源,Android源码是公开,系统随便用,
用IOS系统公司只有一家苹果,Android系统公司:小米,华为,OPP,魅族,锤子,
安卓的坏处
屏幕碎片化:UI界面变形,不好看
机型的碎片:有一个APP你转到三星手机,没有问题,运行正常,
但是你转到华为手机,一运行就闪退
比如:你打开相机原生的API,xxxx ,小米打开相机API方法就变了,
YYYY 报一个方法找不到异常
系统版本碎片化:V4,V7,V13的兼容包
我们在开发APP的时候也要注意到系统的问题,Android6.0动态权限
问题原因:
Android P版 谷歌在改进系统稳定性的措施上又增加了新的限制, 即应用程序引用非SDK接口,无论采用直接、反射、JNI获取等手段都将受到限制。
详细原因:http://baijiahao.baidu.com/s?id=1596298004755001784&wfr=spider&for=pc
因为我们项目使用的是插件化框架,所以项目中的context是通过反射来通过ContextImpl获取,但是因为P版本加了限制,所以导致反射找不到相对应的方法,从而获取不到context,导致出现了一个空指针异常,使项目无法打开
ContextImpl源码解析:https://blog.csdn.net/dongxianfei/article/details/54632423
解决方案:
华为给出的解决方案有三种
1.向谷歌申请加入灰名单(能量不够,可行性太小)
2.加入华为的白名单(在华为系统正常运行,但是在其他手机系统上无法正常运行)
3.重构代码,不使用当前的插件化框架(代价太大,工作量太大)
以及我在网上找到的三个方案:
https://blog.csdn.net/qq_31391977/article/details/79918689
当前采用的方案是第二种
机型适配:
按照手机的品牌去适配,
屏幕适配:
屏幕适配不是手机品牌去区分,以屏幕大小区分
适配主流的分辨率我们去适配
统计的大数据,对做开发十分有用:http://compass.umeng.com/#/?_k=0oq41k
https://feisher.github.io/ScreenAdapter/
最新适配开源框架,qq发明:http://www.androidchina.net/8128.html
最简单的适配:https://feisher.github.io/ScreenAdapter/
https://www.jianshu.com/p/1302ad5a4b04
分辨率:1920*1080 1280*720
为了实现我们的手机屏幕的完美适配:
1.图片适配
2.dimens适配
3.布局layout适配
4.java代码适配
java代码适配(常用)
有一些情况下,我们需要去动态的设置控件的大小或者是控件的位置,
比如dialog或者popupwindow的偏移量或者是显示的位置等等,
这个时候在xml布局里就显得有点乏力,
我们可以根据当前屏幕的大小属性来设置合适的数值。
代码:
//获取屏幕高宽
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
windowsHeight = metric.heightPixels;
windowsWight = metric.widthPixels;
//动态改变布局
LinearLayout production_factory = (LinearLayout)findViewById(R.id.production_factory);
LayoutParams params = production_factory.getLayoutParams();
params.height = windowsHeight / 2;
production_factory.setLayoutParams(params);
dp转换为px
通过dp和px转化操作进行适配(工具类,固定代码,更常用)
public class DensityUtil {
/**
* 根据手机的分辨率从 dip 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density; //获取手机的屏幕的密度
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}
https://feisher.github.io/ScreenAdapter/
5.权重适配
你权重用多了,那么UI性能就不会太好
公式:自身宽度+屏幕剩余宽度*比例=真正的宽度
L+(L-L-L)*1/3=2/3L
L:屏幕整体宽度
比例:权重
6.百分比适配(鸿洋的一个思路 , autoLayout,但是有问题,
于是有人优化后创造ScreenAdapter )
.9图适配
.9图适配,图片根据我们的内容,自动改变自己的大小
你要制作.9图片.必须PNG格式,哪怕每个给你的是JPG格式,
你自己也要改一下后缀名
魅族,黄金比例,导致适配和其他手机就是不一样
图片适配(.9图适配)
根据不同 的手机的密度,设置不同大小的图片
怎么做:把不同分辨率的手机,所需的图片,放到不同文件目录即可
原因:在不同密度的手机上,图片大小会不一致,导致图片会变形
每个手机的屏幕密度都不一样,当程序运行到手机上时,
系统会根据当前手机所对应的屏幕密度去找相应文件夹下面的图片。
比如当我们启动一个屏幕密度为mdpi的手机时,
加载的其实就是分辨率48x48大小为2.21k的ic_launcher图片,其他以此类推。
6中尺寸
图片提示:如果不考虑apk体积,美工切两套图,这一做,适配工作我们可以少做一点
dp(dip,dpi)密度(这个单位只有安卓有),指的是屏幕的像素密度
每一英寸(对角线的长度)存在的像素
dip,px
,sp,:描述字体的单位,谷歌推荐使用12sp以上的,通常可以用12sp,14sp,18sp,22sp,
这是谷歌推荐,为了避免精度的损失,不用奇数和小数
主流的分辨率是前六种:1280×720、1920×1080、854×480、960×540、800×480、1184×720。
(真实开发中,我们要做的事就是适配当前市场上绝大多数的 Android 屏幕就可以了。)
注意UI妹子,不懂什么是dp,只知道像素PX.(我们可以把PX转换为dp)
项目中res包下放图片的包代表的意思
drawable-ldpi、drawable-mdpi、drawable-hdpi
精度分别为低、中(android默认)、高。
对应的图片大小为:36x36、48x48、72x72。
xxxhdpi 4K:3840*2160
xxhdpi: 144*144
xhdpi:96*96
hdpi:72*72
mdpi:48*48
ldpi:36*36
dp是虚拟像素,在不同的像素密度的设备上会自动适配,比如:
在320x480分辨率,像素密度为160,1dp=1px
在480x800分辨率,像素密度为240,1dp=1.5px
计算公式:1dp*像素密度/160 = 实际像素数
drawable- hdpi、drawable- mdpi、drawable-ldpi的区别:
(1)drawable-hdpi里面存放高分辨率的图片,如WVGA (480x800),FWVGA (480x854)
(2)drawable-mdpi里面存放中等分辨率的图片,如HVGA (320x480)
(3)drawable-ldpi里面存放低分辨率的图片,如QVGA (240x320)
把图片按照大小放入对应的图片包中,如果混淆的话容易出bug
如果时间不够可以按分辨率高的来切
系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。
注意:把适合的图片放到对应的文件夹下,可以节省内存,
把高分辨的图片放到低分辨率的文件夹,会导致内存消耗随着差值越大,
消耗也就越大
如果条件有限,就按照高分辨的切一套图,放到高分辨的文件下,
就可以极大节省内存
既然一套图就可以适配,为什么现实中很多app会提供两三套图?
是不是只提供xhdpi会导致一定的性能问题?
是的,系统帮忙缩放图片也是要小号内存的,特备是差异大的时候
ppi的运算方式是:
PPI = √(长度像素数² + 宽度像素数²) / 屏幕对角线英寸数
dp:Density-independent pixels,以160PPI屏幕为标准,则1dp=1px,
dp和px的换算公式 :
dp*ppi/160 = px。比如1dp x 320ppi/160 = 2px。
内存优化:图片适配这一块如果注意到这个细节,也可以优化内存
,屏幕分辨率,
屏幕尺寸