Android 面试:常见问题总结,真香警告

}

六、JNI 调用中考虑的问题

1. java和c是如何互通的?
  • 不能互通的原因主要是 数据类型 的问题。

  • 但jni解决了这个问题,例如c文件中的 jstring 数据类型就是 java传入的String对象 ,经过jni函数的转化就能成为c的 char*

对应数据类型关系如下表:

| Java 类型 | 本地c类型 | 说明 |

| — | — | — |

| boolean | jboolean | 无符号,8 位 |

| byte | jbyte | 无符号,8 位 |

| char | jchar | 无符号,16 位 |

| short | jshort | 有符号,16 位 |

| int | jint | 有符号,32 位 |

| long | jlong | 有符号,64 位 |

| float | jfloat | 32 位 |

| double | jdouble | 64 位 |

| void | void | N/A |

2. 如何将java传入的String参数转换为c的char*,然后使用?
  • java 传入的String参数,在c文件中被jni转换为jstring的数据类型

  • 在c文件中声明 char* test,然后

test = (char*)(*env)->GetStringUTFChars(env, jstring, NULL);

  • 注意:test使用完后,通知虚拟机平台相关代码无需再访问:

(*env)->ReleaseStringUTFChars(env, jstring, test);

3. 将c中获取的一个char*的buffer传递给java?
  1. 这个char*如果是一般的字符串的话,作为 string 传回去就可以了。

  2. 如果是含有’/0’的buffer,最好作为 bytearray 传出,

因为可以制定copy的length,如果copy到string,可能到’/0’就截断了。

有两种方式传递得到的数据:

  1. 在jni中直接new一个byte数组,然后调用函数(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);将buffer的值copy到bytearray中,函数直接return bytearray就可以了。

  2. return 错误号,数据作为参数传出,但是java的基本数据类型是传值,对象是传递的引用,所以将这个需要传出的byte数组用某个类包一下,如下:

class RetObj

{

public byte[] bytearray;

}

这个对象作为函数的参数retobj传出,通过如下函数将retobj中的byte数组赋值便于传出。代码如下:

jclass cls;

jfieldID fid;

jbyteArray bytearray;

bytearray = (*env)->NewByteArray(env,len);

(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer);

cls = (*env)->GetObjectClass(env, retobj);

fid = (*env)->GetFieldID(env, cls, “retbytes”, “[B”]);

(*env)->SetObjectField(env, retobj, fid, bytearray);

4. 不知道占用多少空间的buffer,如何传递出去呢?
  • 在 jni 的c文件中new出空间,传递出去。

  • java的数据不初始化,指向传递出去的空间即可。

七、Android中的动画有哪几类,它们的特点和区别是什么?

  1. Tween动画:使视图组件移动、放大、缩小以及产生透明度的变化

给出两个关键帧,通过一些算法将给定属性值在给定的时间内在两个关键帧间渐变。

  1. Frame动画:传统的动画方法,通过顺序的播放排列好的图片来实现。

  2. 属性动画:真正的改变属性。

八、Handler机制的原理

Andriod 提供了 Handler 和 Looper 来满足线程间的通信。

  1. Looper : 一个线程可以产生一个Looper对象,管理此线程里的MessageQueue(消息队列)。

  2. Handler : 构造Handler对象来与Looper沟通,

如push新消息到MessageQueue里,或者接收Looper从MessageQueue取出的消息。

  1. MessageQueue : 消息队列,用来存放线程放入的消息。

  2. 线程 : UI线程通常就是主线程,程序启动时会替它建立一个MessageQueue。

九、mvc模式的原理以及在Android中的运用

松耦合,组件的重用。

  1. view:视图层,一般采用xml文件进行界面的描述,也可以使用javascript+html等的方式作为view层。

  2. controller:一般指Acitvity,所以不要在acitivity中数据操作等耗时操作的代码,要通过activity交割model业务逻辑层处理。

  3. model:对数据库的操作、对网络等的操作都应该在model里面处理,当然对业务计算等操作也是必须放在的该层的。

十、介绍下Android的数据存储方式

  1. 使用SharedPreferences存储数据;

  2. 文件存储数据;

  3. SQLite数据库存储数据;

  4. 使用ContentProvider存储数据;

  5. 网络存储数据;

Android 中的数据存储都是私有的,其他应用程序都是无法访问的,除非通过ContentResolver获取其他程序共享的数据。

十一、介绍下ContentProvider是如何实现数据共享的

ContentProvider:为存储和获取数据提供统一的接口,可以在不同的应用程序之间共享数据。

无论数据的来源是什么,ContentProvider都会认为是一种表,然后把数据组织成表格。

  1. 定义一个继承ContentProvider的类

  2. 实现ContentProvider的所有方法 (query、insert、update、delete、getType、onCreate)

  3. 在AndroidMinifest.xml中进行声明

十二、如何启用Service,如何停用Service

  1. 通过调用Context.startService()启动,调用Context.stopService()结束,

startService()可以传递参数给Service.

  1. 第二种方式是通过调用Context.bindService()启动,调用Context.unbindservice()结束

这种方式可以通过ServiceConnection访问Service。

  • 在Service每一次的开启关闭过程中,只有onStartCommand()可被多次调用(通过多次startService调用),

  • 其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

十三、注册广播接收器有几种方式,这些方式有何优缺点?

Android中,不同 进程之间 传递信息要用到广播。

方式1. 在Manifest.xml中注册广播

是一种比较推荐的方法,不需要手动注销广播。

(如果广播未注销,程序退出时可能会出错),范例代码:

<receiver android:name = “.MyBroadcastReceiver”

上面两个android:name分别是 广播名广播动作名

如果要自己发送一个广播,在代码中为:

Intent i = new Intent(“com.zhuanghongji.broadcastreceiver.test”);

sendBroadcast(i);

广播就发出去了,然后是接收。

新建一个类,继承至BroadcastReceiver,也可以建一个BroadcastReceiver的实例,然后得写onReceive()方法,实现如下:

protected BroadcastReceiver mEvtReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (action.equals(“com.zhuanghongji.broadcastreceiver.test”)) {

//Do something

}

}

};

方式2. 接在代码中实现,但需要手动注册注销

通过IntentFilter设置action,使用 registerReceiver() 方法进行注册。

IntentFilter filter = new IntentFilter();

filter.addAction(“com.zhuanghongji.broadcastreceiver.test”);

registerReceiver(mEvtReceiver, filter);

// 这时注册了一个recevier ,名为mEvtReceiver,

// 然后同样用上面的方法以重写onReceiver,

// 最后在程序的onDestroy中要注销广播,实现如下:

@Override

public void onDestroy() {

super.onDestroy();

unregisterReceiver(mPlayerEvtReceiver);

}

十四、请谈谈Android引入广播机制的用意

1. 解答
  • Android系统中的广播是广泛用于 应用程序之间通信 的一种手段。

类似于事件处理机制,不同的地方就是广播的处理是系统级别的事件处理过程(一般事件处理是控件级别的)。在此过程中仍然是离不开Intent对象,理解广播事件的处理过程,灵活运用广播处理机制,在关键之处往往能实现特别的效果。

  • 在Android 中如果要发送一个广播必须使用sendBroadCast(Intent intent) 向系统发送对其感兴趣的广播接收器中。

  • 使用广播必须要有一个intent 对象必设置其action动作对象使用广播必须在配置文件中显式的指明该广播对象。

  • 每次接收广播 都会重新生成一个接收广播的对象,在 BroadCast中 尽量不要处理太多逻辑问题,建议复杂的逻辑交给Activity 或者 Service 去处理.

补充:

2. BroadcastReceiver的生命周期:

这里写图片描述

大意为:如果一个广播处理完onReceive 那么系统将认定此对象将不再是一个活动的对象,也就会finished掉它。

3. 如何在一个广播接收器中处理多个动作呢?
  • 同样的你必须在 Intent-filter 里面注册该动作,可以是系统的广播动作也可以是自己需要的广播。

  • 之后你之需要在onReceive 方法中,通过 intent.getAction() 判断传进来的动作即可做出不同的处理,不同的动作。

小结:

  • 在Android 中如果要发送一个广播必须使用sendBroadCast 向系统发送对其感兴趣的广播接收器中。

  • 使用广播必须要有一个intent 对象必设置其action动作对象

  • 使用广播必须在配置文件中显式的指明该广播对象

  • 每次接收广播都会重新生成一个接收广播的对象

  • 在BroadCast 中尽量不要处理太多逻辑问题,建议复杂的逻辑交给Activity 或者 Service 去处理

十五、单线程模型中Message,Handler,MessageQueue,Looper之间的关系

  • Message:Handler接收和处理的消息对象。

  • Handler:发送和处理消息。

  • MessageQueue:消息队列,以”先进先出”的方式管理Message。

  • Looper:读取MessageQueue的消息,然后把消息交给”发送该消息的Handler”进行处理。

详细内容可以看我的另一篇总结:Android 总结:Message,MessageQueue,Looper,Handler 消息机制

十六、AIDL 如何工作?能处理哪些类型的数据?

1. 概述

AIDL:Android Interface Definition Language(安卓接口描述语言)

  • 编译器可以通过 aidl文件 生成一段代码,通过预先定义的接口达到 两个进程内部通信,进程间跨界对象访问的目的。

  • AIDL的IPC机制是基于接口的,是轻量级的。使用代理类在客户端和实现层间传递值.。

2. 使用AIDL, 需要完成2件事情
  1. 引入AIDL的相关类

  2. 调用aidl产生的class

理论上, 参数可以传递基本数据类型和String, 还有就是Bundle的派生类。

3. 具体实现步骤
  1. 创建AIDL文件,

在这个文件里面定义接口, 该接口定义了可供客户端访问的方法和属性

  1. 编译AIDL文件

用Ant的话, 可能需要手动, 使用Eclipse plugin的话,可以根据adil文件自动生产java文件并编译, 不需要人为介入。

  1. 在Java文件中, 实现AIDL中定义的接口

编译器会根据AIDL接口, 产生一个JAVA接口。这个接口有一个名为Stub的内部抽象类,它继承扩展了接口并实现了远程调用需要的几个方法。

  1. 向客户端提供接口 ITaskBinder

如果写的是service,扩展该Service并重载 onBind () 方法来返回一个实现上述接口的类的实例。

  1. 在服务器端回调客户端的函数

前提是当客户端获取的IBinder接口的时候,要去注册回调函数, 只有这样, 服务器端才知道该调用那些函数。

4. AIDL语法和支持的数据类型

AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。

由于远程调用的需要, 这些参数和返回值并不是任何类型。

下面是些AIDL支持的数据类型:

  1. 不需要import声明的简单Java编程语言类型(int,boolean等)

  2. String, CharSequence 不需要特殊声明

  3. List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型.

5. 实现接口时有几个原则
  1. 抛出的异常不要返回给调用者. 跨进程抛异常处理是不可取的.

  2. IPC调用是同步的。

如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,你应该避免在Activity的主线程中调用。

也就是说IPC调用会挂起应用程序导致界面失去响应。

这种情况应该考虑单起一个线程来处理.

  1. 不能在AIDL接口中声明静态属性。
6. IPC的调用步骤
  1. 声明一个接口类型的变量,该接口类型在.aidl文件中定义。

  2. 实现ServiceConnection。

  3. 调用ApplicationContext.bindService(),并在ServiceConnection实现中进行传递.

  4. 在ServiceConnection.onServiceConnected()实现中,

你会接收一个IBinder实例(被调用的Service).

调用YourInterfaceName.Stub.asInterface((IBinder)service)将参数转换为YourInterface类型。

  1. 调用接口中定义的方法。 你总要检测到DeadObjectException异常,该异常在连接断开时被抛出。它只会被远程方法抛出。

  2. 断开连接,调用接口实例中的ApplicationContext.unbindService()

十七、什么是ANR?如何避免它?

1. 什么是ANR?
  1. ANR:Application Not Responding
  • 在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。

  • Android应用程序完全运行在一个独立的线程中当出现下列情况时,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。

  • 因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intent broadcast)。

  1. 当出现下列情况时,Android就会显示ANR对话框了:
  • 对输入事件(如按键、触摸屏事件)的响应超过5秒

  • 意向接受器(intentReceiver)超过10秒钟仍未执行完毕

2. 如何避免它?
  • 潜在的比较耗时的操作,如访问网络和数据库;

  • 或者是开销很大的计算,比如改变位图的大小;

  • 需要在一个单独的子线程中完成 (或者是使用异步请求,如数据库操作)

主线程为子线程提供了 Handler,让子线程在即将结束的时候调用它与主线程通信。

十八、谈谈你对Intent的理解

一个intent是一个Intent对象,它保存了消息的内容。

  1. 对于activity和service来说,它指定了请求的操作名称和待操作数据的URI

  2. Intent对象可以显式的指定一个目标组件。

  • 如果这样的话,android会找到这个组件 (基于manifest文件中的声明)并激活它。

  • 但如果一个目标不是显式指定的,android必须找到响应intent的最佳组件。

它是通过将Intent对象和目标的intent filter相比较来完成这一工作的。一个组件的intent filter告诉android该组件能处理的intent。intent filter也是在manifest文件中声明的。

十九、如何将SQLite数据库(dictionary.db文件)与apk文件一起发布?

总结

**其实上面说了这么多,钱是永远赚不完的,在这个知识付费的时代,知识技能提升才是是根本!我作为一名8年的高级工程师,知识技能已经学习的差不多。**在看这篇文章的可能有刚刚入门,刚刚开始工作,或者大佬级人物。

像刚刚开始学Android开发小白想要快速提升自己,最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以这里分享一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

这么重要的事情说三遍啦!点赞+点赞+点赞 免费分享所有学习秘籍!
直达领取链接:点击链接免费领取【Android高级架构师

【Android高级架构师系统学习资料】高级架构师进阶必备——设计思想解读开源框架

第一章、热修复设计
第二章、插件化框架设计
第三章、组件化框架设计
第四章、图片加载框架
第五章、网络访问框架设计
第六章、RXJava 响应式编程框架设计
第七章、IOC 架构设计
第八章、Android 架构组件 Jetpack

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

五章、网络访问框架设计
第六章、RXJava 响应式编程框架设计
第七章、IOC 架构设计
第八章、Android 架构组件 Jetpack

[外链图片转存中…(img-nc640Pch-1710959267103)]

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-jxtXX8hN-1710959267104)]
[外链图片转存中…(img-XQVEiPJR-1710959267104)]
[外链图片转存中…(img-hoAXXZI9-1710959267105)]
[外链图片转存中…(img-SCKimFxz-1710959267105)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-an8bGGVl-1710959267105)]

  • 21
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值