目录
- 1. JNI和NDK
- 1.谈谈你对JNI和NDK的理解
- 2.简要的JNI调用过程:
- 2. 线程、同步、异步
- 1.Java创建线程的方式有几种?start()方法和 run()方法的区别
- 2.Handler 机制和原理
- 3.为什么在子线程中创建Handler会抛异常?
- 4.Android中的ANR的解决方法
- 5.intentservice有什么优点?
- 6.okhttp异步请求流程
- 7.Okhttp的同步请求
- 3. UI
- 1.谈谈你对 Bitmap 的理解,什么时候应该手动调用 bitmaprecycle():
- 2.Android布局的五个常见类型:
- 4. 组件
- **1.Android四大组件是指Activity、Service、BroadcastReceiver和ContentProvider**。
- 5. 四大组件详解
- 1. **activity**
- **2 .service**
- **3 .content provider**
- **4 .broadcast receiver**
- 如果后台的activity由于某种原因被系统回收了,如何在被系统回收之前保存当前状态?
- 6. 机制
- 1.view的事件分发机制
- 7. 性能
- 1.GC是什么,为什么要有GC
- 8. 数据库
- 1.SQLite 数据库升级——新增字段处理
1. JNI和NDK
1.谈谈你对JNI和NDK的理解
答:JNI(Java Native Interface)是Java提供的一种机制,用于实现Java与其他编程语言(如C、C++)之间的交互。它允许Java代码调用本地代码(Native Code)并与其进行数据交换。
NDK(Native Development Kit)是Android提供的一个工具集,用于在Android应用中使用本地代码。它包含了一系列的工具和库,可以将C、C++代码编译成与特定平台相关的本地库文件(例如.so文件),然后通过JNI将这些本地库文件嵌入到Android应用中。
JNI和NDK的关系是,JNI提供了Java与本地代码交互的机制,而NDK则提供了将本地代码集成到Android应用中的工具和库。通过JNI和NDK,开发者可以在Android应用中使用C、C++等本地语言编写高性能、底层的功能模块,比如图像处理、音频处理、加密算法等。
使用JNI和NDK可以带来以下优势:
1.性能优化:某些计算密集型任务,使用本地代码可以提高执行效率。
2.跨平台开发:通过使用本地代码,可以在不同平台上共享代码和库。
3.重用现有代码:如果已经有了C、C++等语言的现有代码,可以通过JNI和NDK将其集成到Android应用中,避免重复开发。
需要注意的是,在使用JNI和NDK时,需要谨慎处理内存管理、类型转换和异常处理等问题,以确保代码的正确性和稳定性。
2.简要的JNI调用过程:
1、**编写本地代码:**首先,需要编写包含所需功能的本地代码,通常是用C或C++编写。这些本地代码将被编译成共享库(.so文件)。
2、创建JNI接口:在Java代码中,需要声明与本地代码对应的JNI接口。这些接口方法将与本地代码中的函数进行绑定,以便在Java中调用。
3、生成头文件:使用Java Development Kit(JDK)中的工具javah,生成包含JNI接口方法定义的头文件。
4、实现JNI接口:在本地代码中,需要实现JNI接口中声明的方法。这些方法将提供与Java代码之间的桥梁,使得Java可以调用本地代码。
5、编译本地代码:使用C/C++编译器将本地代码编译成共享库(.so文件)。
6、将共享库加载到应用程序:在Android应用程序中,可以使用System.loadLibrary()方法加载共享库。
7、调用JNI方法:在Java代码中,通过调用JNI接口中声明的方法来调用本地代码。可以使用native关键字标记这些方法。
8、运行应用程序:在应用程序运行时,当Java代码调用JNI方法时,将触发与本地代码的交互,完成相应的功能操作。
需要注意的是,JNI调用涉及到本地代码的编写和编译,因此需要对C/C++有一定的了解。此外,在JNI调用过程中,需要注意内存管理和数据类型转换等问题,以确保安全性和正确性。
JNI调用过程包括编写本地代码、创建JNI接口、生成头文件、实现JNI接口、编译本地代码、加载共享库、调用JNI方法等步骤,通过这些步骤可以实现Java代码与本地代码之间的交互。
2. 线程、同步、异步
1.Java创建线程的方式有几种?start()方法和 run()方法的区别
答:在Java中,有两种主要的方式可以创建线程:
1.继承Thread类:通过继承Thread类并重写其run()方法来创建线程。首先,创建一个继承自Thread的子类,并在子类中实现run()方法来定义线程的具体逻辑。然后,通过创建子类的实例对象,并调用其start()方法来启动线程。
2.实现Runnable接口:通过实现Runnable接口来创建线程。首先,创建一个实现了Runnable接口的类,并在该类中实现run()方法。然后,创建Thread类的实例对象,将实现了Runnable接口的类的实例作为参数传递给Thread的构造函数。最后,调用Thread对象的start()方法来启动线程。
区别:
- 使用继承Thread类的方式,线程的逻辑直接写在子类中的run()方法中,但这样会限制了子类的继承关系。
- 使用实现Runnable接口的方式,线程的逻辑在实现了Runnable接口的类中定义,可以更灵活地共享代码和资源,并且避免了单继承的限制。
关于start()方法和run()方法的区别:
- start()方法用于启动线程并异步执行线程的逻辑。调用start()方法后,系统会为线程分配资源并调用线程的run()方法。
- run()方法是线程的入口点,可以将线程的具体逻辑在run()方法中实现。但直接调用run()方法并不会启动新的线程,而是在当前线程中同步执行run()方法的代码块。
总结来说,Java创建线程的方式有继承Thread类和实现Runnable接口。start()方法用于启动线程并异步执行线程的逻辑,而run()方法是线程的入口点,在调用start()方法后由系统自动调用。
2.Handler 机制和原理
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。
基础概念
- UI线程
主线程 ActivityThread ,主线程也是Ui线程,应用启动的时候会启动一个ui线程 - Handler
负责发送消息和处理消息。 - Looper
负责消息循环,循环取出 MessageQueue 里面的 Message,并交给相应的 Handler 进行处理。 - MessageQueue
消息队列,用来存放通过Hangdler 发送的消息,按照先进先出的顺序取出消息,内部使用的是单链表结构(