android面试题整理

android面试题整理,第1张

目录
    • 2.volatile、synchroized?
        • (1)、synchronized介绍
        • (2)、volatile介绍
        • **(5)、volatile和synchronized的区别:**
    • 3.Java中 == 、equals的区别?
    • 4.String、StringBuffer与StringBuilder的区别? 优先推荐使用哪个?
    • 5.Interface、abstract的区别?
          • 共同点
          • 不同点
    • 6.ArrayList和LinkedList的区别?
    • 8.两个Activity之间跳转必然会执行哪几种方法?
    • 9.Activity四种Launcher Mode及其使用场景?
        • 1、standard:标准化启动模式
        • 2、singleTop:栈顶复用模式
        • 3、singleTask:栈内复用模式
        • 4、singleInstance:
    • 10.怎么保证service不被杀死?
        • 方式一:onStartCommand`方法中,返回`START_STICKY
        • 方式二: 提升Service优先级
        • 方式三:在onDestory()中发送广播开启自己
    • 11.Broadcast的注册方式与区别?
        • 第一种是在android的manifest中静态注册:
        • 第二种是在代码中动态注册:
    • 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的区别:
类别synchronizedvolatile
本质锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。告诉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的区别?
  1. ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;

  2. 对于随机访问get和set,ArrayList要优于LinkedList,因为LinkedList要移动指针;

  3. 对于添加和删除 *** 作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
    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中静态注册:

        <intent-filter>
              
               
        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;
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/877686.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存