Android--面试中遇到的问题总结(一)

简介: 版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/56479430 一、handl...
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/56479430

一、handler

一、主要涉及到的类有Handler、Thread、Message、Looper、MessageQueue;

二、.异步消息处理机制的作用主要有刷新UI和线程间通信

三、    .Handler主要是发送消息(sendMessage),处理消息(handlerMessage)的类;

             Message就是在线程之间传递的消息,它可以携带少量信息,在线程间进行信息交换;

             Looper主要是管理消息队列的,一旦调用Loop()方法之后就会进入到一个无线循环中去,每当发现 MessageQueue 中存在一条消息,就会将其取出,并传递到 handleMessage()方法当中,每个线程中也 只会 有一个Looper对象;

             MessageQueue消息队列用来存储handler传过来的消息的,每个线程只有一个消息队列。

二、手机屏幕适配

1.布局文件适配:多用match_parent、wrap_content,weight;多套布局文件

2.图片资源适配:根据手机屏幕分辨率的不同,制作几套图片资源;使用自动拉伸位图:Nine-Patch的图片类

3.布局控件尺寸适配:尽量使用密度无关像素 dp 或独立比例像素 sp 单位指定尺寸

4.自定义控件,利用代码根据屏幕的大小动态设置界面的显示大小

使用 “wrap_content”,系统就会将视图的宽度或高度设置成所需的最小尺寸以适应视图中的内容,而 “match_parent”(在低于 API 级别 8 的级别中称为 “fill_parent”)则会展开组件以匹配其父视图的尺寸。

如果使用 “wrap_content” 和 “match_parent” 尺寸值而不是硬编码的尺寸,视图就会相应地仅使用自身所需的空间或展开以填满可用空间。 此方法可让布局正确适应各种屏幕尺寸和屏幕方向。

weight是线性布局的一个独特的属性,我们可以使用这个属性来按照比例对界面进行分配,完成一些特殊的需求。

三、内存泄漏的原因

1.资源对象没关闭造成的内存泄漏:资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄漏。因为有些资源性对象,比如 SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null.在我们的程序退出时一定要确保我们的资源性对象已经关闭。

2.构造Adapter时,没有使用缓存的convertView:public View getView(int position, ViewconvertView, ViewGroup parent)

来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此可以看出,如果我们不去使用 convertView,而是每次都在getView()中重新实例化一个View对象的话。

3.Bitmap对象不在使用时调用recycle()释放内存

4.试着使用关于application的context来替代和activity相关的context:有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他自己的范围之外。使用Application context。这个context的生存周期和你的应用的生存周期一样长,而不是取决于activity的生存周期。如果你想保持一个长期生存的对象,并且这个对象需要一个context,记得使用application对象。你可以通过调用 Context.getApplicationContext() or Activity.getApplication()来获得。

5.注册没取消造成的内存泄漏

一些Android程序可能引用我们的Anroid程序的对象(比如注册机制)。即使我们的Android程序已经结束了,但是别的引用程序仍然还有对我们的Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。调用registerReceiver后未调用unregisterReceiver。

比如:假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个 PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。

但是如果在释放 LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process 进程挂掉。

6.集合中对象没清理造成的内存泄漏

我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。

四、Android中的动画

Android中动画分别帧动画、补间动画和属性动画(Android 3.0以后的)

帧动画

帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。在有些代码中,我们还会看到android:oneshot=”false” ,这个oneshot 的含义就是动画执行一次(true)还是循环执行多次。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/a_0"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_1"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_2"
        android:duration="100" />
</animation-list>

补间动画

补间动画又可以分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。 
补间动画的实现,一般会采用xml 文件的形式;代码会更容易书写和阅读,同时也更容易复用。Interpolator 主要作用是可以控制动画的变化速率 ,就是动画进行的快慢节奏。pivot 决定了当前动画执行的参考位置

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

属性动画

属性动画,顾名思义它是对于对象属性的动画。因此,所有补间动画的内容,都可以通过属性动画实现。属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。

五、Android中常用的布局

常用的布局:

FrameLayout(帧布局):所有东西依次都放在左上角,会重叠
LinearLayout(线性布局):按照水平和垂直进行数据展示
RelativeLayout(相对布局):以某一个元素为参照物,来定位的布局方式

不常用的布局:

TableLayout(表格布局): 每一个TableLayout里面有表格行TableRow,TableRow里面可以具体定义每一个元素(Android TV上使用)
AbsoluteLayout(绝对布局):用X,Y坐标来指定元素的位置,元素多就不适用。(机顶盒上使用)

新增布局:

PercentRelativeLayout(百分比相对布局)可以通过百分比控制控件的大小。
PercentFrameLayout(百分比帧布局)可以通过百分比控制控件的大小。
六、Android数据存储

  1. 使用SharedPreferences存储数据;它是Android提供的用来存储一些简单配置信息的一种机制,采用了XML格式将数据存储到设备中。只能在同一个包内使用,不能在不同的包之间使用。
  2. 文件存储数据;文件存储方式是一种较常用的方法,在Android中读取/写入文件的方法,与Java中实现I/O的程序是完全一样的,提供了openFileInput()和openFileOutput()方法来读取设备上的文件。
  3. SQLite数据库存储数据;SQLite是Android所带的一个标准的数据库,它支持SQL语句,它是一个轻量级的嵌入式数据库。
  4. 使用ContentProvider存储数据;主要用于应用程序之间进行数据交换,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。
  5. 网络存储数据;通过网络上提供给我们的存储空间来上传(存储)和下载(获取)我们存储在网络空间中的数据信息。
七、Android中的ANR

ANR的全称application not responding 应用程序未响应。

在android中Activity的最长执行时间是5秒。
BroadcastReceiver的最长执行时间则是10秒。
Service的最长执行时间则是20秒。

超出执行时间就会产生ANR。注意:ANR是系统抛出的异常,程序是捕捉不了这个异常的。

解决方法: 
1. 运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法 (如onCreate()和onResume())里尽可能少的去做创建操作。(可以采用重新开启子线程的方式,然后使用Handler+Message 的方式做一些操作,比如更新主线程中的ui等) 
2. 应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。但不再是在子线程里做这些任务(因为 BroadcastReceiver的生命周期短),替代的是,如果响应Intent广播需要执行一个耗时的动作的话,应用程序应该启动一个 Service。

八、 AsyncTask

AsyncTask的三个泛型参数说明

1.第一个参数:传入doInBackground()方法的参数类型

2.第二个参数:传入onProgressUpdate()方法的参数类型

3.第三个参数:传入onPostExecute()方法的参数类型,也是doInBackground()方法返回的类型

运行在主线程的方法:

 
 
onPostExecute()
onPreExecute()
onProgressUpdate(Progress...)

运行在子线程的方法:

doInBackground()

控制AsyncTask停止的方法:

cancel(boolean mayInterruptIfRunning)

AsyncTask的执行分为四个步骤

1.继承AsyncTask。

2.实现AsyncTask中定义的下面一个或几个方法onPreExecute()、doInBackground(Params…)、onProgressUpdate(Progress…)、onPostExecute(Result)。

3.调用execute方法必须在UI thread中调用。

4.该task只能被执行一次,否则多次调用时将会出现异常,取消任务可调用cancel。

九、Android进程间的通讯

1.activity

Activity的跨进程访问与进程内访问略有不同。虽然它们都需要Intent对象,但跨进程访问并不需要指定Context对象和Activity的 Class对象,而需要指定的是要访问的Activity所对应的Action(一个字符串)。有些Activity还需要指定一个Uri(通过 Intent构造方法的第2个参数指定)。

       在android系统中有很多应用程序提供了可以跨进程访问的Activity,例如,下面的代码可以直接调用拨打电话的Activity。

  1. Intent callIntent = new  Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678" );  
  2. startActivity(callIntent);
2. Content Provider  

      Android应用程序可以使用文件或SqlLite数据库来存储数据。Content Provider提供了一种在多个应用程序之间数据共享的方式(跨进程共享数据)。应用程序可以利用Content Provider完成下面的工作

1. 查询数据

2. 修改数据

3. 添加数据

4. 删除数据


3.广播(Broadcast) 
      广播是一种被动跨进程通讯的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。
在应用程序中发送广播比较简单。只需要调用sendBroadcast方法即可。该方法需要一个Intent对象。通过Intent对象可以发送需要广播的数据。

4.Service

1.利用AIDL Service实现跨进程通信

        这是我个人比较推崇的方式,因为它相比Broadcast而言,虽然实现上稍微麻烦了一点,但是它的优势就是不会像广播那样在手机中的广播较多时会有明显的时延,甚至有广播发送不成功的情况出现。 

       注意普通的Service并不能实现跨进程操作,实际上普通的Service和它所在的应用处于同一个进程中,而且它也不会专门开一条新的线程,因此如果在普通的Service中实现在耗时的任务,需要新开线程。

       要实现跨进程通信,需要借助AIDL(Android Interface Definition Language)。Android中的跨进程服务其实是采用C/S的架构,因而AIDL的目的就是实现通信接口。




目录
相关文章
|
11天前
|
ARouter IDE 开发工具
Android面试题之App的启动流程和启动速度优化
App启动流程概括: 当用户点击App图标,Launcher通过Binder IPC请求system_server启动Activity。system_server指示Zygote fork新进程,接着App进程向system_server申请启动Activity。经过Binder通信,Activity创建并回调生命周期方法。启动状态分为冷启动、温启动和热启动,其中冷启动耗时最长。优化技巧包括异步初始化、避免主线程I/O、类加载优化和简化布局。
28 3
Android面试题之App的启动流程和启动速度优化
|
12天前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
18 3
Android面试题之Java 泛型和Kotlin泛型
|
5天前
|
缓存 网络协议 安全
Android网络面试题之Http基础和Http1.0的特点
**HTTP基础:GET和POST关键差异在于参数传递方式(GET在URL,POST在请求体),安全性(POST更安全),数据大小限制(POST无限制,GET有限制),速度(GET较快)及用途(GET用于获取,POST用于提交)。面试中常强调POST的安全性、数据量、数据类型支持及速度。HTTP 1.0引入了POST和HEAD方法,支持多种数据格式和缓存,但每个请求需新建TCP连接。**
20 5
|
2天前
|
SQL XML Java
Android 这 13 道 ContentProvider 面试题,你都会了吗?
Android 这 13 道 ContentProvider 面试题,你都会了吗?
|
2天前
|
安全 Android开发 Kotlin
Android面试题之Kotlin协程并发问题和互斥锁
Kotlin的协程提供轻量级并发解决方案,如`kotlinx.coroutines`库。`Mutex`用于同步,确保单个协程访问共享资源。示例展示了`withLock()`、`lock()`、`unlock()`和`tryLock()`的用法,这些方法帮助在协程中实现线程安全,防止数据竞争。
9 1
|
3天前
|
安全 网络协议 算法
Android网络基础面试题之HTTPS的工作流程和原理
HTTPS简述 HTTPS基于TCP 443端口,通过CA证书确保服务器身份,使用DH算法协商对称密钥进行加密通信。流程包括TCP握手、证书验证(公钥解密,哈希对比)和数据加密传输(随机数加密,预主密钥,对称加密)。特点是安全但慢,易受特定攻击,且依赖可信的CA。每次请求可能复用Session ID以减少握手。
13 2
|
9天前
|
缓存 JSON 网络协议
Android面试题:App性能优化之电量优化和网络优化
这篇文章讨论了Android应用的电量和网络优化。电量优化涉及Doze和Standby模式,其中应用可能需要通过用户白名单或电池广播来适应限制。Battery Historian和Android Studio的Energy Profile是电量分析工具。建议减少不必要的操作,延迟非关键任务,合并网络请求。网络优化包括HTTPDNS减少DNS解析延迟,Keep-Alive复用连接,HTTP/2实现多路复用,以及使用protobuf和gzip压缩数据。其他策略如使用WebP图像格式,按网络质量提供不同分辨率的图片,以及启用HTTP缓存也是有效手段。
30 9
|
4天前
|
缓存 网络协议 Android开发
Android网络面试题之Http1.1和Http2.0
HTTP/1.1 引入持久连接和管道机制提升效率,支持分块传输编码和更多请求方式如PUT、PATCH。Host字段指定服务器域名,RANGE用于断点续传。HTTP/2变为二进制协议,实现多工处理,头信息压缩和服务器推送,减少延迟并优化资源加载。HTTP不断发展,从早期的简单传输到后来的高效交互。
17 0
Android网络面试题之Http1.1和Http2.0
|
13天前
|
网络协议 算法 安全
小米安卓春招面试一面
小米安卓春招面试一面
23 3
|
8天前
|
Java Android开发 Kotlin
Android面试题:App性能优化之Java和Kotlin常见的数据结构
Java数据结构摘要:ArrayList基于数组,适合查找和修改;LinkedList适合插入删除;HashMap1.8后用数组+链表/红黑树,初始化时预估容量可避免扩容。SparseArray优化查找,ArrayMap减少冲突。 Kotlin优化摘要:Kotlin的List用`listOf/mutableListOf`,Map用`mapOf/mutableMapOf`,支持操作符重载和扩展函数。序列提供懒加载,解构用于遍历Map,扩展函数默认参数增强灵活性。
14 0