@zifeng328573112
2021-05-18T01:59:14.000000Z
字数 10674
阅读 242
速度上面String不断的复制和更改是创建不同的对象来进行操作,这里涉及到GC垃圾回收机制,会影响速度;而StringBuffer和StringBuilder则处理同一个对象不存在JVM的GC回收。
线程安全与否:如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,不能同步的问题。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
广播的注册有两种形式,一种是在应用程序的代码上注册,
注册:registerReceiver(receiver,filter)
取消注册:unregisterReceiver(receiver)
另一种方形式则是在注册表androidmanifest.xml当中注册,
<receiver>
<intent-filter>
<action android:name = "android.intent.action.PICK"/>
</intent-filter>
</receiver>
startService(onCreate-onStartCommand-onDestory)
服务与启动者没有必然联系,启动者销毁,服务也可以存在;除非主动调用StopService方法来停止服务。
bindService(onCreate-onBind-onUnbind-onDestory)
服务与启动者相互关联,启动者销毁,那么服务也会跟着销毁;比如activityA中bind服务,然后activityB中也在使用该服务,一旦activityA销毁那么服务也会销毁,这个时候activityB中服务也就没用了,除非再bind一次。
startService之后再bindService这样避免宿主死亡之后service跟着被销毁。
避免:
1.不要在主线程做耗时操作(数据库查询,网络操作,大量数据存储,图片的切割等)。
2.不要在广播内做耗时操作,如果非要,那么请通过Service新起线程来进行耗时操作。
AndroidManifest.xml不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。生命周期如下:
onSaveInstanceState-onPause-onStop-onDestory-onCreate-onStart-onRestoreInstanceState-onResume
设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次。生命周期如下:
onSaveInstanceState-onPause-onStop-onDestory-onCreate-onStart-onRestoreInstanceState-onResume
设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。
一共23种,随便说几种就行,然后一般会问一些互相之间的区别啊,使用它们的好处之类的。
Android3.0之前2种动画,3.0之后3种动画
帧动画(Frame Animation):类似于一帧帧图片组成的电影,xml中多张图片组成,在UI线程中播放这个xml形成的动画。
补间动画(Tweened Animation):补间动画分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。补间动画的实现,一般会采用xml 文件的形式;当然也可以用Java代码直接实现。
属性动画(Property Animation):这是3.0之后加入的动画,为了弥补前面两种动画的不足。属性动画可以实现很多数学函数的路径动画。属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。
UI优化:
(1)减少层级,合理使用 RelativeLayout 和 LinerLayout,合理使用Merge,Include。
(2)提高显示速度,使用 ViewStub,它是一个看不见的、不占布局位置、占用资源非常小的视图对象。
(3)布局复用,可以通过标签来提高复用。
(4)尽可能少用wrap_content,wrap_content 会增加布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。
(5)删除控件中无用的属性。
更稳:减低 Crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。
(1)增加相应的判断,以及异常处理。
(2)避免在主线程做耗时操作。
更省:节省流量和耗电,节约内存,减少用户使用成本,避免使用时导致手机发烫。
耗电分析工具:Battery Historian
(1)避免浮点运算。
(2)根据客户端图片的大小要求叫UI做相应大小的图提供给服务器,避免过大消耗更多流量和电量。
(3)不用的广播,服务记得及时关闭。
内存分析工具:Memory Monitor
(1)对象引用:强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。
(2)减少不必要的内存开销:注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。
(3)使用最优的数据类型:比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等。
(4)图片内存优化:点9图减少图片大小以及可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等。
更小:安装包小可以降低用户的安装成本。
(1)做混淆优化代码。
(2)删除无用的代码及图片相应的本地库。
(3)Lint优化。
(4)zip压缩。
MVC:Model(数据模型)、View(视图)、(Controller)控制器(activity或者fragment),View将操作反馈给Activity,Activitiy去获取数据,数据通过观察者模式刷新给View。循环依赖
1.Activity(Fragment)重,很难单元测试。
2.View和Model耦合严重。
MVP:Model(模型层)、View、Presenter(接口,Model和View交互的桥梁),View将操作给Presenter,Presenter去获取数据,数据获取好了返回给Presenter,Presenter去刷新View。PV,PM双向依赖
1.如果功能复杂,Presenter接口爆炸(界面的操作更新UI都必须配合Presenter的接口来操作)。
2.Activity需要重写很多接口方法来更新UI。
3.Model和View不直接进行交互,达到解耦效果。
/**
* 冒泡排序 从小到大
* 每次冒泡出相对最大的数到相对最后面
*/
public static void bubbleSort(int[] data) {
if (data == null) throw new IllegalArgumentException("data can't be null");
if (data.length < 2) return;
//外层循环data.length-1次
for (int i = 0; i < data.length - 1; i++) {
//内层循环每次选择一个最大的数冒泡到最后 循环次数每次都会少1次直到外层循环完毕data.length-i-1
for (int j = 0; j < data.length - i - 1; j++) {
if (data[j] > data[j + 1]) {
int temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
}
}
System.out.println(i + "冒泡排序:" + Arrays.toString(data));
}
System.out.println("冒泡排序:" + Arrays.toString(data));
}
/**
* 选择排序 从小到大
* 每次选出一个相对较小的排前面
*/
public static void selectSort(int[] data) {
if (data == null) throw new IllegalArgumentException("data can't be null");
if (data.length < 2) {
return;
}
//循环次数data.length-1
for (int i = 0; i < data.length - 1; i++) {
int index = i;
//每次选择第i个数依次和后面的数进行比较,谁小谁变成第i个数;循环次数也是data.length-i-1
for (int j = i; j < data.length - 1; j++) {
if (data[index] > data[j]) {
index = j;
}
}
if (i != index) {
int temp = data[index];
data[index] = data[i];
data[i] = temp;
}
System.out.println(index + "选择排序:" + Arrays.toString(data));
}
System.out.println("选择排序:" + Arrays.toString(data));
}
/**
* 快速排序实现
*
* @param array
* @param low
* @param high
*/
public static void quickSort(int array[], int low, int high) {
if (low < high) {
int pivot = partition(array, low, high);
quickSort(array, low, pivot - 1);
quickSort(array, pivot + 1, high);
System.out.println(pivot);
}
}
/**
* @param array 待排序数组
* @param low 数组下标下界
* @param high 数组下标上界
* @return pivot
*
*/
public static int partition(int array[], int low, int high) {
//当前位置为第一个元素所在位置
int p_pos = low;
//采用第一个元素为轴
int pivot = array[p_pos];
for (int i = low + 1; i <= high; i++) {
if (array[i] < pivot) {
p_pos++;
swap(array, p_pos, i);
}
}
swap(array, low, p_pos);
return p_pos;
}
/**
* 交换指定数组a的两个变量的值
*
* @param a 数组应用
* @param i 数组下标
* @param j 数组下标
*
*/
public static void swap(int a[], int i, int j) {
if (i == j) return;
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
https://www.jianshu.com/p/e99b5e8bd67b
基于不同位置
Dalvik:基于寄存器,编译和运行都会快一些
JVM: 基于栈, 编译和运行都会慢些
字节码的区别
Dalvik: 执行.dex格式的字节码,是对.class文件进行压缩后产生的,文件变小
JVM: 执行.class格式的字节码
运行环境的区别
Dalvik : 一个应用启动都运行一个单独的虚拟机运行在一个单独的进程中
JVM: 只能运行一个实例, 也就是所有应用都运行在同一个JVM中
ART GC 与 Dalvik 的主要区别在于 ART GC 引入了移动垃圾回收器。使用移动 GC 的目的在于通过堆压缩来减少后台应用使用的内存。目前,触发堆压缩的事件是 ActivityManager 进程状态的改变。当应用转到后台运行时,它会通知 ART 已进入不再“感知”卡顿的进程状态。此时 ART 会进行一些操作(例如,压缩和监视器压缩),从而导致应用线程长时间暂停。目前正在使用的两个移动 GC 是同构空间压缩和半空间压缩。
与 Dalvik 相比,暂停次数从 2 次减少到 1 次。Dalvik 的第一次暂停主要是为了进行根标记,而这个动作在 ART中已经是让线程自己去标记,然后马上恢复运行,这样就减少了一次暂停。
与 Dalvik 类似,ART GC 在清除过程开始之前也会暂停 1 次。两者在这方面的主要差异在于:在此暂停期间,某些 Dalvik 环节在 ART 中并发进行。这些环节包括 java.lang.ref.Reference 处理、系统弱清除(例如,jni 弱全局等)、重新标记非线程根和卡片预清理。在 ART 暂停期间仍进行的阶段包括扫描脏卡片以及重新标记线程根,这些操作有助于缩短暂停时间。
相对于 Dalvik,ART GC 改进的最后一个方面是粘性 CMS 回收器增加了 GC 吞吐量。不同于普通的分代 GC,粘性 CMS 不移动。系统会将年轻对象保存在一个分配堆栈(基本上是 java.lang.Object 数组)中,而非为其设置一个专属区域。这样可以避免移动所需的对象以维持低暂停次数,但缺点是容易在堆栈中加入大量复杂对象图像而使堆栈变长
Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程(比喻成没有界面的activity),也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。
IntentService是Service的子类,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。通过Handler looper message的方式实现了一个多线程的操作,同时耗时操作也可以被这个线程管理和执行,同时不会产生ANR的情况。
Service:service是android的一种机制,对应的service是运行在主线程上的,它是由系统进程托管。他们之间的通信类似于client和server,是一种轻量级的ipc通信,这种通信的载体是binder,它是在linux层交换信息的一种ipc。
线程:线程是程序执行的最小单元,它是分配CPU的基本单位。可以用线程来执行一些异步的操作。
区别:Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制;而Service则可以被多个activity共用(当然你也可以说我可以在服务里面新起线程这样不就可以被多个activity共用了,其实这样的本质还是共用的服务而不是线程)。
我们不用服务替代线程是因为:服务(子类IntentService则是在内部添加了子线程)也是运行在主线程上面,而不是子线程,相当于你还是需要新起线程来完成相应的操作,这又是何苦啦;并且一个类里面需要多线程操作的情况,服务是不是显得很无力。各有各的优点,下面来看使用情况。