目录
- 2.volatile、synchroized?
- 3.Java中 == 、equals的区别?
- 4.String、StringBuffer与StringBuilder的区别? 优先推荐使用哪个?
- 5.Interface、abstract的区别?
- 6.ArrayList和LinkedList的区别?
- 8.两个Activity之间跳转必然会执行哪几种方法?
- 9.Activity四种Launcher Mode及其使用场景?
- 10.怎么保证service不被杀死?
- 11.Broadcast的注册方式与区别?
- 12.Android中的几种动画及其特点?
- 13.Intent可以传递哪几种数据类型?
- 14.谈谈对AIDL和Binder的理解?
- 15.描述Handler的原理?
- 16.ANR产生原因和常见处理方式?
- 17.如何自定义view?
- 18.对于context的理解?
- 19. mvc、mvp和mvvm区别?
- 20.手写一种常见的设计模式?
2.volatile、synchroized?
(1)、synchronized介绍
- synchronized能保证原子性,有序性,可见性。
- synchronized**可见性:**当线程获取锁时会从主内存中获取共享变量的最新值,释放锁的时候会将共享变量同步到主内存中。从而,synchronized具有可见
- synchronized有序性:synchronized语义表示锁在同一时刻只能由一个线程进行获取,当锁被占用后,其他线程只能等待。因此,synchronized语义就要求线程在访问读写共享变量时只能“串行”执行,因此synchronized具有有序性。
- synchronized**原子性:**因为每次只有一个线程在执行,其他线程只能等待 ,所以只能“串行”执行 ,而volatile能保障有序性是通过内存屏障,保障可见性是通过像cpu发送一条硬件指令lock,但是对于一些复杂的业务计算volatile不能保障其原子性
(2)、volatile介绍
- volatile能保证有序性,可见性,但不能保证原子性。
- volatile可见性:如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令 ,这个指令会个变量所在缓存行的数据写回到系统主内存 ,并且这个写回内存的操作会使得其他CPU里缓存了该内存地址的数据无效 (是每个处理器通过嗅探在总线观察 )
- volatile保障内存有序性:我们都知道,为了性能优化,JMM在不改变正确语义的前提下,会允许编译器和处理器对指令序列进行重排序,那如果想阻止重排序要怎么办了?答案是可以添加内存屏障。
- volatile写操作是在前面和后面分别插入内存屏障,而volatile读操作是在后面插入两个内存屏障
为什么volatile不能保障原子性?
-
原子性:原子性是指一个操作是不可中断的,要么全部执行成功要么全部执行失败,有着“同生共死”的感觉**。及时在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程所干扰。
-
1、 int a = 10; 是原子操作,将10赋值给线程工作内存的变量a 2、 a++; 读取变量a的值,对a进行加一的操作,将计算后的值再赋值给变量a,这三个操作无法构成原子操作 问题:如何让volatile保证原子性,必须符合以下两条规则: 1、运算结果并不依赖于变量的当前值,或者能够确保只有一个线程修改变量的值; 2、变量不需要与其他的状态变量共同参与不变约束
(5)、volatile和synchronized的区别:
类别 | synchronized | volatile |
---|---|---|
本质 | 锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 | 告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; |
使用级别 | 变量、方法、和类级别 | 变量级别 |
变量修改 | 可以保证变量的修改可见性和原子性 | 实现变量的修改可见性,不能保证原子性; |
线程阻塞 | 可能会造成 | 不会造成 |
标记的变量是否被编译器优化 | 可以被优化 | 不会被优化 |
3.Java中 == 、equals的区别?
== 首先用在比较基本类型数据时,比较的是值是否相同,用在比较引用类型,则比较的是引用地址是否相同。
equals 是Object的一个方法,在没有被重写的情况下,是和==等效的,在被重写的情况下一般比较的是内容是否相同,比如常见的String,Integer等类都重写了equals方法,比较的是内容是都相同。
4.String、StringBuffer与StringBuilder的区别? 优先推荐使用哪个?
String:字符串常量 不适用于经常要改变值得情况,每次改变相当于生成一个新的对象
StringBuffer:字符串变量 (线程安全)
StringBuilder:字符串变量(线程不安全) 确保单线程下可用,效率略高于StringBuffer
5.Interface、abstract的区别?
共同点
(1)两者都是抽象类,都不能实例化。
(2)interface实现类和abstract继承类都必须实现抽象方法。
不同点
(1)interface需要实现,用implements;abstract需要继承,用extends。
(2)一个类可以实现多个interface;一个类只能继承一个abstract。
(3)interface强调功能的实现;abstract强调从属关系。
(4)interface的所有抽象类都只有声明没有方法体;abstract抽象方法可以选择实现,也可以选择继续声明为抽象方法,无需实现,留给子类去实现。
6.ArrayList和LinkedList的区别?
-
ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;
-
对于随机访问get和set,ArrayList要优于LinkedList,因为LinkedList要移动指针;
-
对于添加和删除操作add和remove,一般大家都会说LinkedList要比ArrayList快,因为ArrayList要移动数据。
8.两个Activity之间跳转必然会执行哪几种方法?
首先定义两个Activity,分别为A和B。
当我们在A中激活B时,A调用onPause()方法,此时B出现在屏幕时,B调用onCreate()、onStart()、onResume()。
这个时候B【B不是一个透明的窗体或对话框的形式】已经覆盖了A的窗体,A会调用onStop()方法。
9.Activity四种Launcher Mode及其使用场景?
1、standard:标准化启动模式
每启动一个Activity,都会重新创建Activity的新的实例,将其放在栈的顶部。不需要考虑这个实例是否已经存在。
每一次启动,它的onCreate()、onStart()、onResume()方法都会被依次调用。
2、singleTop:栈顶复用模式
当前栈中已经有该Activity实例,并且该实例位于栈顶时,会去调用onNewIntent()方法。
当前栈中已有该Activity的实例,但是该实例不在栈顶时,依然会去创建Activity。
当前栈中不存在该Activity实例时,会去新创建一个该Activity。
应用场景:IM对话框、新闻客户端推送。
3、singleTask:栈内复用模式
它主要检测【寻找,通过taskAffinity】整个栈中是否已经存在当前想要启动的Activity,存在的话直接将该Activity置于栈顶,之前位于该Activity上面的Activity将被销毁,同时调用onNewIntent()方法,而不存在的话进行创建。
应用场景:应用主界面。
4、singleInstance:
一个人独享一个任务栈。当该Activity启动时,系统会创建一个新的任务栈,同时将Activity放到这个新的任务栈当中,有别的应用来启动该Activity时,由于栈内复用的特性,不会再去创建相应Activity任务栈,而是这两个应用独享一个Activity实例。
例如:应用A中现有两个Activity E、Activity F,为standard启动模式,应用B中有一个Activity G,但其启动模式是singleInstance。应用A想用应用B任务栈当中的Activity G,尽管在不同的应用下,但是应用A仍然会直接复用Activity G。
特性:
1、以SingleInstance模式启动的Activity具有全局唯一性【全局唯一性即指在整个系统当中只会存在一个这样的实例】;
2、如果在启动这样一个Activity时,【整个系统都是单例的】,已经存在了一个实例;
3、以SingleInstance模式启动的Activity具有独占性。
应用场景:呼叫来电。
10.怎么保证service不被杀死?
方式一:onStartCommand方法中,返回
START_STICKY
在StartCommand()
几个常量:
START_STICKY
系统重新创建服务并且调用onStartCommand()
方法,但并不会传递最后一次传递的intent
,只是传递一个空的intent
。除非存在将要传递来的intent
,那么就会传递这些intent
。这个适合播放器一类的服务,不需要执行命令,只需要独自运行,等待任务。START_NOT_STICKY
系统不重新创建服务,除非有将要传递来的intent
。这是最安全的选项,可以避免在不必要的时候运行服务。START_REDELIVER_INTENT
系统重新创建服务并且调用onStartCommand()
方法,传递最后一次传递的intent
。其余存在的需要传递的intent
会按顺序传递进来。这适合像下载一样的服务,立即恢复,积极执行。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
}
方式二: 提升Service优先级
前台服务是被认为用于已知的正在运行的服务,当系统需要释放内存时不会优先杀掉该进程。前台进程必须发一个notification
在状态栏中显示,知道进程被杀死。因为前台服务一直消耗一部分资源,但不像一般服务那样会在需要的时候被杀掉,所以为了节约资源,保护电池寿命,一定要在建前台服务的时候发送notification
,提示用户。当然系统提供的方法就必须有notification
参数的,所以不要想着怎么把notification
隐藏掉。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Intent notificationIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification noti = new Notification.Builder(this)
.setContentTitle("Title")
.setContentText("Message")
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pendingIntent)
.build();
startForeground(123456,noti);
return Service.START_STICKY;
}
startForeground()
方法就是将服务设置为前台服务,参数123456就是这个通知的唯一的id,只要不为0即可。
方式三:在onDestory()中发送广播开启自己
service+broadcast方式,就是当service调用到ondestory()
的时候,发送一个自定义的广播,当收到广播的时候,重新启动service;
<receiver android:name="com.example.demo.MyReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT"/>
<action android:name=com.example.demo.destroy"/>// 这个是自定义的action
</intent-filter>
</receiver>
在service中的ondestroy()
时候:
@Override
public void onDestroy(){
stopForeground(true);
Intent intent = new Intent("com.example.demo.destroy");
sendBroadcast(intent);
super.onDestroy();
}
在MyReceiver中
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("com.example.demo.destroy")){
Intent sevice = new Intent(this, MyService.class);
this.startService(sevice);
}
}
}
11.Broadcast的注册方式与区别?
BroadcastReceiver的工作流程是这样的:系统程序或用户程序广播了某Intent之后,就会被与该Intent匹配的广播接收者(这个广播接收者可以是用户自己通过扩展BroadcastReceiver得到的Receiver)所接收,接着就会执行onReceive(Context context, Intent intent)方法中的代码,在这里可以完成自己要实现的功能。
所以,为使Receiver与广播的某Intent相匹配,则需要注册该Receiver,注册一个广播接收者Receiver方法有两种。
第一种是在android的manifest中静态注册:
<receiver android: name =“包名.自己扩展的广播接收者名">
<intent-filter>
<!----和Intent中的action对应--->
<actionandroid:name=“com.forrest.action.mybroadcast”/>
</intent-filter>
</receiver>
第二种是在代码中动态注册:
//和广播中Intent的action对应;
IntentFilter filter = new IntentFilter(“com.forrest.action.mybroadcast”);
MyBroadcastReceiver br= newMyBroadcastReceiver();
// registerReceiver(BroadcastReceiver receiver, IntentFilter filter);
registerReceiver(br, filter);
但此方法需要解除所注册的广播:
在onStop()或onDestroy()方法中添加unRegisterReceiver(br);
两种注册类型的区别是:
1)第一种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
2)第二种不是常驻型广播,也就是说广播跟随程序的生命周期。
****注:****除了用于过滤广播的IntentFilter可以在代码中动态创建外,其他组件的IntentFilter必须在AndroidManifest.xml中注册,如:Activity、Service。
12.Android中的几种动画及其特点?
Tween动画,这种实现方式可以使视图组件移动、放大、缩小以及产生透明度的变化。
Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。
13.Intent可以传递哪几种数据类型?
intent间传送数据一般有两种常用的方法: 1、extra 2、data。
extra可以用Intent.putExtra放入数据。新启动的Activity可用Intent.getExtras取出Bundle,然后用Bundles.getLong,getInt,getBoolean,getString等函数来取放进去的值。
Data则是传输url。url可以是指我们熟悉的http,ftp等网络地址,也可以指content来指向ContentProvider提供的资源。Intent.setData可以放入数据,Intent.getData可以取出数据
14.谈谈对AIDL和Binder的理解?
AIDL全称是:Android Interface Define Language。编译器可以通过AIDL文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的。
AIDL使用代理类在客户端和实现层间传递值。如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用AIDL产生的class.
Binder是一个类,它实现了IBinder接口,而IBinder接口定义了与远程对象的交互协议。通常在进行跨进程通信时,不需要实现IBinder接口,直接从Binder派生即可。
除了实现IBinder接口外,Binder中还提供了两个重要的接口。
(1)Transact(),客户端调用,用于发送调用请求
(2)onTransact(),服务端响应,用于接收调用请求
Binder是客户端与服务端的通信媒介,其主要用在Service组件应用中。
Service与客户端通信,有两种方式,AIDL和Messenger。AIDL基于Binder,而Messenger基于AIDL
15.描述Handler的原理?
loop轮询检测发送消息到MessagerQuery,MessageQuery对Message入列,Handler回调方法处理消息,重写handMessage方法刷新ui。
16.ANR产生原因和常见处理方式?
ANR:Application Not Responding。在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应,当用户操作的在5s内应用程序没能做出反应,BroadcastReceiver在10秒内没有执行完毕,就会出现应用程序无响应对话框,这既是ANR。
避免方法:Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者异步方式)来完成。主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。
17.如何自定义view?
第一步,创建自己的自定义类,让它继承View类,并重写构造方法。
第二步,重写ondraw()方法。
18.对于context的理解?
Context字面意思上下文,位于framework package的android.content.Context中。
Context提供了关于应用环境全局信息的接口。它是一个抽象类,它的执行被Android系统所提供。它允许获取以应用为特征的资源和类型。同时启动应用级的操作,如启动Activity,broadcasting和接收intents。**context最主要的功能是加载和访问资源。**在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
application context伴随application的一生,与activity的生命周期无关。application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取。
每个activity都是context,里面包含了运行时的状态。同样application也有一个context,android会保证这个context是唯一的实例。
19. mvc、mvp和mvvm区别?
MVC:View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些 业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,即View。所以,在MVC模型里,Model不依赖于View,但是 View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。
MVP:MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。
MVVM:数据双向绑定,通过数据驱动UI,M提供数据,V视图,VM即数据驱动层
20.手写一种常见的设计模式?
饿汉式单例模式——在类初始化时,已经自行实例化
public class SingletonInstance {
//私有构造方法
private static SingletonInstance (){
}
//声明成员变量
private static SingletonInstance singletonInstance = new SingletonInstance();
//对外提供接口获取该实例
public static SingletonInstance getSingletonInstance(){
return singletonInstance ;
}
}
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。
懒汉式单例----在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//静态工厂方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}