Android面试题(二)Android基础1

24 篇文章 0 订阅

二、Android基础

(一)Android基础知识点

1、四大组件是什么

Android四大组件有Activity,Service服务,Content Provider内容提供,BroadcastReceiver广播接收器。

2、Activity之间的通信方式

常用的三种 Activity 之间的通信方式:

  • 使用 Intent/Bundle
  • 类静态变量
  • 全局变量

3、横竖屏切换的时候,Activity 各种情况下的生命周期

Fragment生命周期

onAttach

onCreate

onCreateView

onActivityCreate                ______以上相当于Activity的onCreate方法

 

onStart                             ______相当于Activity的onStart方法

onResume                        ______相当于Activity的onResume方法

onPause                           ______相当于Activity的onPause方法

onStop                             ______相当于Activity的onStop方法

 

onDestroyView

onDestroy

onDetach                         ______以上相当于Activity的onDestroy方法

 

当Activity包含一个Fragment的时候,Activity和Fragment生命周期的变化:

Activity(onCreate)---> Fragment(onAttach onCreate onCreateView onActivityCreate)--->

Activity(onStart)---> Fragment(onStart)--->

Activity(onResume)---> Fragment(onResume)--->

Fragment(onPause)---> Activity(onPause)--->

Fragment(onStop)---> Activity(onStop)--->

Fragment(onDestroyView onDestroy onDetach)---> Activity(onDestroy)

由于Fragment依附于Activity,所以启动的时候Activity的方法肯定在前面,Fragment的方法在后面,但是在要销毁的时候,Fragment的方法先执行,再执行Activity的方法。

在宿主Activity中使用hide、show方式切换Fragment的时候,Fragment的生命周期是:

a 初始化

Fragment1(onAttach onCreate onCreateView onActivityCreate) --->  Fragment1(onStart)---> Fragment1(onResume)

Fragment2(onAttach onCreate onCreateView onActivityCreate) --->  Fragment2(onStart)---> Fragment2(onResume)

b Fragment1和Fragment2来回切换都没有回调生命周期

c 当某一个Fragment调用了跳转到另一个Activity的时候(或者按HOME键的时候)

Fragment1(onPause)---> Fragment1(onStop)

Fragment2(onPause)---> Fragment2(onStop)

d 当在一个透明的Activity中弹出一个Dialog时(与Activity的情况相同)

Fragment1(onPause)

e 当宿主Activity被销毁的时候

Fragment1(onPause)---> Fragment1(onStop)---> Fragment1(onDestroyView onDestroy onDetach)

Fragment2(onPause)---> Fragment2(onStop)---> Fragment2(onDestroyView onDestroy onDetach)

当采用FragmentStatePagerAdapter适配器加载‘Fragment的时候,Fragment的生命周期同上面的情况相同

4、两个Activity 之间跳转时必然会执行的是哪几个方法?

一般情况下比如说有两个activity,分别叫A,B。

当在A 里面激活B 组件的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。

这个时候B覆盖了A的窗体, A会调用onStop()方法。

如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。

如果B已经存在于Activity栈中,B就不会调用onCreate()方法。

5、Activity的四种启动模式对比

 

       standard、singleTop、singleTask、singleInstance

standard-默认模式:个模式是默认的启动模式,即标准模式,在不指定启动模式的前提下,系统默认使用该模式启动Activity,每次启动一个Activity都会重写创建一个新的实例,不管这个实例存不存在,这种模式下,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中。这个Activity它的onCreate(),onStart(),onResume()方法都会被调用。

 

singleTop-栈顶复用模式:这个模式下,如果新的activity已经位于栈顶,那么这个Activity不会被重写创建,同时它的onNewIntent方法会被调用,通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该Activity的实例,则情况与standard模式相同。需要注意的是这个Activity它的onCreate(),onStart()方法不会被调用,因为它并没有发生改变。

singleTask-栈内复用模式:这个模式十分复杂,有各式各样的组合。在这个模式下,如果栈中存在这个Activity的实例就会复用这个Activity,不管它是否位于栈顶,复用时,会将它上面的Activity全部出栈,并且会回调该实例的onNewIntent方法。其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过taskAffinity属性指定。如果这个任务栈不存在,则会创建这个任务栈。

singleInstance-全局唯一模式:  该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。

6、Activity状态保存于恢复

当系统内存不足时,系统会强制结束一些不可见的Activity以节省内存资源。在某些情况下,当被强制结束的Activity再次显示时会出现一些问题。

例如:一个APP有2个Activity界面:Activity1 和 Activity2。用户在Activity1填写了一些数据后跳转到了Activity2,Activity2完全把Activity1遮盖了起来。当系统资源不足时,被Activity2完全遮盖住的Activity1也有可能被系统干掉。如果发生了这种情况,当用户在Activity2折腾了一番又点击返回按钮想返回Activity1时,就可能会有一些问题了。因为Activity1已经被系统强制销毁了,用户之前在Activity1填写的数据已经不存在了。所以Activity类中还提供了onSaveInstanceState() 和 onRestoreInstanceState() 2个方法可以用来解决这个问题。

1、onSaveInstanceState() 

onSaveInstanceState() 方法用来在Activity被强制销毁之前保存数据,onSaveInstanceState()方法会携带一个 Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用 putString()方法保存字符串,使用 putInt()方法保存整型数据。每个保存方法需要传入两个参数,第一个参数是键,第二个参数是真正要保存的内容。

2、onRestoreInstanceState()

onRestoreInstanceState() 方法用来取得之前在onSaveInstanceState() 保存的值。

另外,除了onRestoreInstanceState()可以取得onSaveInstanceState() 保存的值之外,onCreate()函数也可以取得保存的值,这些值就存在onCreate()函数的参数savedInstanceState里,在哪个函数取出这些值就要看具体的需求了。

7、fragment各种情况下的生命周期

Fragment完整的生命周期

既然是介绍Fragment 在各种情况下的生命周期,那么Fragment完整的生命周期也是必须要介绍一下啦,由于Fragment是必须依赖于Activity的,所以Fragment的生命周期必然和Activity的生命周期有一定的关联,下面这张图就能很好的反应这个关系(哈哈,我没在官网上找到这张图,借大神一张图)

上图就是Fragment完整的生命周期,相比于Activity的生命周期多了如下几个方法

onAttach():当Fragment与Activity发生关联时,该方法被调用

onCreateView():创建Fragment的视图

onActivityCreate():当Activity的onCreate()返回时被调用

onDestoryView():与onCreateView()是对应的,当Fragment的视图被销毁时,该方法被调用

onDetach(): 与onAttach() 方法相对应,当Fragment与Activity的关联被取消时,该方法被调用

 

Activity中调用replace()方法时的生命周期

新替换的Fragment:onAttach > onCreate > onCreateView > onViewCreated > onActivityCreated > onStart > onResume

被替换的Fragment:onPause > onStop > onDestroyView > onDestroy > onDetach

 

Activity中调用replace()方法和addToBackStack()方法时的生命周期

新替换的Fragment(没有在BackStack中):onAttach > onCreate > onCreateView > onViewCreated > onActivityCreated > onStart > onResume

新替换的Fragment(已经在BackStack中):onCreateView > onViewCreated > onActivityCreated > onStart > onResume

被替换的Fragment:onPause > onStop > onDestroyView

 

Fragment在运行状态后跟随Activity的生命周期

Fragment在上述的各种情况下进入了onResume后,则进入了运行状态,以下4个生命周期方法将跟随所属的Activity一起被调用:

onPause > onStop > onStart > onResume

8、Fragment状态保存startActivityForResult是哪个类的方法,在什么情况下使用?

https://blog.csdn.net/barryhappy/article/details/53229238

9、fragment之间传递数据的方式?

  • Intent传值
  • 广播传值
  • 静态调用
  • 本地化存储传值
  • 暴露接口/方法调用
  • eventBus等之类的

10、Activity 怎么和Service 绑定?

1、首先是创建service类和activity类。

2、在service类中   

定义一个内部类继承自Binder类:

public class MyBinder extends Binder{  

        public Service1 getService(){  

            return Service1.this;  

        }  

    }  

实例化onBind()方法:

private final IBinder binder = new MyBinder();  

    public IBinder onBind(Intent intent) {  

        Log.i(LOG, "onBind............");  

        return binder;  

    } 

3、在activity中完成绑定

Intent intent = new Intent(Activity1.this,Service1.class);  

        bindService(intent, conn, Context.BIND_AUTO_CREATE);  

1)、    注意到bindService的第二个参数是一个ServiceConnection类型的参数。service和其他组件之间的连接都表示为一个ServiceConnection,要想将service和其他组件进行绑定,就需要实现一个新的ServiceConnection。

所以应该在activity中定义一个内部类

public ServiceConnection conn= new ServiceConnection() {  

        @Override  

        public void onServiceDisconnected(ComponentName name) {  

//当连接意外断开时调用

            myservice = null;  

        }  

        @Override  

        public void onServiceConnected(ComponentName name, IBinder service) {  

//当建立连接时调用

            Log.i(LOG, "onServiceConnected>>>>>>>>");  

            myservice = ((Service1.MyBinder)service).getService();  

        }  

    };   

这里的myservice就是我们获取到的已经绑定的service的实例。

2)、  bindService的第三个参数是一个flag。

 可以使用的flag有

BIND_AUTO_CREATE:绑定完成后就启动目标service

BIND_DEBUG_UNBIND:这只在debug时使用,跟unbind有关。

BIND_NOT_FOREGROUND:确保被绑定的service永远不会有运行于前台的优先级,因为默认情况下,绑定一个service会提高它的优先级

BIND_ABOVE_CLIENT:确保客户端处于前台时,绑定的service也变为前台进程

BIND_ALLOW_OOM_MANAGEMENT:允许系统在低内存等状态下删除该service(这是自己对源码中注释的理解)

BIND_WAIVE_PRIORITY:绑定service时不改变其优先级

BIND_ADJUST_WITH_ACTIVITY:系统根据service所绑定的activity的重要程度来调整这个service的优先级。

11、service和activity怎么进行数据交互?

  • 通过 broadcast:通过广播发送消息到 activitry
  • 通过 Binder:通过与 activity 进行绑定

1) 添加一个继承 Binder 的内部类,并添加相应的逻辑方法。

2) 重写 Service 的 onBind 方法,返回我们刚刚定义的那个内部类实例。

3) Activity 中创建一个 ServiceConnection 的匿名内部类,并且 重 写 里 面 的 onServiceConnected 方 法 和onServiceDisconnected 方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用(在onServiceConnected方法中,我们可以得到一个刚才那个 service 的 binder 对象,通过对这个 binder 对象进行向下转型,得到我们那个自定义的 Binder 实例,有了这个实例,做可以调用这个实例里面的具体方法进行需要的操作了)。

12、Service的开启方式

第一种: 开启完服务之后, 就跟服务没关系了. 不管服务的死活了.

startService 开启服务, 生命周期显示: onCreate -> onStartCommand 服务正在运行了.

当服务已经在后台运行, 无论调用多少次startService都不会重新创建服务, 而是调用onStartCommand

stopService 停止服务, 当服务正在后台运行, stopService会把服务关掉, 生命周期: onDestory

注 : 这种方式开启服务, 不可以调用服务中的方法.

第二种: 可以调用服务中的方法, 当前的activity开启的service, 它俩的关系是, 不求同时生, 但求同时挂.

bindService 绑定服务 , 生命周期: onCreate -> onBind 服务正在运行了.

unbindService 解绑服务. 生命周期: onUnbind -> onDestory 服务被销毁了.

13、谈谈你对ContentProvider的理解

https://blog.csdn.net/qq_35133320/article/details/53563337

https://blog.csdn.net/u012858833/article/details/51629245

14、说说ContentProvider、ContentResolver、ContentObserver 之间的关系

ContentProvider——内容提供者, 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。

ContentResolver——内容解析者, 其作用是按照一定规则访问内容提供者的数据(其实就是调用内容提供者自定义的接口来操作它的数据)。

ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。

15、请描述一下广播BroadcastReceiver的理解

广播接收者,android四大组件之一,也是唯一一个能动态注册的组件。

1)广播接收者是一个专注于接收广播通知信息,并做出对应处理的组件。很多广播是源自于系统──比如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以进行广播──比如说,通知其它应用程序一些数据下载完成并处于可用状态。

2)应用程序可以拥有任意数量的广播接收者以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。

3)广播接收者没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

广播分几种?他们有什么区别?

 广播被分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播。

  然而有序广播是按照接收者声明的优先级别,被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C 。优先级别声明在 intent-filter 元素的 android:priority 属性中,数越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置 。有序广播的接收者可以终止广播Intent的传播,广播Intent的传播一旦终止,后面的接收者就无法接收到广播。

  另外,有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。

   Context.sendBroadcast()

发送的是普通广播,所有订阅者都有机会获得并进行处理。

   Context.sendOrderedBroadcast()

发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播(BroadcastReceiver.abortBroadcast()),如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将数据通过setResultExtras(Bundle)方法存放进结果对象,然后传给下一个接收者,下一个接收者通过代码:Bundle bundle = getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。

16、本地广播和全局广播有什么差别?

本地广播和全局广播的差别

BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通信的一种方式

LocalBroadcastReceiver仅在自己的应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全广播只在这个程序里,而且效率更高。

BroadcastReceiver 使用

1.制作intent(可以携带参数)

2.使用sendBroadcast()传入intent;

3.制作广播接收器类继承BroadcastReceiver重写onReceive方法(或者可以匿名内部类啥的)

4.在java中(动态注册)或者直接在Manifest中注册广播接收器(静态注册)使用registerReceiver()传入接收器和intentFilter

5.取消注册可以在OnDestroy()函数中,unregisterReceiver()传入接收器

LocalBroadcastReceiver 使用

LocalBroadcastReceiver不能静态注册,只能采用动态注册的方式。

在发送和注册的时候采用,LocalBroadcastManager的sendBroadcast方法和registerReceiver方法

17、AlertDialog,popupWindow,Activity区别

AlertDialog builder:用来提示用户一些信息,用起来也比较简单,设置标题类容 和按钮即可,如果是加载的自定义的view ,                                  调用 dialog.setView(layout);加载布局即可(其他的设置标题 类容 这些就不需要了)

popupWindow:就是一个悬浮在Activity之上的窗口,可以用展示任意布局文件

activity:Activity是Android系统中的四大组件之一,可以用于显示View。Activity是一个与用记交互的系统模块,几乎所              有的Activity都是和用户进行交互的

区别:AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。

18、Application 和 Activity 的 Context 对象的区别

首先Activity.this和getApplicationContext()返回的不是同一个对象,一个是当前Activity的实例,一个是项目的Application的实例,这两者的生命周期是不同的,它们各自的使用场景不同,this.getApplicationContext()取的是这个应用程序的Context,它的生命周期伴随应用程序的存在而存在;而Activity.this取的是当前Activity的Context,它的生命周期则只能存活于当前Activity,这两者的生命周期是不同的。getApplicationContext() 生命周期是整个应用,当应用程序摧毁的时候,它才会摧毁;Activity.this的context是属于当前Activity的,当前Activity摧毁的时候,它就摧毁。

19、Android属性动画特性

(1) 对任意对象的属性执行动画操作:属性动画允许对任意对象的属性执行动画操作,因为属性动画的性质是通过反射实现的。

(2)可改变背景颜色。

(3)真正改变 View 本身:因为是通过反射改变其属性,并刷新,如改变width,他会搜索getWidth(),反射获取,再通过进行某种计算,将值通过setWidth()设置进去并更新。

20、介绍下SurfaceView

我们在使用普通View时,如果我们绘制过程逻辑很复杂,我们的界面更新还非常频繁,这时候就会造成界面的卡顿,影响用户体验,为此我们可以用SurfaceView来解决这一问题。

SurfaceView更适合于频繁刷新界面,而且还会开启一个子线程来对页面进行刷新。同时在底层机制中就实现了双缓冲机制。(双缓冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上。双缓冲主要是为了解决 反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里,然后整体的一次性画出来)

使用SurfaceView的话需要三个步骤,分别是创建、初始化、使用。

1.创建SurfaceView

我们需要自定义一个类继承自SurfaceView,并且实现两个接口以及接口定义的方法。

重写3个构造函数,以及surfaceCreated()(创建时调用)、surfaceChanged()(改变时调用)、surfaceDestroyed()(销毁时调用)、run()方法,在run()方法中写我们子线程中执行的绘图逻辑即可

2.初始化surfaceView

这一步我们主要是定义成员变量以备后面绘图时使用,然后初始化这三个成员变量并且注册对应的回调方法。

3.使用SurfaceView

这一步又可以分为3步来完成:

(1) 通过lockCanvas()方法获得Canvas对象

(2) 在子线程中使用Canvas对象进行绘制

(3) 使用unlockCanvasAndPost()方法将画布内容进行提交

注意: lockCanvas() 方法获得的Canvas对象仍然是上次绘制的对象,由于我们是不断进行绘制,但是每次得到的Canvas对象都是第一次创建的Canvas对象。

21、序列化的作用,以及Android两种序列化的区别

java序列化主要有2个作用:

对象持久化,对象生存在内存中,想把一个对象持久化到磁盘,必须已某种方式来组织这个对象包含的信息,这种方式就是序列化;

远程网络通信,内存中的对象不能直接进行网络传输,发送端把对象序列化成网络可传输的字节流,接收端再把字节流还原成对象。

Serializable 和Parcelable 的区别:

在Android上应该尽量采用Parcelable,它效率更高。Parcelabe代码比Serializable多一些。但速度高十倍以上。

Serializable只需要对某个类以及它的属性实现Serializable接口即可,无需实现方法。缺点是使用的反射,序列化的过程较慢,这种机制会在序列化的时候创建许多的临时对象。容易触发GC。

Parcable方法实现的原理是将一根完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能。

22、差值器、估值器

https://www.jianshu.com/p/915471529d3c

23、Android中数据存储方式

  • 使用SharedPreferences存储数据;  
  • 文件存储数据;
  • SQLite数据库存储数据;
  • 使用ContentProvider存储数据;
  • 网络存储数据;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值