1 Android中屏幕密度的核算办法
在 Android 中,屏幕密度的核算办法是经过比较屏幕上每英寸(Inch)的物理像素数目来确认的。屏幕密度是指屏幕上每英寸的物理像素数目(一般表明为 DPI 或 PPI)。
详细而言,Android 中的屏幕密度核算办法如下:
屏幕密度(dpi)= √(横向像素数 + 纵向像素数)/ 屏幕对角线英寸数
例如,关于 5.5 英寸、750*1334 像素的屏幕,核算屏幕密度的公式如下:
屏幕密度(dpi)= √(750 + 1334)/ 5.5 ≈ 326 dpi
屏幕密度一般被分为以下几种类型:
-
- ldpi(低密度):表明屏幕密度为 120 dpi;
-
- mdpi(中密度):表明屏幕密度为 160 dpi;
-
- hdpi(高密度):表明屏幕密度为 240 dpi;
-
- xhdpi(超高密度):表明屏幕密度为 320 dpi;
-
- xxhdpi(超超高密度):表明屏幕密度为 480 dpi;
-
- xxxhdpi(超超超高密度):表明屏幕密度为 640 dpi。
在开发 Android 运用时,需求依据屏幕密度的不同,供给不同密度的资源文件,以确保运用在不同类型的设备上都能够正常显现。
一般,将资源文件分别放置在不同密度的目录下,例如 res/drawable-ldpi、res/drawable-mdpi、res/drawable-hdpi 等。当运用在不同的设备上运转时,体系会主动依据设备的屏幕密度,从相应的目录中加载对应密度的资源文件。
2 Android中dp与px的转化
在 Android 开发中,运用 dp 和 px 是常见的尺度单位,运用 dp 能够使得运用在不同屏幕巨细和密度的设备上有更好的适应性,运用 px 则是直接运用实践的像素数目。
下面介绍一下 dp 与 px 之间的转化:
2.1 dp 转 px
dp 和 px 的转化需求考虑设备的屏幕密度,一般来说,设备的屏幕密度越高,则 dp 转化成的 px 像素数目越多。
一般状况下,咱们能够运用 Android SDK 供给的一个常量进行转化,这个常量为 density,是指当时设备的屏幕密度。例如,将 dp 值转化为 px 的办法如下:
public int dp2px(int dpValue) {
float scale = getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
在这个办法中,咱们首要获取了当时设备的屏幕密度,然后将 dp 值乘以 density 值,最终加上 0.5f 并强制转化为 int 类型,即可得到转化后的像素值。
2.2 px 转 dp
假如想将 px 像素数目转化为相应的 dp 值,则需求依照以下公式进行核算:
dp = px / density
同样地,咱们能够编写一个办法进行转化:
public int px2dp(int pxValue) {
float scale = getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
在这个办法中,咱们首要获取了当时设备的屏幕密度,然后将像素数目除以 density 值,最终加上 0.5f 并强制转化为 int 类型,即可得到转化后的 dp 值。
需求留意的是,在进行 dp 和 px 的转化时,需求运用 context.getResources().getDisplayMetrics().density 来获取当时设备的屏幕密度值,而不能运用 DisplayMetrics 类的 density 特点,因为 DisplayMetrics 类的 density 特点是固定的,而不是依据当时设备的屏幕密度而变化的。
3 Android中Activity的发动形式
Android 中的 Activity 发动形式非常重要,它能够影响 Activity 的生命周期和使命栈的运作。不同的发动形式适用于不同的场景,下面给出常见的发动形式以及运用场景:
-
- Standard(标准形式) 标准形式是 Activity 的默许发动形式。每次发动 Activity 都会创立一个新的实例,不论这个 Activity 是否现已存在。适用于独立运转的 Activity,不需求特殊的发动形式。
-
- SingleTop(栈顶复用形式) singleTop 形式表明假如当时 Activity 在栈顶,则直接复用该 Activity,不会创立新的实例。假如不在栈顶,则创立新的实例,并参加使命栈的栈顶。适用于需求及时更新数据的状况,比方谈天界面、告诉界面等。
-
- SingleTask(栈内复用形式) singleTask 形式表明假如当时使命栈中不存在该 Activity,则创立新的实例,并放在栈底。假如存在,则将该 Activity 上面的一切 Activity 弹出栈,使其处于栈顶方位。适用于需求保持唯一性的 Activity,比方主界面、登录界面等。
-
- SingleInstance(单实例形式) singleInstance 形式表明 Activity 是大局的,独立于其他使命栈。在该形式下,体系会创立一个新的使命栈来寄存该 Activity 的实例,而且该使命栈中只能存在该 Activity 的实例。适用于需求和其他运用程序隔离的 Activity,比方电话界面、相机界面等。 需求留意的是,发动形式只影响 Activity 的发动办法和使命栈的运作,不会影响 Activity 的生命周期。在运用 Activity 发动形式时,需求依据实践需求挑选适宜的发动形式,才干抵达最佳的效果。
4 Android Service 的发动办法
在 Android 开发中,能够经过以下办法敞开 Service
4.1 startService()
startService() 办法用于发动一个 Service,不会影响调用者的生命周期,除非调用 stopService() 或 stopSelf() 办法。运用 startService() 发动 Service 后,Service 会一向运转,直到调用 stopService()、stopSelf() 或 Service 自己调用 stopSelfResult()。
4.2 bindService()
bindService() 办法用于发动一个 Service,会影响调用者的生命周期,调用者与 Service 之间建立起连接,能够经过 ServiceConnection 回调接口进行通讯。运用 bindService() 发动 Service 后,Service 仅在连接存在时运转,只有调用者与 Service 都中止后才会被毁掉。
4.3 startForegroundService()
startForegroundService() 办法用于发动一个前台 Service,与 startService() 相似,可是发动的 Service 有必要调用 startForeground() 办法,将 Service 放在前台告诉栏中显现。
4.4 startIntentService()
startIntentService() 办法用于发动一个 IntentService,会在后台履行使命,使命履行结束后主动中止 Service。
运用 IntentService 能够防止手动中止 Service 的操作,然后进步运用的安稳性和可靠性。
需求留意的是,敞开 Service 后需求在恰当的时候中止 Service,以防止资源糟蹋和内存走漏。能够经过 stopService()、unbindService() 来中止 Service,或许在 Service 内部调用 stopSelf()、stopSelfResult() 来中止 Service。
5 Android 播送的注册办法
在 Android 开发中,能够经过以下办法注册播送:
5.1 静态注册
静态注册是指在 AndroidManifest.xml 文件中声明播送接纳器,并指定接纳的播送类型和处理逻辑。这种办法在运用发动时就会注册播送接纳器,只有在运用被卸载或更新时才会被刊出。静态注册的优点是方便,缺陷是无法动态增加或移除播送接纳器,且运用无法接纳未运转时的播送。
5.2 动态注册
动态注册是指在代码中运用 registerReceiver() 办法注册播送接纳器,并经过 unregisterReceiver() 办法刊出。
动态注册的优点是能够在运转时动态增加或移除播送接纳器,缺陷是需求在恰当的时刻刊出播送接纳器,不然会引起内存走漏或其他不必要的问题。
一般主张在 Activity 的 onResume() 办法中注册播送接纳器,在 onPause() 办法中刊出播送接纳器。
需求留意的是,在注册播送时需求指定 IntentFilter,即要接纳的播送类型。能够经过 IntentFilter.addAction() 办法增加要接纳的播送类型,也能够在 IntentFilter 构造函数中指定。播送类型能够是体系界说的,也能够是自界说的,依据实践需求挑选适宜的播送类型。
6 Android中Activity与fragment通讯办法
在 Android 中,Activity 与 Fragment 之间能够经过以下几种办法进行通讯:
6.1 运用接口回调
Activity 能够界说一个接口,在 Fragment 中完结该接口,并在 Activity 中获取 Fragment 实例后将该接口传递给 Fragment,这样 Fragment 就能够经过接口回调的办法与 Activity 进行通讯。
6.2 运用播送
Activity 能够经过发送播送的办法告诉 Fragment 进行相应的操作,Fragment 能够注册播送接纳器并在接纳到播送时履行相应的操作。需求留意的是,运用播送进行通讯或许会影响功用,主张在必要时才运用。
6.3 运用事情总线
事情总线是一种常用的通讯办法,常见的事情总线包括 EventBus 和 RxJava。
Activity 能够发送事情,Fragment 能够订阅事情并履行相应的操作。需求留意的是,运用事情总线需求增加相关依靠库,主张在大型项目中运用。
6.4 直接调用办法
假如 Fragment 与 Activity 之间的联系比较严密,也能够直接调用 Activity 中的办法进行通讯。Activity 能够获取 Fragment 实例并调用其办法,或许 Fragment 能够经过 getActivity() 办法获取 Activity 实例并直接调用其办法。需求留意的是,直接调用办法或许会导致耦合性较高,主张在必要时才运用。
综上所述,不同的通讯办法适用于不同的场景,需求依据实践需求挑选适宜的办法。
7 Android中怎么完结加载大图
在 Android 中,假如要加载大图,能够考虑以下几种办法:
7.1 运用 BitmapRegionDecoder
BitmapRegionDecoder 是 Android 供给的一个类,能够用来加载大图并显现其间的一个区域。运用这种办法,能够防止一次性加载整张大图,然后下降内存占用。
需求留意的是,运用 BitmapRegionDecoder 加载大图需求在子线程中进行,不然或许会引起 ANR。
7.2 运用 BitmapFactory.Options
能够经过 BitmapFactory.Options 中的 inSampleSize 特点来缩小图片的尺度,然后削减内存占用。inSampleSize 的值应该是 2 的指数,表明缩小的倍数。需求留意的是,缩小图片的尺度会下降图片的质量,需求依据实践需求挑选适宜的缩小倍数。
7.3 运用 Glide 或 Picasso 等第三方库
Glide 和 Picasso 等第三方库能够主动对加载的图片进行紧缩和缩放,然后防止一次性加载整张大图。一起,这些库也供给了其他的图片加载功用,如图片缓存、图片旋转、图片裁剪等。
7.4 将图片分割成多个小图
将图片分割成多个小图,并在需求时分别加载并拼接成一张完好的大图。
这种办法能够防止一次性加载整张大图,但需求进行额外的处理和办理,比较杂乱。
需求留意的是,加载大图或许会引起 OOM(Out of Memory)过错,因而需求合理地进行内存办理,防止一次性加载过多的图片。一起,也需求考虑用户的体会,如在加载图片时显现加载进度条,防止用户等候时刻过长。
8 Android中缓存数据的办法有哪些
Android 中常用的缓存数据的办法首要有以下几种:
8.1 SharedPreferences
SharedPreferences 是 Android 开发中最为常见的轻量级数据存储办法之一,适宜存储一些简略的键值对数据,比方用户的设置、运用的配置等。经过 SharedPreferences 存储的数据会存储在运用的私有目录下。
8.2 文件缓存
将数据以文件形式存储在本地,能够运用 Java 中的 File 类或 Android 中的 Context.getCacheDir() 办法保存数据。适宜存储一些较大的或许结构比较杂乱的数据,如图片、音频、视频等。
8.3 数据库
运用 SQLite 数据库存储数据,适宜存储数据量较大或结构比较杂乱的数据。经过 SQLiteOpenHelper 或许 ContentProvider 能够方便地对数据库进行增删改查操作。
7.4 内存缓存
将数据保存在内存中,适宜存储需求频频读写的数据,如图片缓存等。Android 中能够运用 LruCache 类完结内存缓存。
需求留意的是,缓存数据虽然能够进步运用功用,但也要留意缓存数据的过期时刻和铲除战略,防止缓存数据占用过多的存储空间。别的,关于一些敏感的数据,也应该采纳加密等措施来确保数据安全。
9 Android LruCache 缓存战略
LRU 缓存的根本原理是,缓存中的数据依照最近拜访的时刻次序排序,当缓存满时,删去最近最少运用的数据,然后确保缓存中的数据是最近拜访过的,而且能够最大程度地利用缓存空间。
在 Android 中,能够经过 LruCache 类来完结 LRU 缓存。 LruCache 类的运用进程如下:
- 创立 LruCache 实例 能够经过 new LruCache<K,V> (int maxSize) 办法来创立 LruCache 实例,其间 maxSize 表明缓存的最大容量。
- 存储数据 能够经过 put(K key, V value) 办法向 LruCache 中存储数据。假如存储的数据巨细超过了缓存的最大容量,LruCache 会主动删去最近最少运用的数据。
- 获取数据 能够经过 get(K key) 办法从 LruCache 中获取数据。假如数据存在于缓存中,LruCache 会将该数据移动到缓存的末尾,并回来该数据;不然回来 null。
10 Android中自界说View的进程
在 Android 中,完结自界说 View 的一般进程如下:
- 创立自界说 View 的类:能够经过继承 View 或许 ViewGroup 类来创立自界说 View 的类,并完结相应的办法来完结自界说 View 的功用。
- 供给自界说 View 的特点:在自界说 View 的类中,经过运用 @Attr、@Styleable 注解来界说自界说 View 的特点,并在 attrs.xml 文件中声明对应的特点。
- 重写 onMeasure 办法:onMeasure 办法用于测量自界说 View 的巨细,能够依据自界说 View 的特点和布局的要求来核算自界说 View 的测量值。
- 重写 onDraw 办法:onDraw 办法用于绘制自界说 View,能够在该办法中运用 Canvas 方针进行绘制操作。
- 处理接触事情:假如需求处理接触事情,能够重写 onTouchEvent 办法来处理。
- 处理滑动事情:假如需求支撑滑动操作,能够运用 Scroller 类来完结滑润滚动效果。
- 供给动画效果:能够运用动画来为自界说 View 增加动态效果,比方运用特点动画完结 View 的平移、旋转、缩放等效果。
- 处理自界说 View 的生命周期:能够经过重写 onAttachedToWindow、onDetachedFromWindow 等办法来处理自界说 View 的生命周期。 经过以上进程,就能够完结自界说 View 的完结。需求留意的是,在创立自界说 View 时,要尽量防止运用硬编码、耦合度高等问题,增强自界说 View 的可复用性和可维护性。
11 概述一下Android中的事情分发机制
在 Android 中,事情分发机制是指当用户经过接触屏幕、按下按键等操作时,体系对这些事情的处理流程。事情分发机制首要触及以下三个方针:View、ViewGroup 和 Window。
事情分发机制首要包括以下几个进程:
- 体系将接触事情传递给顶层的 Window,由 Window 将该事情传递给详细的 View。
- View 会将接触事情传递给自己的 onTouchEvent() 办法进行处理。假如该 View 没有处理该事情,则将该事情传递给其父 ViewGroup 进行处理。
- ViewGroup 会先将该事情传递给自己的 onTouchEvent() 办法进行处理。假如该 ViewGroup 没有处理该事情,则将该事情传递给其子 View 进行处理。
- 假如事情仍未被处理,则将事情传递给其上一级的 ViewGroup 进行处理,直到事情被处理或许抵达顶层的 Window。
- 假如事情都没有被任何 View 或 ViewGroup 处理,则该事情被判别为无效事情。
需求留意的是,事情分发机制的详细完结或许会受到 View 的特定完结和事情类型的影响,比方ScrollView会阻拦滑动事情进行处理。一起,经过重写 View 或 ViewGroup 的办法,也能够对事情分发机制进行自界说完结。
11 概述一下 Handler的原理
Handler 是 Android 中用于处理音讯和线程间通讯的机制。Handler 的原理首要包括以下几个进程:
- 创立一个 Handler 方针 在创立 Handler 方针时,体系会主动将该 Handler 与创立它的线程的 MessageQueue 相关联,一起该 Handler 会与创立它的线程的 Looper 相关联。
- 向 Handler 发送音讯 当经过 Handler 的 sendMessage() 办法向 Handler 发送音讯时,体系会创立一个 Message 方针,并将该方针增加到 Handler 对应的 MessageQueue 中。
- 将音讯分发给方针线程 当 Looper 预备处理该线程的 MessageQueue 时,体系会将 MessageQueue 中的音讯一个一个地取出,并依据音讯中的 target 特点,将音讯分发给对应的 Handler 进行处理。
- 处理音讯 当 Handler 接纳到音讯后,会依据音讯中的 what 特点和 Handler 内部的 handleMessage() 办法进行相应的处理。
- 处理完结后,或许发送新的音讯 在 handleMessage() 办法中,假如需求向该 Handler 发送新的音讯,则能够调用 sendMessage() 办法,将新的音讯增加到该 Handler 对应的 MessageQueue 中。
总的来说,Handler 的原理是经过 MessageQueue 和 Looper 来完结的,当经过 Handler 的 sendMessage() 办法向 Handler 发送音讯时,体系会将该音讯增加到 MessageQueue 中,然后经过 Looper 顺次取出音讯,并将其分发给对应的 Handler 进行处理。
12 Android中子线程运用Handler应该留意什么
在 Android 中,子线程运用 Handler 进行线程间通讯时,需求留意以下几点:
-
确认与哪个 Looper 相关联 与主线程不同,子线程默许是没有关联 Looper 的。因而,在运用 Handler 时,需求先创立一个 Looper 方针,并运用该方针创立一个 Handler 方针。
-
防止内存走漏 当子线程结束时,假如 Handler 方针没有被及时收拾,则或许会导致内存走漏问题。因而,在运用 Handler 时,需求尽量防止运用匿名内部类,以便在恰当的时候开释 Handler 方针。
-
不要在子线程中更新 UI Android 中规则,只能在主线程中更新 UI,不然或许会导致程序溃散。因而,在运用 Handler 时,需求留意不要在子线程中直接更新 UI,而是需求经过 Handler 将更新 UI 的操作发送给主线程进行处理。
综上所述,运用 Handler 进行线程间通讯时,需求留意与哪个 Looper 相关联、防止内存走漏,而且不要在子线程中更新 UI。
13 Android 中创立子线程的办法有哪几种
13.1 运用 Thread 类进行创立
Thread 是 Java 中的一个类,能够经过继承 Thread 类或许创立 Thread 方针并传入 Runnable 方针来创立子线程
13.2 运用 Runnable 接口进行创立
Runnable 是 Java 中的一个接口,能够经过完结 Runnable 接口并将其传入 Thread 方针来创立子线程。
13.3 运用 AsyncTask 类进行创立
AsyncTask 是 Android 中的一个类,能够经过继承 AsyncTask 类并重写其办法来创立子线程。AsyncTask 能够方便地进行 UI 操作,而且不需求手动处理线程间通讯问题。
13.4 运用线程池进行创立
线程池是一种能够重复利用线程的机制,能够削减创立和毁掉线程所带来的开支。Android 中常用的线程池包括 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor。
14 Android中子线程与主线程的通讯办法
在 Android 中,子线程与主线程之间的通讯是一种常见的需求,一般有以下几种办法:
14.1 运用 Handler
Handler 是 Android 中的一个类,能够用来在不同线程间传递音讯。主线程能够创立一个 Handler 方针,并将其传递给子线程。子线程能够在需求更新 UI 界面时,经过调用 Handler 的 post 办法来告诉主线程进行相应的操作。例如:
Handler handler = new Handler(Looper.getMainLooper());
// 在子线程中履行耗时操作
new Thread(new Runnable() {
@Override
public void run() {
// 子线程要履行的代码
// 发送音讯告诉主线程更新 UI
handler.post(new Runnable() {
@Override
public void run() {
// 主线程要履行的代码
}
});
}
}).start();
14.2 运用 runOnUiThread 办法
Activity 类供给了一个 runOnUiThread 办法,能够用来在主线程中履行代码。子线程能够经过该办法来更新 UI 界面。例如:
new Thread(new Runnable() {
@Override
public void run() {
// 子线程要履行的代码
// 在主线程中更新 UI
runOnUiThread(new Runnable() {
@Override
public void run() {
// 主线程要履行的代码
}
});
}
}).start();
14.3 运用 AsyncTask
AsyncTask 是 Android 中的一个类,在 doInBackground 办法中履行耗时操作,在 onPostExecute 办法中更新 UI 界面。例如:
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
// 子线程要履行的代码
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
// 主线程要履行的代码
}
}.execute();
14.4 运用 broadcastReceiver 能够用 broadcastReceiver 来完结子线程向主线程发送音讯。子线程发送 broadcast,主线程接纳 broadcast,然后在主线程的 onReceive 办法中进行相应的操作。例如:
// 在子线程中发送 broadcast
Intent intent = new Intent("com.example.UPDATE_UI");
sendBroadcast(intent);
// 在主线程中注册 broadcastReceiver
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 主线程要履行的代码
}
};
registerReceiver(receiver, new IntentFilter("com.example.UPDATE_UI"));
综上所述,Android 中子线程与主线程的通讯办法有运用 Handler、运用 runOnUiThread 办法、运用 AsyncTask 和运用 broadcastReceiver。依据实践需求挑选适宜的办法。
15 概述一下Android中的冷发动与热发动
在 Android 中,运用发动有两种办法:冷发动和热发动。
15.1 冷发动
是指在运用没有在后台运转的状况下,点击运用图标发动运用。
这种办法需求进行完好的运用发动进程,包括创立新的进程、创立运用方针、创立运用的界面和初始化数据等操作。因为需求履行完好的发动进程,所以耗时较长。
15.2 热发动
是指在运用现已在后台运转的状况下,再次点击运用图标发动运用。
这种办法不需求重新创立进程和运用方针,而是直接从后台切换到前台并康复运用的状态。因为不需求进行完好的发动进程,所以速度较快。
需求留意的是,假如运用在后台运转较长时刻且体系资源紧张,也或许会被体系收回掉,此时再次发动运用就会触发冷发动进程。
为了进步用户体会,Android中的运用一般会对发动进行优化,例如运用发动页、预加载等办法,下降用户感知到的发动耗时,进步运用发动速度。一起,在运用开发中也需求留意发动优化,削减发动时刻,进步用户体会。
16 Android运转时类的加载机制
在 Android 中,Java 代码会被编译成 .class 文件,然后打包成 .dex 文件,在运转时加载到虚拟机中履行。 详细的进程如下:
16.1
.dex 文件的加载 在运用发动后,Android 体系会为运用分配一个独立的虚拟机 Dalvik 或 ART。Dalvik 和 ART 会分别加载运用的 .dex 文件,将其间的代码解析成字节码,在虚拟机中履行。
16.2 类的查找
虚拟机在加载运用的 .dex 文件时,会扫描这些文件,查找其间的类信息并记载在一个列表中。当需求加载某个类时,虚拟时机先在这个列表中查找,假如找到了就直接加载。假如没有找到,则会经过类加载器向其他 .dex 文件或体系的类库中查找。
16.3. 类的加载
假如找到了需求加载的类,虚拟时机先查看该类是否现已被加载过。假如没有加载过,就会为这个类创立一个 Class 方针,并在虚拟机中为其分配内存空间。然后,虚拟时机依据类的信息,加载这个类的父类和接口,并将这些内容一起存储在内存中。
16.4 类的链接
在类加载的进程中,虚拟时机对这个类进行链接。
链接的进程包括验证、预备和解析三个阶段。其间,验证阶段会查看这个类的信息是否合法;预备阶段会分配并初始化类变量的内存空间;解析阶段会将符号引证转化成直接引证。
16.5 类的初始化
最终,假如这个类还没有被初始化过,就会触发其初始化进程。类的初始化进程包括静态变量的赋值和静态代码块的履行等操作。
总归,Android 运转时类的加载机制和传统的 Java 运转时类加载机制比较相似,但有一些细节上的差别。例如,Android 运转时环境选用的是依据 .dex 文件的虚拟机,而不是依据 .class 文件的虚拟机。此外,Android 体系还能够经过类加载器加载外部的 .jar 文件,然后扩展运用的功用。
17 Android中方针的内存收回机制
在 Android 中,方针的内存收回机制由废物收回器来完结。废物收回器是一个体系等级的服务,它会守时扫描运用的内存空间,查看哪些方针现已不再被引证,然后将这些方针符号为废物,并收回它们所占用的内存空间。 方针的内存收回机制首要触及以下几个方面:
17.1. 引证计数
引证计数是一种简略直观的内存收回办法,它记载每个方针被引证的次数。当方针的引证计数减为 0 时,就能够将其收回。可是,引证计数办法容易呈现循环引证的问题,导致一些方针无法被收回,因而在 Android 中并没有选用该办法进行内存收回。
17.2. 符号铲除
符号铲除是一种依据可达性剖析的内存收回办法。废物收回器会从根方针(如 Activity、Service 等)开端遍历,找出一切被引证的方针,并在堆上为这些方针打上符号。然后,废物收回器会扫描堆上一切的方针,将没有符号的方针视为废物,将其收回。缺陷是符号和铲除进程功率较低。
17.3. 仿制算法
仿制算法是一种依据空间仿制的内存收回办法。它将堆空间分为两个持平的部分,每次只运用其间一部分,当这一部分的空间用尽时,将其间的存活方针仿制到空间未用尽的另一部分上,并铲除原来的部分。缺陷是糟蹋了一半的空间。
17.4. 符号收拾
符号收拾是一种综合了符号铲除和仿制算法的内存收回办法。
它先进行符号,然后把一切存活的方针往堆的一端移动,把未被运用的空间会集起来,最终铲除一切移动后的废物方针。缺陷是移动方针的进程需求消耗一定的时刻。
总归,Android 中的方针内存收回机制首要选用依据可达性剖析的符号铲除和符号收拾算法,以及一些优化手法来进步内存收回功率。运用开发者能够经过削减方针的创立、合理运用缓存等手法来减轻废物收回器的负担,然后进步运用的功用和安稳性。
18 Android中怎么完结插件动态加载
在 Android 中,完结插件化首要有两种办法:动态加载和静态加载,其间动态加载是指在运用程序运转时加载插件,而静态加载是指在编译时加载插件。
下面介绍一下 Android 中怎么完结动态加载插件。 完结动态加载插件的详细进程如下:
- 创立插件 APK 文件 开发者需求创立一个插件 APK 文件,该文件包括插件的一切资源和代码。插件 APK 文件应该包括一个 Activity,该 Activity 用于发动插件。
- 创立宿主运用程序 宿主运用程序是指用于加载插件的运用程序。开发者需求在宿主运用程序中创立一个用于加载插件的 Activity,该 Activity 能够依据插件的包名和类名发动插件中的 Activity。
- 在宿主运用程序中加载插件 宿主运用程序能够经过以下几种办法加载插件:
3.1 运用 ClassLoader 加载插件中的类和资源;
3.2 运用反射调用插件中的办法;
3.3 运用 Intent 调用插件中的 Activity。 - 更新插件 运用程序热更新能够协助开发者快速修复运用程序中的问题,并供给更好的用户体会。开发者能够经过下载新版插件文件并替换原版插件文件的办法进行插件更新,在插件更新进程中需求留意安全性和安稳性问题。
需求留意的是,动态加载插件需求慎重考虑,开发者需求留意插件的安全性和安稳性问题。主张在必要时才运用动态加载插件,防止对运用程序的安稳性和用户体会造成不良影响。
最新的开发办法主张是 Android + 小程序 来替换插件化更新计划。
19 概述一下Android中完结动画的办法
Android 中完结动画的办法有以下几种:
19.1. View Animation
View Animation 又称 tween(补间)动画,是最根本的动画完结办法,能够完结平移、旋转、缩放和透明度等效果,经过对 View 进行缩放、移动、旋转和淡入淡出等处理,让 View 呈现相似于动效的效果。View Animation 一般用于简略的动画效果完结,适用于 API 1 及以上版别。
19.2.
Property Animation Property Animation 是 Android API 3.0 引进的新动画特性,与 View Animation 不同,Property Animation 能够完结更灵敏、更天然的动效,适用于 API 11 及以上版别。Property Animation 能够对 View 的特点进行详细的操作,如对 View 的方位、巨细、圆角、透明度等特点进行操作。一起,还能够对多个 View 进行联合动画。
19.3. Drawable Animation
Drawable Animation 能够完结相似帧动画的效果,用于显现连续的帧图画。它经过在 Drawable 方针中界说一组不同的图片,在一段时刻内顺次播映这些图片,然后完结动态效果。Drawable Animation 一般用于一些简略的帧动画效果,适用于 API 1 及以上版别。
19.4. 动画布局
动画布局是一个布局容器,能够将多个动画效果结合起来,完结杂乱的动画效果。动画布局能够使 View 具有有机的运动效果,能够很方便地完结多种杂乱的动画效果。动画布局一般用于比较杂乱的动画效果,适用于 API 3 及以上版别。 综上所述,Android 中完结动画的办法有多种挑选,开发者能够依据实践需求挑选适宜的办法,完结想要的动画效果。
20 Andorid中怎么完结数据加密
在 Android 中,能够运用如下办法完结数据加密:
20.1. 对称加密
对称加密算法(如 AES、DES、3DES)运用相同的密钥对数据进行加密和解密。在 Android 中,能够运用 javax.crypto 包中的类来完结对称加密。
20.2. 非对称加密
非对称加密算法(如 RSA、DSA)运用公钥加密,私钥解密或许运用私钥签名,公钥验证。在 Android 中,能够运用 java.security 包中的类来完结非对称加密。
20.3. 音讯摘要
音讯摘要算法(如 MD5、SHA)将任意长度的数据转化为一个固定长度的摘要信息,一般用于数据完好性校验。在 Android 中,能够运用 java.security 包中的类来完结音讯摘要。
20.4. HTTPS HTTPS 是依据 SSL/TLS 协议的加密协议,在网络传输进程中对数据进行加密。在 Android 中,能够运用 HttpsURLConnection 或许 OkHttp 等结构来完结 HTTPS 恳求。
需求留意的是,在完结数据加密时,需求留意密钥的生成和办理、加密算法的挑选、数据传输的安全性等问题。一起,还需求留意密钥加密和数据加密的别离,以确保密钥的安全性。
21 AES 加密算法原理概述
AES(Advanced Encryption Standard),高档加密标准,是一种对称加密算法,用于维护敏感信息的安全性,安全性高于 DES 等老式加密算法。
AES 加密算法的原理如下:
- 密钥生成 AES 加密算法运用一个密钥进行加密和解密,密钥的长度能够是 128 位、192 位或 256 位。依据密钥长度的不同,加密算法分别称为 AES-128、AES-192 和 AES-256。
- 明文的转化 AES 加密算法将明文分成若干个长度为 16 字节的块(假如明文不足 16 字节,要进行填充)。每个块经过加密算法的运算,转化为一个密文块,然后将这些密文块组合起来,形成加密后的密文。
- 加密进程 AES 加密算法的加密进程运用一系列杂乱的算法,包括字节替换、行移位、列混杂和轮密钥加。这些算法将密文块与密钥进行混合运算,然后得到加密后的密文块。AES 加密算法选用多轮加密,轮数的数量取决于密钥的长度和块的巨细。
- 解密进程 AES 解密算法与加密算法彻底对称,运用相同的密钥和相反的运算,能够将加密后的密文解密为明文。解密进程也是多轮的。
总结:AES 加密算法经过多轮加密和解密运算,运用密钥对明文进行加密,然后得到安全的密文,确保了信息的机密性。原理比较杂乱,但其运用广泛,是现代网络通讯中常用的加密算法之一。
22 概述一下 Android中的RenderScript
RenderScript 是用于在 Android 上以高功用运转核算密集型使命的结构。RenderScript 首要用于数据并行核算,不过串行作业负载也能够从中受益。
RenderScript 运转时可在设备上供给的多个处理器(如多核 CPU 和 GPU)间并行调度作业。这样您就能够专注于表达算法而不是调度作业。RenderScript 关于专注于图画处理、核算摄影或核算机视觉的运用来说尤其有用。
从 Android 12 开端,RenderScript API 已被抛弃。可运用RenderScript 内建函数替换工具包来替代。
23 概述一下Android中的权限体系
在 Android 中,权限体系用于维护用户数据和体系资源,确保运用只能在其授权范围内操作。
Android 的权限体系首要分为以下几个层次。
- 运用权限 运用权限是指运用在装置时需求获取的权限,如拜访相机、文件体系等。运用权限由 Android 体系界说,并依照危险等级分类,包括一般权限和危险权限。在 Android 6.0 及以上版别中,运用有必要在运转时动态恳求危险权限,用户能够挑选颁发或拒绝运用权限。
- 用户权限 用户权限是指 Android 操作体系为用户保留的一些权限,如拨打电话、发送短信等,这些权限能够在体系设置中进行办理和授权。用户权限归于体系等级的权限,不同于运用权限。
- 设备战略权限 设备战略权限是指 Android 企业设备办理功用所需的权限,包括锁定设备、铲除设备数据等。这些权限由设备办理员办理和授权,在具有这些权限的前提下,企业设备办理者能够办理和操控设备的运用。
- 未知来源运用装置权限 在 Android 体系中,用户能够装置来自 Google Play 商店以外的运用,但需求先在设置中授权答应来自未知来源的运用装置。这是一种安全机制,能够防止用户意外装置有恶意程序的运用。
- root 权限 root 权限是指用户获取设备 root 权限后所具有的体系等级权限。具有 root 权限的用户能够对体系进行自由操作和配置,但一起也带来了安全和安稳性问题,因而不主张一般用户获取 root 权限。
24 概述一下 Android 12 的一些新特性
- 更出色的隐私维护和权限办理:Android 12 加强了隐私维护和权限办理,供给了愈加细致的权限操控和愈加安全的数据维护。
- Materia You 规划言语:Android 12 推出了全新的规划言语 Materia You,增加了更多的动画特效和个性化设置,为用户带来愈加流通、美观的体会。
- 手势操作增强:Android 12 增强了手势操作的功用和灵敏度,供给了愈加天然的交互办法。
- 愈加智能和快捷的用户体会:Android 12 引进了一系列智能化特性,如主动切换 Wi-Fi 和手机数据网络、智能截屏等,为用户带来愈加快捷的运用体会。
- 愈加高效的功用优化和资源办理:Android 12 供给了愈加高效的内存办理和资源分配,为运用供给愈加安稳、快速的功用表现。
- 数字身份和数字钱包:Android 12 支撑数字身份和数字钱包功用,用户能够安全地存储和办理自己的身份证、驾驶证、信用卡等个人信息。
总归,Android 12 的新特性首要聚集于隐私维护、个性化规划、智能化特性、功用优化和数字身份等方面,为用户带来愈加智能、快捷和安全的运用体会。
25 概述一下 Android 13 的一些新特性
25.1 发送告诉权限
大多数运用程序利用告诉发布有用的警报和提醒,在Android 13中,谷歌增加了告诉的运转时权限。
为了不干扰用户和开发者,Android 13中的告诉拜访会依据正在运转的运用程序的方针API等级进行不同的处理。然而,不论运用程序的方针API等级怎么,Android 13都会提示用户颁发运用程序发送告诉的权限。
Android 13 或更高版别为方针渠道,需求在运用程序manifest文件中,显现声明的权限,而且需求动态恳求。
<manifest ...>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application ...>
...
</application>
</manifest>
25.2 读取媒体文件权限
以Android 13 及以上为方针渠道,需求恳求如下权限.要保持与旧版别Android的兼容性,请把READ_EXTERNAL_STORAGE的maxSdkVersion设为32。
<manifest ...>
<!-- Required only if your app targets Android 13. -->
<!-- Declare one or more the following permissions only if your app needs
to access data that's protected by them. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- Required to maintain app compatibility. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application ...>
...
</application>
</manifest>
25.3 邻近的WIFI设备权限
在Android 13中,Google将Wi-Fi扫描与方位别离。Android 13 为办理设备与周围 Wi-Fi 热门连接的运用增加NEARBY_WIFI_DEVICES运转时权限 (归于NEARBY_DEVICES权限组)。
以 Android 13 为方针渠道的运用程序,拜访邻近的 WI-FI 设备。除特例API需求恳求ACCESS_FINE_LOCATION外,其他需求恳求android.permission.NEARBY_WIFI_DEVICES运转时权限;
25.4 播送接纳器
播送接纳器是否应被导出以及是否对设备上的其他运用可见,Android 13 或更高版别为方针渠道的运用,在运用的每个播送接纳器中,明晰指明其他运用是否能够向其发送播送,如以下代码段所示:
context.registerReceiver(sharedBroadcastReceiver, intentFilter,
RECEIVER_EXPORTED);
//或许是
context.registerReceiver(privateBroadcastReceiver, intentFilter,
RECEIVER_NOT_EXPORTED);
假如在注册时不指定,体系会抛出 SecurityException。
25.5 新增的功用
- 新的相片挑选器和 API
- Android 13 开端改写 Android 的中心库
- Android 13 增加了对可编程 RuntimeShader 方针的支撑
- 新的图块放置API将答应运用程序提示用户直接将自界说图块增加到活动的快速设置图块集合中
- Android 13版别在CameraManager类中包括了新办法,能够让运用程序取得并设置手电筒强度等级。
- 从 Android 13 开端,将内容增加到剪贴板时,体系会显现标准视觉确认界面
26 概述一下Android中WebView与JS的交互办法
在 Android 中,WebView 与 JavaScript 之间能够经过以下几种办法进行交互:
26.1. 运用 addJavascriptInterface() 办法
Android 4.2 及以上版别支撑运用 addJavascriptInterface() 办法在 WebView 中注册一个 Java 方针,使其露出给 JavaScript 调用。Java 方针中的 public 办法能够被 JavaScript 直接调用,然后完结 WebView 和 JavaScript 的彼此调用。
26.2. 运用 evaluateJavascript() 办法
Android 4.4 及以上版别支撑运用 evaluateJavascript() 办法在 WebView 中履行 JavaScript 代码,并获取履行成果。经过该办法,能够完结 WebView 调用 JavaScript 办法,并获取回来值。需求留意的是,该办法是异步的,回来成果需求经过回调办法获取。
26.3. 运用 JavaScriptInterface 接口 Android 2.3 及以上版别支撑运用 JavaScriptInterface 接口完结 WebView 和 JavaScript 的交互。经过在 Java 中界说接口,在 JavaScript 中完结该接口,然后完结 JavaScript 调用 Java 办法的功用。
26.4. 运用 shouldOverrideUrlLoading()
办法 WebView 中的 shouldOverrideUrlLoading() 办法能够阻拦 WebView 中的网页中的 URL 恳求,然后完结 JavaScript 与 Java 之间的通讯。经过在 WebView 中加载特定的 URL 恳求,Java 能够捕获该恳求,并触发相应的操作。 综上所述,以上这些办法都能够完结 WebView 和 JavaScript 的交互,需求依据实践需求挑选适宜的办法。需求留意的是,在运用 WebView 和 JavaScript 交互时,要留意数据安全问题,并尽量防止用户输入的数据被攻击者利用。
27 Android Webview中的定位问题
在 Android WebView 中,定位功用一般需求用户授权拜访方位信息,不然定位功用将无法正常作业。一起,定位功用还需求满足以下条件:
- WebView 中需求启用 JavaScript 支撑。
- WebView 中需求设置 setGeolocationEnabled() 办法为 true,以启用定位功用。
- Android 设备需求启用定位服务,而且需求敞开网络定位和 GPS 定位。
- AndroidManifest.xml 文件中需求增加相应的权限声明,如 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION,以获取定位信息的权限。 在 Android 6.0 及以上版别,用户授权拜访方位信息需求动态恳求权限。
能够经过以下代码示例完结:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 未授权,恳求定位权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE);
} else {
// 已授权,启用定位功用
webView.getSettings().setGeolocationEnabled(true);
webView.getSettings().setJavaScriptEnabled(true);
}
在处理定位信息时,还需求完结 WebChromeClient 类中的 onGeolocationPermissionsShowPrompt() 办法,用于向用户显现方位信息恳求对话框并获取用户授权,示例代码如下:
// 完结 WebChromeClient 类
private class MyWebChromeClient extends WebChromeClient {
@Override
public void onGeolocationPermissionsShowPrompt(String origin,
GeolocationPermissions.Callback callback) {
// 显现方位信息恳求对话框,并获取用户授权
callback.invoke(origin, true, false);
}
}
需求留意的是,定位功用在运用时需求留意隐私问题,尽量防止用户信息泄露。
28 Android Webview 的输入框问题
在 Android WebView 中,输入框问题首要有以下几种状况:
- 输入法弹出问题:当 WebView 中包括输入框时,用户点击该输入框时,输入法或许不会弹出。这个问题能够经过设置 webView.requestFocus() 办法来处理。
- 输入框文字不能被清空问题:在某些状况下,用户在输入框中输入文字后,无法经过点击清空按钮或经过长按输入框来清空输入框中的文字。这个问题一般发生在参加了某些特定的 CSS 样式或 JS 脚本时。能够经过设置 webView.getSettings().setJavaScriptEnabled(true) 办法来启用JavaScript支撑以处理这个问题。
- 输入框取得焦点问题:在某些状况下,输入框或许无法取得焦点,例如在运用 Hybrid App 开发时,输入框的焦点或许会丢掉。这个问题能够经过手动设置输入框获取焦点来处理,例如在加载 WebView 时调用 input.requestFocus() 办法即可。
- 输入框光标方位问题:在某些状况下,输入框中的光标或许会呈现在输入框外面。这个问题一般发生在 WebView 中嵌套了多个层级的 div 标签时。能够经过设置输入框的 position 特点来处理这个问题,例如在 CSS 中设置:
input { position: relative; z-index: 1; }
以上是常见的 Android WebView 输入框问题和处理办法,需求依据实践状况挑选与处理。
29 Java中类加载的双亲派遣原理
双亲派遣是指在 Java 中类加载器在加载一个类时,首要将加载恳求派遣给父类加载器,假如父类加载器无法加载该类,则再交给当时加载器自己测验加载。假如当时加载器依然无法加载,则将加载恳求持续向上派遣,直到顶层的发动类加载器。只有在一切的父类加载器都无法加载该类时,才会由当时类加载器自己加载。
双亲派遣机制的首要意图是确保 Java 类库的安全性和安稳性。因为 Java 类库触及到Java中心类库和第三方库,不同的类或许会以不同的办法被加载,假如不存在标准的加载次序,就会呈现一些安全和安稳性问题。而经过双亲派遣机制,能够确保不同的类库或运用程序不会干扰到中心类库,然后确保Java的安全性和安稳性。
例如,当咱们在类路径下自界说了一个名为java.lang.String的类,假如没有双亲派遣机制,Java虚拟机或许会优先加载咱们自界说的类,而不是中心的java.lang.String类,这样将会导致程序不安稳。而经过双亲派遣机制,Java虚拟时机首要派遣给父类加载器Bootstrap类加载器去加载java.lang.String类,因为Bootstrap类加载器是最顶层的类加载器,所以假如它无法加载,才会持续向下派遣,直到体系最低层的运用程序加载器。
总归,双亲派遣机制经过界说明晰的类加载器层次联系,确保了Java中心类库和第三方库的安全和安稳性。
30 HashSet怎么确保不重复
在 HashSet 中,不答应存在重复的元素,它是经过两个办法来确保其元素不重复的。
30.1 哈希表
HashSet 内部实践上是一个 HashMap,其间一切元素都存储在 HashMap 的 Key 中,而 Value 中存储了一个不变的 Object 方针。因而 HashSet 实践上是依据 HashMap 的封装,它运用 HashMap 作为存储结构。HashMap 的 Key 能够看成是 HashSet 的元素,而 Value 始终为一个不变的 Object 方针。
当向 HashSet 中刺进一个元素时,HashSet 首要会依据该元素的 hashCode() 办法回来值得到一个 hash 值,并由此确认该元素在 HashSet 内部存储的方位。假如该方位上现已有元素存在,则需求比较这两个元素是否持平。假如两个元素不持平,则需求在该方位上持续寻找适宜的方位。如此循环直到找到一个空的方位或许找到了与该元素持平的元素为止。
30.2 equals() 办法
因为 HashSet 是经过 hashCode() 办法和 equals() 办法来判别元素是否持平的,因而假如两个元素的 hashCode() 办法回来值持平,而且 equals() 办法回来 true,则以为这两个元素是持平的,HashSet 将不会将后续被增加的元素增加到 HashSet 中。
因而,在运用 HashSet 时应该为需求增加到 HashSet 中的元素正确地完结 hashCode() 办法和 equals() 办法,不然增加到 HashSet 中的元素或许会重复。
综上所述,HashSet 经过哈希表和 equals() 办法来确保其元素不重复。完结 hashCode() 办法和 equals() 办法关于确保 HashSet 内部元素不重复是至关重要的。
31 Java中wait/notify关键字
在Java中,wait/notify是一种线程同步机制,用于完结多线程之间的协作和互斥操作。wait/notify是依据方针的锁机制,只能用于同步办法或同步代码块中,运用时需求先获取方针的锁。
31.1 Wait办法
当线程调用一个方针的wait办法时,该线程会被堵塞,开释当时方针的锁,并进入方针的等候行列中,直到其他线程调用了该方针的notify/notifyAll办法,或许等候时刻抵达后,线程才会被唤醒。
31.2 Notify办法
当线程调用一个方针的notify办法时,该方针的等候行列中的一个线程将被唤醒,被唤醒的线程需求等候当时线程退出同步块或办法后,才干再次竞赛该方针的锁。假如要唤醒等候行列中的一切线程,能够运用notifyAll办法。
运用wait/notify技能能够完结多线程的协作和互斥操作,防止了繁琐的轮询等候机制,进步了程序功用。可是,运用wait/notify供给的线程同步机制需求慎重运用,不然或许会导致死锁和其他问题。
32 Java中完结线程同步的办法
Java中完结线程同步的办法首要包括以下几种:
- synchronized关键字:运用synchronized关键字能够对同享资源进行同步,使得在同一时刻只有一个线程能够拜访该资源。synchronized能够润饰办法或代码块,确保了线程的互斥拜访和可见性。
- Lock接口:Lock是Java5中引进的一个新的同步机制,经过Lock和Unlock办法来对同享资源进行加锁和开释操作,与synchronized比较,能够愈加灵敏地操控同步范围。
- ReentrantLock类:ReentrantLock是Lock接口的一个完结类,功用比synchronized愈加强壮,包括可重入锁、可中止锁、公平性、完结Condition等功用。
- volatile关键字:运用volatile关键字润饰的变量在多个线程之间可见,即一个线程对该变量做出的修正,会被其他线程立即看到,并更新自己的缓存。volatile关键字能够确保线程之间的可见性。
- AtomicInteger类:AtomicInteger是Java中供给的一个原子性变量类,它能够确保多个线程一起对一个整数变量进行加减操作时的原子性。
- synchronized块和Lock接口完结读写锁:在读写别离的场景中,能够运用synchronized块或Lock接口的完结类ReadWriteLock来完结读写锁,然后进步程序的并发性和功用。
总的来说,以上几种办法都能够用来完结线程之间的同步和协作,咱们在实践开发中需求依据详细的需求挑选适宜的办法来完结线程同步。
33 Java的原子性、可见性、有序性概述
Java 中的原子性、可见性和有序性是指在多线程环境下,Java 内存模型对数据的拜访和操作具有的特性。它们分别表明如下含义:
- 原子性:指一个操作是不可中止的,在履行进程中,不能被其他线程干扰。Java 中供给了一些原子性操作类,如 AtomicBoolean、AtomicInteger、AtomicLong 等,能够确保该操作的原子性,而且在多线程环境下也能够正常运用。
- 可见性:指一个线程对同享数据的修正,能够被其他线程及时地感知到。Java 中运用 volatile 关键字能够完结可见性。当一个变量被 volatile 关键字润饰时,表明该变量被多个线程同享,任意一个线程对变量的修正都会被其他线程及时地感知到。
- 有序性:指程序履行的次序依照代码的先后次序履行。Java 中运用 synchronized 关键字和 Lock 接口能够确保有序性,因为它们都会在履行之前取得锁,然后确保代码的先后次序。
34 Java 线程中的join
Java中的join()办法是一个非常重要的线程同步办法。它能够让当时线程等候另一个线程履行结束后再履行。
运用join()办法能够确保线程的履行次序,防止呈现多线程并发时的问题。 join()办法的运用非常简略,只需求在需求等候其他线程履行结束的线程中调用另一个线程的join()办法即可。例如,咱们能够运用如下代码等候线程A履行结束:
Thread threadA = new Thread(() -> {
// 线程A的业务逻辑
});
// 发动线程A
threadA.start();
// 等候线程A履行结束
try {
threadA.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
在上面的代码中,咱们创立了一个线程A,并发动它。然后,咱们在当时线程中调用线程A的join()办法,等候线程A履行结束后再持续履行。
需求留意的是,join()办法会抛出InterruptedException异常,咱们需求处理它。
此外,假如join()办法的参数设置为一个较长的时刻,那么在等候期间假如被中止,也会触发InterruptedException异常。
总归,运用join()办法能够让多个线程之间和谐一致地履行,防止呈现多线程并发时的问题。可是,在运用join()办法时,咱们需求留意处理InterruptedException异常,并合理设置等候时刻,防止呈现死锁等问题。
35 Java中使命调度
Java中使命调度首要经过以下两种办法完结:
-
java.util.Timer 和 java.util.TimerTask 这是Java中最根本的使命调度办法,它依据时刻驱动,能够指定一个时刻点或一个时刻距离,履行相应的使命。Timer类负责守时调度,而TimerTask类则表明要守时履行的使命。在运用时,咱们需求创立Timer和TimerTask的实例,然后经过Timer的schedule()办法来指定使命的履行时刻和距离。
-
Java.util.concurrent.ScheduledExecutorService 这是Java 5之后引进的新的使命调度办法,它是在ExecutorService基础上扩展的,能够运用ScheduledExecutorService履行守时使命。ScheduledExecutorService能够经过schedule()、scheduleAtFixedRate()和scheduleWithFixedDelay()办法来完结使命的守时调度,每个办法的调度办法稍有不同,能够依据业务需求进行挑选。
使命调度在Java中广泛运用于各种场景,例如守时使命、异步履行、数据备份等。它能够协助咱们主动化地完结各种使命,并进步体系的可靠性和功率。可是,在运用使命调度时,咱们需求留意安全性和功用等方面的问题,防止呈现竞态条件、死锁等并发问题。
36 Java中wait和sleep办法
Java中的wait()和sleep()办法都能够用于线程的等候和暂停,可是它们的效果和运用办法有所不同。
wait()办法是Object类中界说的办法,能够让当时线程等候,直到其他线程调用notify()或notifyAll()办法唤醒它。在运用wait()办法时,咱们需求将其放在synchronized块中,而且运用notify()或notifyAll()办法来唤醒等候的线程。
例如,咱们能够运用如下代码完结线程之间的等候和唤醒:
Object lock = new Object();
// 等候线程
Thread waitThread = new Thread(() -> {
synchronized (lock) {
try {
lock.wait();
// 被唤醒后履行的逻辑
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 唤醒线程
Thread notifyThread = new Thread(() -> {
synchronized (lock) {
lock.notify();
}
});
// 发动线程
waitThread.start();
notifyThread.start();
sleep()办法是Thread类中界说的静态办法,能够让当时线程暂停一段时刻。在运用sleep()办法时,咱们不需求运用synchronized块,也不需求其他线程的唤醒操作。 例如,咱们能够运用如下代码完结线程的暂停:
Thread.sleep(1000); // 暂停一秒钟
需求留意的是,wait()办法和sleep()办法的效果和用法不同,不能混杂运用。在运用wait()办法时,需求将其放在synchronized块中,而且经过notify()或notifyAll()办法来唤醒等候的线程。在运用sleep()办法时,不需求运用synchronized块,而且不需求其他线程的唤醒操作。