这篇文章主要是记录自己在开发过程中遇到的一些小tip,别看这些东西很细微,有时候可以解决大麻烦,有些对于开发非常重要。还有就是自己曾经踩过的坑,我觉得都有必要记录下来。这些坑虽然不是每个人都会踩(有些确实是自己太笨了才踩的),但是既然我踩了,那可能还会有人踩,这样既惊醒自己,也可帮助他人。文章内容持续更新,也没有具体的分类,遇到一个添加一个。
greendao 生成代码
很多人都用过greendao,集成greendao时,会自动生成DaoMaster和DaoSession等文件,这些文件至关重要。但是前段时间我在集成后竟然无法生成这些文件,找了半天也不知道原因。后来才知道原因:在配置完greendao之后,必须有实体作为greendao的数据实体,如果一个实体都没有,它是不会生成DaoMaster等文件的;同时,greendao目前好像还不支持kotlin,无法将kotlin的数据类作为实体,还是要将实体卸载java文件中。
greendao 主键自增长
greendao可以设置主键自增长,但是我在用时就在想,如果没有没有主键,那么long类型不是为0吗,那还是有值呀。后来在使用时果然出现问题。实际上greendao在使用主键自增长是,主键类型必须是Long,而不是long,这种主键就可以为null了。
service启动activity
当在Service中启动activity时,需要添加
1 | it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
因为在service中启动的activity是没有栈的,启动时会程序判断当前是否是在service中启动且包含FLAG_ACTIVITY_NEW_TASK。这样启动的activity相当是singleInstance模式。
但是如果你在activity中配置了singleTask模式,就会依旧在task中启动一个。
synchronized使用
synchronized在锁代码块时其实锁的是对象,所以如果你在锁之前完全没有使用该对象,就白锁了。
位运算
1 | << : 左移运算符,num << 1,相当于num乘以2(<< 2 相当于乘以4) |
位运算比普通的运算块
ImageView scaleType
center:图片居中,不缩放,不放大,超过了就截取中间的,不超过就空着。
centerInside:图片居中,可缩放,不放大,超过了就缩小放置在中间,不超过就空着。
centerCrop:图片居中,可缩放,可放大,超过了就将缩小到有一边与ImageView边相等,不超过放大到最小边与ImageView边相等,保证图片完全充满ImageView
fitCenter:图片居中,可缩放,可放大,缩小放大到自己有一边到ImageView边界为止。
fitXY:可放大,可缩放,将自己完全充满ImageView,可以变形。
fitStart:可放大,可缩放,缩小放大到自己有一边到ImageView边界为止,同时靠左靠上。
fitEnd:可放大,可缩放,缩小放大到自己有一边到ImageView边界为止,同时靠右靠下。
FragmentPagerAdapter和FragmentStatePagerAdapter
FragmentPagerAdapter在滑动时,destroyItem只会将那些不可见的Fragment做detach处理,即只是从屏幕上移除,并不会销毁。同时即使使用notifyDataSetChanged,并且Fragment的数量减少,原来已有的Fragment也不会重新创建。所以这种方法适合item少量的情况。
FragmentStatePagerAdapter在执行destroyItem时,会将那些不可见的Fragment销毁,同时会保存其状态。在再次需要显示的时候回重新创建,并且传入之前的状态。所以这种方式适合item数量比较大时的情况,可以减少fragment的内存,但是在创建和销毁时会有所消耗。
ViewPager+Fragment禁止预加载延迟
当ViewPager.setOffscreenPageLimit(0);当设置预加载的page<1时,程序还是会设置默认的预加载页面为1,所以该方法不可行。
在FragmentPagerAdapter、FragmentStatePagerAdapter的instantiateItem方法中,都有将未显示的fragment设置为不可见状态:fragment.setUserVisibleHint(false);将可见的fragment设置为可见状态:fragment.setUserVisibleHint(true);所以我们只需要在fragment中重写setUserVisibleHint方法,可见时才加载布局。甚至可以使用ViewStub,在可见时初始化整个布局。
ViewPaper直接跳转到后面item
写一个Scroller类继承Scroller,重写其startScroll方法,将其滑动的时间设置为0。
1 | @Override |
使用反射的方法,将ViewPager的Scroller替换掉:
1 | Class c=viewPager.getClass(); |
这种方式会使普通的滑动的时间也为0,所以在具体使用时,可以通过滑动的具体情况,在跳转多页时才将时间设置0。
ProGuard的常用语法
-optimizationpasses 5 代码优化次数,android一般为5,理论上越多越好,到时多了混淆时间就长了,而且优化到无法再优化时就停止了,因此不一定是写着的次数
-libraryjars class_path 避免混淆应用的依赖包,如android-support-v4
-keep [,modifier,…] class_specification 不混淆某些类。例子:
1 | -keep public class javax.** |
-keepclassmembers [,modifier,…] class_specification 不混淆类的成员。例子:
1 | -keepclassmembers class * extends android.app.Activity{ |
-keepclasseswithmembers [,modifier,…] class_specification 不混淆类及其成员。例子:
1 | -keepclasseswithmembers class * { //不混淆有该init方法和该类 |
-keepnames class_specification 不混淆类及其成员名。例子:
1 | -keepnames class * implements java.io.Serializable //不混淆实现Serializable接口的类 |
-keepattributes {attribute_name,…} 不混淆给定的可选属性。例子:
1 | -keepattributes *Annotation*//不混淆注解 |
-keepclassmembernames class_specification 不混淆类的成员名。
-keepclasseswithmembernames class_specification 不混淆类及其成员名
1 | -keepclasseswithmembernames class * { //不混淆自定义View之类的类 |
-dontwarn [class_filter] 不提示warnning
-dontusemixedcaseclassnames //混淆时不产生混合大小写的类名
-dontskipnonpubliclibraryclasses //指定不去忽略非公共的库类
-dontpreverify //不预校验
-verbose //显示混淆的log,帮助排错
-optimizations !code/simplification/arithmetic,!field/,!class/merging/ //代码混淆采用的算法,一般不改变,使用谷歌默认算法即可
Jobscheduler使用
在Jobscheduler使用过程中,设置延时setMinimumLatency和设置最大延时setOverrideDeadline,不同手机延时时间可能会出现偏差。比如测试一台sony手机时,延时最小为5s,同时,一旦设置了最大延时则普通的延时时间无效,而如果单设置延时,延时时间也不一定准,而这些在模拟器上则完全没有出现。
一旦设置了这两个延时,则无法再设置重复时间,不然会报错,一旦设置了重启设备任务继续时setPersisted,需要配置系统开机事件的权限。
当onStopJob返回true,或者jobFinished(params, true)时,系统会在满足条件是重新调用onStartJob,可以设置setBackoffCriteria设置等待时间和时间策略,默认等待时间是30s,策略是指数增长。
BroadCast权限问题
1.自定义权限时,名字不是任意命名的,最好是包名.名字
的形式(经测试,a.b.名字也是可以的,但是直接名字不行)。
2.定义权限时,需要在发送方和接收方都定义权限和申请权限。
1 | <uses-permission android:name="c.a.SEND_MESSAGE" /> |
3.发送带权限的Broadcast时,说明应用要有该权限才能发出这条通知,但是任何普通的receiver都能接收。
4.Receiver配置权限后,说明只有有该权限的其他应用的通知,它才能接收到,但是自己的通知还是可以不传权限收到。
Broadcast其他tip:静态注册的Receiver,要不是单独一个文件的,要不是public static的;StickyBroadcast已经被废弃。
Service进程
service启动时可以设置进程android:process=":web"
。当在其他进程启动Service时,如果该Service没有单独设置进程,那么该Service依旧在主进程中。