greenDao缓存踩坑

 分类:Android, Java 阅读 (103)  greenDao缓存踩坑已关闭评论
9月 042020
 

  今天在执行如下操作时发现一个奇怪的问题,首先使用update更新数据库,然后select数据进行上传,结果select出来的数据总是旧数据。查了一天更新和上传那块的代码也没发现什么问题,后来发现是greenDao的问题。

  问题:greenDao中创建DaoSession对象时默认是使用缓存的,这样select出来的数据可能就不是最新的

  解决方法:

  方法一:创建DaoSession对象的时候传入IdentityScopeType.None参数默认禁止缓存,示例如下:

  方法二:在select的时候执行一下DaoSession对象的clear方法(注:本方法笔者未验证是否有其他问题,请谨慎使用),如下:

 

关于Android系统栏中back和home键的实现

 分类:Android, Java 阅读 (147)  关于Android系统栏中back和home键的实现已关闭评论
8月 252020
 

本文基于Android8.1系统编写

一、背景

  今天想实现自定义的back和home键,比着葫芦画瓢,把back和home键的部局抄过来了。但怎么也没找到back和home键的java功能实现部分。

后来度娘了一下才找到实现的原理。

  参考链接:http://blog.chinaunix.net/uid-701715-id-3054850.html

  自己也记录一下

二、按钮的组件类KeyButtonView

  在部局中可以看到,back和home键用了一个自定义view,开始我还以为是为了实现按钮的动画效果才自定义了一个这个view,现在发现自己天真了!

  KeyButtonView的核心在于,他定义了一个可设置的部局属性keyCode,用于设置按钮对应的键,如下back键的部局代码:

  keyCode=”4″对应的为KeyEvent.KEYCODE_BACK键

  在KeyButtonView的构造函数中,读取并保存了这个属性:

  如此,在部局文件中设置的keyCode读到了类中

三、模拟发送按键

  原理是,拦截onTouch事件,当按钮按下时发送keyCode的ACTION_DOWN操作,当按钮弹开时发送keyCode的ACTION_UP操作,完成一次按键的操作。

  sendEvent函数,先构造KeyEvent对象,然后通过InputManager发送到系统,代码如下:

 

 Posted by on 2020-08-25

关于View类的几个宽度值的区别

 分类:Android, Java 阅读 (114)  关于View类的几个宽度值的区别已关闭评论
8月 172020
 

本文同样适用于高度相关的对应函数

一、几个函数

1. getWidth()

View的实际宽度

2. getMeasuredWidth()

是用setMeasureDimension设置的宽度,这个并不能作为最终的View的宽度来使用,只是在onMeasure的时候用户计算的宽度,只能在这个函数里使用?

3. getMeasuredWidthAndState()

和getMeasuredWidth()类似,但是返回的值包括measuredWidth和MEASURED_SIZE_MASK或者MEASURED_STATE_TOO_SMALL的标志位。

4. getMinimumWidth()

应该是在布局设计时,设置的minWidth属性对应的值或者使用函数setMinimumWidth动态设置的值

5. getSuggestedMinimumWidth()

如果View设置了背景,则取mMinWidth和背景的最小宽度中比较大的一个值。

6. 去除padding后的实际宽度

如果需要考虑padding参数,则去除padding后的实际内容宽度为:

getWidth() – getPaddingLeft – getPaddingRight

二、其他注意事项

1. 在onMeasure函数中不能使用getWidth()和getHeight()函数,此时这两个值都是0

2. MeasureSpec,三种度量规格:

  • UNSPECIFIED – 未指定
  • EXACTLY – 固定尺寸
  • AT_MOST – 最大值

 

 Posted by on 2020-08-17

Android中正方形TextView的实现

 分类:Android, Java 阅读 (184)  Android中正方形TextView的实现已关闭评论
8月 012020
 

  本自定义组件实现了一个以高度为标准的正方形TextView组件,如果想以其他标准(最大或者最小宽度、高度)需要再进行修改:

  自定义View的代码如下;

 

慎用addOnGlobalLayoutListener

 分类:Android, Java 阅读 (151)  慎用addOnGlobalLayoutListener已关闭评论
8月 012020
 

使用如下代码:

本来是想实现tvMyAccount这个TextView的宽度始终等于高度。

但是这个会造成UI线程一直在处于忙碌状态,可能会造成如下后果:

1. Android Studio中Layout Inspector无法获取Activity的部局

2. 使用Instrumentation进行自动化测试时,无法测试

addOnGlobalLayoutListener的原理

待整理

 Posted by on 2020-08-01

为什么greenDao的autoincrement字段必须为Long型

 分类:Android, Java 阅读 (160)  为什么greenDao的autoincrement字段必须为Long型已关闭评论
7月 292020
 
一、首先,第一点,为什么不是int型,而是long型

  没在代码中看出原因,在greenDao的源代码中只是硬性的规定必须使用Long/long型,估计是为了确保自增值的范围足够大?(应该不是)

  做此限制的代码在文件DaoGenerator/src/org/greenrobot/greendao/generator/Property.java中

  在sqlite库的源码中,绑定字段的地方也没有int型相关的参数,只有bindLong和bindDouble、bindString等,和这个有关?

  sqlite库源码:frameworks\base\core\java\android\database\sqlite\SQLiteProgram.java

二、为什么是Long而不是long?

  奇怪的是,官方代码中的意思是Long/long都可以,但long是不行的,在插入2条记录的时候就会报ndroid.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: notes.localid错误。

  这个涉及使用sql语句向数据库的自增字段插入数据的问题,sql语句如下:

  insert into table(id, name) values(NULL, ‘ldr’);

  在greenDao中如果成员是long型,则未赋值时返回的是0,如果是Long型,则返回的是null,所以是这个原因?

  这个涉及的文件是bean类生成的相应的Dao类,比如”NoteBeanDao.java”

 Posted by on 2020-07-29

LaunchMode应用解析

 分类:Android, Java 阅读 (128)  LaunchMode应用解析已关闭评论
7月 202020
 

本文基于Android8.1系统进行测试

一、四种LaunchMode

1. standard

默认方式,每次总是新建一个Activity,并放在当前任务的顶端。

2. singleTop(和FLAG_ACTIVITY_SINGLE_TOP标志一样的作用)

如果当前Activity栈的顶部是要打开的Activity,则不新建Activity,而是复用这个Activity,但是intent是通过onNewIntent事件传入(不能通过getIntent得到)。

如果当前Activity栈的顶部不是要打开的Activity,则新建一个Activity

3. singleTask

若被启动的activity的taskAffinity与调起这个activity的不同,则为此Activity新建一个任务,并且此Activity为新建任务的根Activity。若相同,则与普通启动无区别。

若所有task中已经有此Activity,则不新建此Activity,将Activity所在的task调到前台,并清楚Activity到栈顶之间的Activity。

三种情况:

1) Activity存在于某个任务中,且在栈顶,不创建新Activity,已存在的Activity触发onNewIntent

2)Activity存在于某个任务中,但不在栈顶,不创建新Activity。

又分两种情况:

I. 如果栈顶Activity的taskAffinity与此Activity的相同则自动关闭栈顶的Activity,直到此Activity时,触发onNewIntent

II. 如果栈顶Activity的taskAffinity与此Activity的不同,并且也是singleTask的,不会自动关闭顶部 的Activity,需要手动关闭,直到此Activity时,触发onNewIntent(但是在某些机型上没发现这种情况,而是I中的情况)(目前测试在Android9.0之前是这样的,9.0之后是第I种情况)

3)Activity不存在于某个任务中,则在当前任务中新建一个Activity并放在栈顶

4. singleInstance

该Activity始终在一个新的任务中创建,并且由该Activity启动的其他Activity始终在另外的任务中。就是说该Activity所在的任务有且只有一个Activity。

二、和FLAG_ATCIVITY_CLEAR_TOP的交互

 

三、关于taskAffinity

 

四、其他

1. moveTaskToBack()函数

五、其他参考链接

官方:了解任务和返回堆栈

官方:概览屏幕

 Posted by on 2020-07-20

Android中一些系统类的研究(ActivityManagerService相关)

 分类:Android, Java 阅读 (152)  Android中一些系统类的研究(ActivityManagerService相关)已关闭评论
7月 152020
 

一. ResolveInfo

  用于根据intent获取AndroidManifest.xml中的Activity或者Service或者Provider中包含对应的intent-filter的信息?

  成员包括ActivityInfo、ServieInfo、ProviderInfo、Icon等。

二. ActivityInfo

  从AndroidManifest.xml中获取的应用的activity或者receiver的信息。

  AndroidManifest.xml中定义的几种launchMode的定义也在这个类里有对应的定义
  • public static final int LAUNCH_MULTIPLE = 0; //对应standard
  • public static final int LAUNCH_SINGLE_TOP = 1; //对应singleTop
  • public static final int LAUNCH_SINGLE_TASK = 2; //对应singleTask
  • public static final int LAUNCH_SINGLE_INSTANCE = 3; //对应 singleInstance

 

三. ActivityStackSupervisor

  ActivityStack主管,在ActivityManagerService中使用一个ActivityStackSupervisor来管理所有的ActivityStack?

  通过查找系统所有代码发现,只有在此类的createStack函数中新建了ActivityStack实例(并不是说只创建了一个实例),所以所有的ActivityStack是通过这个对象来管理的。

  也只有在ActivityManagerService中新建了一个ActivityStackSuperVisor实例,也就是系统中只有一个ActivityStackSupervisor对象

  另外这个类还负责和PackmanagerService的一些交互,还用于判断进程是否存在(调用ams的函数),并起动新进程(调用ams的函数)

四. ActivityRecord

  用于表示Activity的一结构,包括Activity相关的很多信息。

  一些变量

  final String taskAffinity – 在AndroidManifest.xml中的Activity节点中定义的taskAffinity

  1. isResolverActivity()

  此Activity是不是一个ResolverActivity

  2. mActivityType可能为以下几种类型

  static final int APPLICATION_ACTIVITY_TYPE = 0;
  static final int HOME_ACTIVITY_TYPE = 1;
  static final int RECENTS_ACTIVITY_TYPE = 2;
  static final int ASSISTANT_ACTIVITY_TYPE = 3;

五. ActivityStarter

  诠释如何启动Activity的控制器。

  根据intent和flag信息,并将这些信息准备相应的activity、Activity Task和Activity Stack的信息。

  我看了一下代码,主要是根据intent中的flag信息处理相关的Activity、Activity Task和Activity Stack的相关信息。

  这个类是为了减轻ActivityManagerService的代码量,分离出来一部分逻辑,好让逻辑更清晰一些。

  一些成员变量:

  mSourceRecord – 源Activity的ActivityRecord对象

  mInTask – 调用startActivity的context所在的task,可能为null(比如service中调用或者通知栏调用?),在启动Activity时在setInitialState函数中传入被赋值

  mLaunchFlags – 新Activity启动时的一些FLAG标志,通过一系列的计算得到

  private boolean mLaunchSingleTop; 在setInitialState函数中根据要启动的Activity的ActivityRecord对象的launchMode判断

  private boolean mLaunchSingleInstance; 在setInitialState函数中根据要启动的Activity的ActivityRecord对象的launchMode判断

  private boolean mLaunchSingleTask; 在setInitialState函数中根据要启动的Activity的ActivityRecord对象的launchMode判断

  1. 函数setInitialState()

  在startActivityUnchecked函数中调用,用于初始化本类中的一些变量。

  3. 函数computeLaunchingTaskFlags()

  计算要启动的Activity的task标志

  4. 函数computeSourceStack

  计算源Activity所在的stack?

六. ActivityStack

  Activity栈类,用于管理某个Activity栈。

  其中:

  final ArrayList<ActivityRecord> mLRUActivities – 是用于存储正在运行Activity列表,列表中最外面一条记录,是最近使用的Activity

七. TaskRecord

  final ArrayList<ActivityRecord> mActivities – 此Task中的Activity列表

  private ActivityStack mStack; – 此Task所在的Activity栈

  1.函数getBaseIntent()

  获取任务中根Activity的 intent

  2.函数getRootActivity()

  从根Activity往外遍历(列表mActivities),获取非finishing状态的Activity的ActivityRecord对象

八. ResolverActivity

  继承自Activity,如果startActivity传入的intent对应多个应用,比如intent中打开url链接,但是系统中有多个浏览器应用,将弹出这个Activity让用户选择 。

 Posted by on 2020-07-15

art和Dalvik的一些知识

 分类:Android, Java 阅读 (149)  art和Dalvik的一些知识已关闭评论
7月 072020
 
一、Art的诞生

  Art是在Android4.4系统中加入的,但是默认是不开启的

  Art和Dalvik的切换是通过指定一个系统设置项来切换的,见art/Android.mk中.PHONY: use-art下面那一段脚本

  本文摘录片段

  libdvm.so是DalvikVm的so库

  libart.so是Art Vm的so库

  之所以两个能同时切换,是因为他们都实现了JNI_Create_JavaVm的入口函数。

二、Art的崛起

  在Android4.4加入Art之后,一直是默认没有开启的,直到Android5.0,DalvikVm彻底被删除,art担当大任

  可以对比下4.4和5.0源码中dalvik/vm下的代码结构

  http://androidxref.com/4.4_r1/xref/dalvik/vm/

  http://androidxref.com/5.0.0_r2/xref/dalvik/vm/

  可以看到从5.0开始,dalvik的代码已经被删除掉了

 Posted by on 2020-07-07

Android中art虚拟机启动流程

 分类:Android, Java 阅读 (181)  Android中art虚拟机启动流程已关闭评论
7月 072020
 

本文基于Android8.1系统进行研究

一、启动zygote

在Linux内核启动完成后,首先启动系统的第一个进程init进程

init进程会读取init.rc中的配置文件

其中有Zygote的配置,init进程将启动zygote进程

zygote的入口在app_main.cpp中的main函数中

二、解析传入参数,调用AndroidRuntime的start方法

在app_main.cpp中的main函数中,首先解析传入的相关参数,并通过如下代码进入ZygoteInit的main函数中

runtime是AppRuntime的一个实例,AppRuntim继承自AndroidRuntime

start函数定义在AndroidRuntime中,下面是start函数的注释

start函数中的这段代码切入到了startVm函数中

三、startVm函数

这个函数前边也是一堆处理Vm启动参数的逻辑

在函数的最好调用JNI_CreateJavaVM函数通过c++层的库创建虚拟机

四、JNI_CreateJavaVM函数

JNI_CreateJavaVM函数是在art/runtime/java_vm_ext.cc中实现的,代码如下:

Runtime是在art/runtime/runtime.h中定义的类

Runtime::Current()返回一个静态的Runtime实例,代码如下:

runtime-Start()启动虚拟机

五、其他参考文章

Android ART运行时无缝替换Dalvik虚拟机的过程分析

https://blog.csdn.net/zhu929033262/article/details/77053640

Android虚拟机art流程:从zygote开始梳理art的启动(1)

https://www.shennongblog.com/art-zygote/

 Posted by on 2020-07-07