在Android中,可供选择的存储方式有SharedPreferences、文件存储、SQLite数据库方式、内容提供器(Content provider)和网络。
https://blog.csdn.net/yueqi1125/article/details/78957174
保存登录用户名密码等情形,应注意多进程并发读的时候数据可能不准确。
需要注意:getSharedPreferences(“User”, Context.MODE_PRIVATE)方法中第二个参数需要了解Android的四种枚举方式下面是详细的解释:
私有模式
Context.MODE_PRIVATE 的值是 0;
①只能被创建这个文件的当前应用访问
②若文件不存在会创建文件;若创建的文件已存在则会覆盖掉原来的文件
追加模式
Context.MODE_APPEND 的值是 32768;
①只能被创建这个文件的当前应用访问
②若文件不存在会创建文件;若文件存在则在文件的末尾进行追加内容
可读模式
Context.MODE_WORLD_READABLE的值是1;
①创建出来的文件可以被其他应用所读取
可写模式
Context.MODE_WORLD_WRITEABLE的值是2
①允许其他应用对其进行写入。
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。多用于大量数据操作时,能明显减少耗时。
https://blog.csdn.net/a443453087/article/details/7222247
即使用事务处理进行优化,默认SQLite的数据库插入操作,如果没有采用事务的话,它每次写入提交,就会触发一次事务操作,而这样几千条的数据,就会触发几千个事务的操作,这就是时间耗费的根源
SQLite目前还不支持drop column,所以必须想出另外一种方法来进行表字段的删除。
如下sql语句会复制一个和record表一样表结构的temp表出来,但是我们想要的是去除某一个字段(例如去除record表中的name字段,就不要复制它就好了),所以sql语句如下:
create table temp as select recordId, customer, place, time from record where 1 = 1;
这样复制出来的表就会缺少“name”字段,然后我们删除旧表并修改新表名即可。
https://blog.csdn.net/phenixyf/article/details/70597232
https://blog.csdn.net/vansbelove/article/details/78416791
scrollBy()也调用了scrollTo()方法,实现了基于当前位置的滑动,而scrollTo()是基于所传参数的绝对滑动
1、public void startScroll(int startX, int startY, int dx, int dy, int duration)
函数功能说明:开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位(dx正值向左滑,负值向右滑),到达坐标为 (startX+dx , startY+dy)处。
2、
/**
* 在其内部完成平滑滚动的逻辑 。在整个后续的平滑滚动过程中,computeScroll()方法是会一直被调用的,
* 我们需要不断调用Scroller的computeScrollOffset()方法来进行判断滚动操作是否已经完成了
* 如果还没完成的话,那就继续调用scrollTo()方法,并把Scroller的curX和curY坐标传入,然后刷新界面从而完成平滑滚动的操作。
*/
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
https://blog.csdn.net/mountain_hua/article/details/81545490
外部拦截:可以在父布局中将onInterceptTouchEvent的返回值设为true进行拦截
内部拦截:类似反射的方式进行拦截,稍显复杂。需要配合requestDisallowInterceptTouchEvent进行拦截
https://www.cnblogs.com/cr330326/p/6340973.html
View的工作流程主要是指measure、layout、draw这三大流程,即测量、布局、绘制,其中measure确定View的测量宽/高,layout确定View的最终宽/高和四个顶点的位置,而draw则将View绘制到屏幕上。
measure过程
measure过程要分情况来看,如果是一个原始的View,那么通过measure方法就完成了其测量过程,如果是一个ViewGroup,除了完成自己的测量过程外,还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个流程。
Layout过程
Layout的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,它在onLayout中会遍历所有的子元素并调用其layout方法,在layout方法中onLayout方法又会被调用。
draw过程
draw过程就比较简单了,它的作用是将View绘制到屏幕上面,View的绘制过程循序以下几步:
- 绘制背景background.draw(canvas)
- 绘制自己(onDraw)
- 绘制children(dispatchDraw)
- 绘制装饰(onDrawScrollBars)
https://www.jianshu.com/p/647913c11673
https://blog.csdn.net/xxdw1992/article/details/81128900
measureSpec
由其父容器的measureSpec及自身的LayoutParams共同决定EXACTLY
,specSize均为childSize
wrap_content
,则不管其父容器的specMode为哪种,子View对应的specMode均为AT_MOST
,specSize均为parentLeftSize
setMeasuredDimension
方法设置view的最终measureSize。但View的真实大小是在Layout阶段才确定下来的,通过child.layout(left,top,right,bottom)
.View的measure size与 layout size不必相等,但绝大多数情况下是相等的。总的来说就是计算出来的父View的MeasureSpec不断往子View传递,结合子View的LayoutParams 一起再算出子View的MeasureSpec,然后继续传给子View,不断计算每个View的MeasureSpec,子View有了MeasureSpec才能更测量自己和自己的子View。
https://blog.csdn.net/myth13141314/article/details/81449109
自定义View的分类:
主要用于实现不规则的效果,即这种效果不方便通过布局的组合方式来实现。相当于就是得自己“画”了。采用这种方式需要自己支持wrap_content,padding也需要自己处理
主要用于实现自定义的布局,看起来很像几种View组合在一起的时候,可以使用这种方式。这种方式需要合适地处理ViewGroup的测量和布局,并同时处理子元素的测量和布局过程。比如自定义一个自动换行的LinerLayout等。
这种方法主要是用于扩展某种已有的View,增加一些特定的功能。这种方法比较简单,也不需要自己支持wrap_content和padding。
这种方式也比较常见,和上面的第2种方法比较类似,第2种方法更佳接近View的底层。
自定义View需要注意的地方:
直接继承View和ViewGroup的控件需要在onMeasure方法中处理wrap_content的方法。处理方法是在wrap_content的情况下设置一个固定的尺寸
直接继承View的控件需要在onDraw方法中处理padding,否则用户设置padding属性就不会起作用。直接继承ViewGroup的控件需要在onMeasure和onLayout中考虑padding和子元素的margin对其造成的影响,不然将导致padding和子元素的margin失效。
View中已经提供了post系列方法,完全可以替代Handler的作用。
在View的onDetachedFromWindow方法可以停止线程和动画,因为当View被remove或是包含此View的Activity退出时,就会调用View的onDetachedFromWindow方法。如果不处理的话很可能会导致内存泄漏
View带有滑动嵌套时,需要处理好滑动冲突问题
在View的onDraw方法中不要创建太多的临时对象,也就是new出来的对象。因为onDraw方法会被频繁调用,如果有大量的临时对象,就会引起内存抖动,影响View的效果
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
从源码中可以看出,这两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。
另外需要注意的是,onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。
onTouch()中的ACTION_UP执行之后,会执行onClick()方法。onClick()方法在onTouchEvent()里面执行。
https://www.cnblogs.com/dubo-/p/6638094.html
view在UI线程去更新自己;而SurfaceView则在一个子线程中去更新自己
surfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面
在UI的主线程中更新动画,时间一旦太长就会出现问题
surfaceView 在新的线程中更新画面所以不会阻塞你的UI主线程,但是涉及到线程同步,需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event
invalidate()用于在主线程中更新UI,postInvalidate()用与在子线程中更新UI,其内部也是使用了handler。
https://blog.csdn.net/caoxiao90/article/details/51545560
https://blog.csdn.net/mountain_hua/article/details/82696065
尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,
因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,
decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,
无需再使用java层的createBitmap,从而节省了java层的空间。
LRU全称是Least Recently Used,即最近最久未使用的意思。
LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。也是利用了程序的局部性原理。
https://blog.csdn.net/u014732103/article/details/78592476
目前常用的一种缓存算法是Least Recently Used,简称:LRU,LRU是近期最少使用算法,它的核心机制是当缓存控件满时,会优先淘汰那些近期最少使用的缓存对象。采用LRU算法的缓存有:LruCache以及DiskLruCache,LruCache用于实现内存缓存,DiskLruCache用于实现存储设备缓存,因此通过这二者的结合使用,就可以很方便地实现一个高效的ImageLoader。
View动画,帧动画,属性动画。
帧动画使用比较简单,但比较容易引起OOM,因此在使用帧动画时要尽量避免使用过多尺寸过大的图片。
View动画不能真正改变View的位置,而属性动画可以
属性动画改变的是对象的属性,比如真正的X,Y坐标属性,而不仅仅是view。
https://www.jianshu.com/p/b117c974deaf
时间插值器(TimeInterpolator)的作用是根据时间流逝的百分比计算出动画进度的百分比。
类型估值器(TypeEvaluator)的作用是根据属性值改变的百分比计算出改变后的属性值。
https://blog.csdn.net/mp624183768/article/details/79289561
名称 | 像素密度(dpi)范围 |
---|---|
mdpi | 120dpi~160dpi |
hdpi | 160dpi~240dpi |
xhdpi | 240dpi~320dpi |
xxhdpi | 320dpi~480dpi |
xxxhdpi | 480dpi~640dpi |
https://blog.csdn.net/xgdtale/article/details/71774247
https://www.aliyun.com/jiaocheng/7722.html
px : pixels(像素),是屏幕的像素点
ppi : pixels per inch(像素密度,所表示的是每英寸所拥有的像素数量);一个基于density的抽象单位,如果一个160dpi的屏幕,1dp=1px
dpi : dots per inch(每英寸的点数)
dp/dip : device independent pixels(设备独立像素)又叫Density Independent Pixels,即密度无关像素
sp : scaled pixels(放大像素)同dp相似,但还会根据用户的字体大小偏好来缩放(建议使用sp作为文本的单位,其它用dip)
https://blog.csdn.net/lichaoxin16/article/details/79314427
1. res会在R.java生成索引ID,在打包的时候判断资源有没有用到,没用到的时候不会被打包进apk中(res/raw文件夹除外),而assets不会。
2. res用getResource()访问,assets用AssetsManager访问。
3. res/raw与assets里的文件在打包的时候都不会被系统二进制编译,都被原封不动打包进APK,通常用来存放游戏资源、脚本、字体文件等。但res/raw不可以创建子文件夹,而assets可以。
4. res/xml会被编译成二进制文件。res/anim存放动画资源。