🔥Android大厂面试通关秘籍:深度剖析技术原理与源码
一、Android系统架构大揭秘
1.1 架构分层的奇妙世界
嘿,朋友们!想象一下Android系统就像一座宏伟的大厦,它有着清晰的分层结构,每一层都有着独特的使命。咱们先从最底层的Linux内核层说起,这就像是大厦的地基,稳如泰山地支撑着整个系统。
c
// kernel/sched/sched.h
// 定义调度类,这可是进程调度的核心哦
struct sched_class {
const struct sched_class *next; // 指向下一个调度类的指针
// 任务入队操作,就像把任务安排到队列里等待处理
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
// 任务出队操作,把处理好的任务从队列中移除
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
// 选择下一个运行的任务,就像挑选下一个要表演的演员
struct task_struct * (*pick_next_task) (struct rq *rq);
};
接着是系统运行库层,它就像是大厦里的各种工具间,存放着各种各样的工具(C/C++库和Android运行时),供上层使用。以SQLite这个常用的数据库库为例,它的代码就像一个精密的机器,每一行都有着重要的作用。
c
// external/sqlite/sqlite3.c
// 打开数据库函数,就像打开一个神秘的宝箱
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
){
// 检查参数合法性,就像检查宝箱的钥匙是否正确
if( ppDb==0 ) return SQLITE_ERROR;
*ppDb = 0;
// 调用内部打开数据库函数,真正去打开宝箱啦
return sqlite3_open16((const void*)filename, ppDb);
}
再往上就是应用框架层,这可是开发者的大舞台,提供了丰富的API让我们可以尽情发挥。Activity的启动流程就像是一场精心编排的舞蹈,每一个动作都有它的意义。
java
// frameworks/base/core/java/android/app/ActivityThread.java
// 处理Activity启动请求,就像导演安排一场表演的开场
public void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 获取Activity实例,就像找到表演的主角
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
// 将Activity与窗口建立关联,就像给主角安排一个舞台
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && r.startsNotResumed, r.isForward);
}
}
最上层就是应用层啦,这就是我们平时在手机上看到的各种丰富多彩的应用程序,就像大厦里的一个个精彩的房间。
1.2 系统启动的惊险之旅
Android系统的启动就像是一场刺激的冒险之旅,从Bootloader阶段开始,就像是探险者踏上了未知的土地。
c
// u-boot/arch/arm/cpu/armv7/start.S
.globl _start
_start:
// 关闭看门狗,就像关掉一个随时可能触发的陷阱
ldr r0, =0x40048000
ldr r1, =0x0
str r1, [r0]
// 设置CPU模式,就像调整探险者的装备
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0x10
msr cpsr, r0
// 跳转到C语言初始化函数,开始正式的探险啦
bl cpu_init_crit
接着进入Linux内核启动阶段,这就像是探险者在森林里搭建营地,初始化各种资源。
c
// kernel/init/main.c
static int __init init_post(void)
{
// 执行init进程,就像在营地中安排第一个任务
if (execute_command) {
run_init_process(execute_command);
pr_info("Failed to execute %s. Attempting defaults...\n",
execute_command);
}
// 尝试执行默认的init程序,就像尝试不同的方法来完成任务
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
return 0;
}
然后是init进程启动,它就像营地的指挥官,解析init.rc
脚本,安排各种任务,启动Zygote进程。
c
// system/core/init/init.c
int main(int argc, char** argv) {
// 解析init.rc脚本,就像指挥官解读作战计划
if (!LoadBootScripts(uevent_context, &action_context, &service_list)) {
ERROR("Error loading init.rc.\n");
}
// 启动服务,就像指挥官下达作战命令
ActionForEach("early-init", action_context, NULL);
ActionForEach("init", action_context, NULL);
// 进入主循环,就像指挥官时刻关注着战场情况
EventLoop(uevent_context, &action_context, &service_list);
return 0;
}
最后是Zygote进程启动,它就像一个神奇的孵化器,预加载系统资源,为应用程序创建进程。
java
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
// 注册Zygote socket,就像打开一个通信的通道
registerZygoteSocket(socketName);
// 预加载类和资源,就像提前准备好各种工具
preloadClasses();
preloadResources();
// 启动Zygote服务,就像孵化器开始工作啦
if (enableLazyPreload) {
ZygoteServer.registerNewZygoteSocket(socketName);
}
// 进入Zygote主循环,时刻准备为新的应用进程服务
runSelectLoop(abiList);
}
二、四大组件的精彩表演
2.1 Activity的奇幻之旅
Activity就像是Android世界里的明星,有着自己独特的生命周期。它的生命周期方法调用流程就像是一场精彩的舞台剧,每一个环节都扣人心弦。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void performCreate(ActivityClientRecord r, Bundle savedInstanceState) {
// 调用Activity的attach方法,就像给明星穿上华丽的服装
r.activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
// 调用Activity的 onCreate方法,就像明星闪亮登场
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(r.activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(r.activity, r.state);
}
}
当Activity进入onStart
方法时,就像是明星开始在舞台上展示自己的风采。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void performStart(ActivityClientRecord r) {
// 调用Activity的 onStart方法
mInstrumentation.callActivityOnStart(r.activity);
// 标记Activity已经开始
r.activity.mStarted = true;
r.stopped = false;
}
而onResume
方法就像是明星达到了表演的高潮,吸引着观众的目光。
java
// frameworks/base/core/java/android/app/ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
boolean reallyResume, int seq, String reason) {
// 获取Activity实例
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
// 调用Activity的 onResume方法
mInstrumentation.callActivityOnResume(r.activity);
// 将Activity置于前台
if (r.window != null) {
r.window.getDecorView().setVisibility(View.VISIBLE);
}
}
}
当Activity进入onPause
方法时,就像是明星的表演暂时告一段落。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void performPause(ActivityClientRecord r, boolean saveState,
PendingTransactionActions pendingActions) {
// 调用Activity的 onPause方法
mInstrumentation.callActivityOnPause(r.activity);
// 标记Activity已经暂停
r.paused = true;
if (saveState) {
callCallActivityOnSaveInstanceState(r);
}
}
onStop
方法就像是明星离开了舞台,暂时消失在观众的视线中。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void performStop(ActivityClientRecord r, boolean saveState,
PendingTransactionActions pendingActions) {
// 调用Activity的 onStop方法
mInstrumentation.callActivityOnStop(r.activity);
// 标记Activity已经停止
r.stopped = true;
if (saveState) {
callCallActivityOnSaveInstanceState(r);
}
}
最后,onDestroy
方法就像是明星的表演彻底结束,一切都回归平静。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
// 获取Activity实例
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
// 调用Activity的 onDestroy方法
mInstrumentation.callActivityOnDestroy(r.activity);
// 移除Activity记录
mActivities.remove(token);
}
}
2.2 Service的幕后英雄
Service就像是Android世界里的幕后英雄,默默地在后台为我们提供各种服务。它有两种启动方式:startService
和bindService
。
2.2.1 startService启动方式
当我们使用startService
启动一个Service时,就像是给幕后英雄下达了一个任务。
java
// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
// 调用ActivityManager的startService方法
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()),
requireForeground,
getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service + " without permission " +
cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new IllegalStateException(
"Cannot start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
2.2.2 bindService启动方式
而bindService
启动方式就像是和幕后英雄建立了一种紧密的联系,可以随时和它沟通。
java
// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mUser);
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
// 调用ActivityManager的bindService方法
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
Service的生命周期也有它自己的特点,onCreate
方法就像是幕后英雄接到任务后开始准备工作。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void handleCreateService(CreateServiceData data) {
// 获取Service实例
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
// 调用Service的 onCreate方法
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
onStartCommand
方法就像是幕后英雄开始执行任务。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void handleServiceArgs(ServiceArgsData data) {
// 获取Service实例
Service s = mServices.get(data.token);
if (s != null) {
try {
int res;
if (!data.taskRemoved) {
// 调用Service的 onStartCommand方法
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_STICKY;
}
QueuedWork.waitToFinish();
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
onDestroy
方法就像是幕后英雄完成任务后休息。
java
// frameworks/base/core/java/android/app/ActivityThread.java
private void handleStopService(IBinder token) {
// 获取Service实例
Service s = mServices.get(token);
if (s != null) {
try {
// 调用Service的 onDestroy方法
s.onDestroy();
mServices.remove(token);
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to destroy service " + s + ": " + e.toString(), e);
}
}
try {
ActivityManager.getService().serviceDoneExecuting(
token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
2.3 BroadcastReceiver的消息使者
BroadcastReceiver就像是Android世界里的消息使者,负责传递各种消息。当我们发送一个广播时,就像是给消息使者下达了一个送信的任务。
java
// frameworks/base/core/java/android/content/ContextWrapper.java
@Override
public void sendBroadcast(Intent intent) {
mBase.sendBroadcast(intent);
}
// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
// 调用ActivityManager的broadcastIntent方法
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
当广播被接收到时,BroadcastReceiver
的onReceive
方法就会被调用,就像是消息使者把信送到了收件人手中。
java
// 自定义BroadcastReceiver类
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 处理接收到的广播消息
String action = intent.getAction();
if (action != null && action.equals("com.example.MY_BROADCAST")) {
Toast.makeText(context, "Received broadcast: " + action, Toast.LENGTH_SHORT).show();
}
}
}
2.4 ContentProvider的数据管家
ContentProvider就像是Android世界里的数据管家,负责管理和提供应用程序之间的数据共享。当我们查询数据时,就像是向数据管家询问一些信息。
java
// frameworks/base/core/java/android/content/ContentResolver.java
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
// 调用ContentProvider的query方法
qCursor = unstableProvider.query(mPackageName, uri, projection, selection,
selectionArgs, sortOrder, cancellationSignal);
if (qCursor == null) {
return null;
}
// 确保Cursor的类型正确
if (!qCursor.getNotificationUri().equals(uri)) {
qCursor.setNotificationUri(getContentResolver(), uri);
}
stableProvider = acquireProvider(uri);
if (stableProvider != null) {
if (qCursor instanceof CrossProcessCursor) {
((CrossProcessCursor) qCursor).setContentProvider(stableProvider);
}
}
} catch (RemoteException e) {
if (stableProvider != null) {
releaseProvider(stableProvider);
}
releaseUnstableProvider(unstableProvider);
throw e.rethrowFromSystemServer();
}
releaseUnstableProvider(unstableProvider);
if (stableProvider != null) {
qCursor.setExtras(stableProvider.call(mPackageName,
ContentProvider.METHOD_GET_EXTRAS, null, null));
releaseProvider(stableProvider);
}
return qCursor;
}
当我们插入数据时,就像是向数据管家存入一些物品。
java
// frameworks/base/core/java/android/content/ContentResolver.java
@Override
public Uri insert(Uri uri, ContentValues values) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
Uri result = null;
try {
// 调用ContentProvider的insert方法
result = unstableProvider.insert(mPackageName, uri, values);
} catch (RemoteException e) {
releaseUnstableProvider(unstableProvider);
throw e.rethrowFromSystemServer();
}
releaseUnstableProvider(unstableProvider);
return result;
}
当我们更新数据时,就像是对数据管家保管的物品进行修改。
java
// frameworks/base/core/java/android/content/ContentResolver.java
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return 0;
}
int count = 0;
try {
// 调用ContentProvider的update方法
count = unstableProvider.update(mPackageName, uri, values, selection, selectionArgs);
} catch (RemoteException e) {
releaseUnstableProvider(unstableProvider);
throw e.rethrowFromSystemServer();
}
releaseUnstableProvider(unstableProvider);
return count;
}
当我们删除数据时,就像是从数据管家那里拿走一些物品。
java
// frameworks/base/core/java/android/content/ContentResolver.java
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return 0;
}
int count = 0;
try {
// 调用ContentProvider的delete方法
count = unstableProvider.delete(mPackageName, uri, selection, selectionArgs);
} catch (RemoteException e) {
releaseUnstableProvider(unstableProvider);
throw e.rethrowFromSystemServer();
}
releaseUnstableProvider(unstableProvider);
return count;
}
三、性能优化的魔法秘籍
3.1 内存优化的神奇之旅
在Android开发中,内存优化就像是一场神奇的魔法之旅,我们要让应用程序在有限的内存空间里翩翩起舞。首先,我们要避免内存泄漏,这就像是要堵住魔法城堡里的漏洞,不让魔力(内存)泄漏出去。
java
// 错误示例:可能导致内存泄漏的单例模式
public class MySingleton {
private static MySingleton instance;
private Context context;
private MySingleton(Context context) {
this.context = context; // 这里如果传入的是Activity的Context,可能会导致内存泄漏
}
public static MySingleton getInstance(Context context) {
if (instance == null) {
instance = new MySingleton(context);
}
return instance;
}
}
// 正确示例:使用Application的Context
public class MySingleton {
private static MySingleton instance;
private Context context;
private MySingleton(Context context) {
this.context = context.getApplicationContext(); // 使用Application的Context,避免内存泄漏
}
public static MySingleton getInstance(Context context) {
if (instance == null) {
instance = new MySingleton(context);
}
return instance;
}
}
另外,我们还要合理使用数据结构,就像是选择合适的魔法道具一样。例如,在需要存储键值对的地方,我们可以根据具体情况选择HashMap
或者SparseArray
。
java
// 使用HashMap存储键值对
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "Apple");
hashMap.put(2, "Banana");
String value = hashMap.get(1);
// 使用SparseArray存储键值对,对于整数键的情况,SparseArray更节省内存
SparseArray<String> sparseArray = new SparseArray<>();
sparseArray.put(1, "Apple");
sparseArray.put(2, "Banana");
String value2 = sparseArray.get(1);
3.2 布局优化的艺术之美
布局优化就像是一场艺术创作,我们要让应用程序的界面既美观又高效。首先,我们要减少布局嵌套,就像是减少艺术品的层次,让它更加简洁。
xml
<!-- 错误示例:过多的布局嵌套 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="World" />
</LinearLayout>
</LinearLayout>
<!-- 正确示例:减少布局嵌套 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="World" />
</LinearLayout>
我们还可以使用include
标签来复用布局,就像是复制艺术品的一部分,提高创作效率。
xml
<!-- main_layout.xml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/header_layout" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Main content" />
</LinearLayout>
<!-- header_layout.xml -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Header" />
</LinearLayout>
3.3 电量优化的节能之道
电量优化就像是一场节能行动,我们要让应用程序在消耗最少电量的情况下完成任务。首先,我们要合理使用唤醒锁,就像是合理使用能源开关,避免不必要的电量消耗。
java
// 获取唤醒锁
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyApp:MyWakeLock");
wakeLock.acquire(); // 申请唤醒锁
// 在不需要时释放唤醒锁
if (wakeLock.isHeld()) {
wakeLock.release();
}
我们还可以使用JobScheduler
来安排后台任务,就像是合理安排工作时间,让应用程序在合适的时间执行任务,减少电量消耗。
java
// 创建JobInfo对象
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, new ComponentName(this, MyJobService.class))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) // 设置网络条件
.setPeriodic(15 * 60 * 1000) // 设置任务执行周期
.build();
// 获取JobScheduler实例
JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
// 调度任务
jobScheduler.schedule(jobInfo);
四、多线程与异步处理的精彩对决
4.1 Thread的冲锋陷阵
Thread就像是战场上的冲锋兵,勇往直前地执行任务。我们可以通过继承Thread
类来创建一个新的线程。
java
// 继承Thread类创建线程
class MyThread extends Thread {
@Override
public void run() {
// 线程要执行的任务
for (int i = 0; i < 10; i++) {
System.out.println("MyThread: " + i);
try {
Thread.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 在主线程中启动新线程
public class Main {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start(); // 启动线程
}
}
我们也可以通过实现Runnable
接口来创建线程,这样可以更好地实现代码的复用。
java
// 实现Runnable接口创建线程
class MyRunnable implements Runnable {
@Override
public void run() {
// 线程要执行的任务
for (int i = 0; i < 10; i++) {
System.out.println("MyRunnable: " + i);
try {
Thread.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 在主线程中启动新线程
public class Main {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start(); // 启动线程
}
}
4.2 Handler的消息传递
Handler就像是战场上的传令兵,负责在不同线程之间传递消息。我们可以在主线程中创建一个Handler,然后在子线程中通过Handler发送消息。
java
// 在主线程中创建Handler
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理接收到的消息
if (msg.what == 1) {
String data = (String) msg.obj;
System.out.println("Received message: " + data);
}
}
};
// 在子线程中发送消息
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000); // 线程休眠2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = Message.obtain();
message.what = 1;
message.obj = "Hello from child thread";
handler.sendMessage(message); // 发送消息
}
}).start();
4.3 AsyncTask的便捷助手
AsyncTask就像是战场上的便捷助手,它简化了异步任务的处理。我们可以通过继承AsyncTask
类来创建一个异步任务。
java
// 继承AsyncTask类创建异步任务
class MyAsyncTask extends AsyncTask<Void, Integer, String> {
@Override
protected void onPreExecute() {
// 在任务执行前的准备工作
System.out.println("Task started");
}
@Override
protected String doInBackground(Void... voids) {
// 后台执行的任务
for (int i = 0; i < 10; i++) {
publishProgress(i); // 发布进度
try {
Thread.sleep(1000); // 线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Task completed";
}
@Override
protected void onProgressUpdate(Integer... values) {
// 处理进度更新
System.out.println("Progress: " + values[0]);
}
@Override
protected void onPostExecute(String result) {
// 任务执行完成后的处理
System.out.println(result);
}
}
// 在主线程中执行异步任务
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
4.4 ExecutorService的高效指挥官
ExecutorService就像是战场上的高效指挥官,它可以管理线程池,提高线程的执行效率。我们可以通过Executors
类来创建不同类型的线程池。
java
// 创建固定大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
try {
Thread.sleep(2000); // 线程休眠2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskId + " is completed");
}
});
}
// 关闭线程池
executorService.shutdown();
五、Android安全的坚固防线
5.1 数据加密的秘密武器
在Android开发中,数据加密就像是为我们的数据穿上了一层坚固的铠甲,保护它不被窃取。我们可以使用Cipher
类来进行数据加密和解密。
java
byte[] decodedBytes = Base64.getDecoder().decode(encryptedText);
byte[] decryptedBytes = cipher.doFinal(decodedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
// 生成密钥
public static SecretKey generateKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(128); // 密钥长度为128位
return keyGenerator.generateKey();
}
public static void main(String[] args) {
try {
// 生成密钥
SecretKey secretKey = generateKey();
String plainText = "Hello, Android Security!";
// 加密数据
String encryptedText = encrypt(plainText, secretKey);
System.out.println("Encrypted Text: " + encryptedText);
// 解密数据
String decryptedText = decrypt(encryptedText, secretKey);
System.out.println("Decrypted Text: " + decryptedText);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在上述代码中,generateKey
方法用于生成一个 AES 加密所需的密钥。encrypt
方法接收明文和密钥,使用 Cipher
类以加密模式初始化,将明文转换为字节数组进行加密,最后使用 Base64 编码将加密后的字节数组转换为字符串。decrypt
方法则接收加密后的字符串和密钥,先将 Base64 编码的字符串解码为字节数组,再使用 Cipher
类以解密模式初始化,对字节数组进行解密,最终将解密后的字节数组转换为字符串。
5.2 权限管理的严格把关
Android 的权限管理就像是一扇大门的守卫,严格控制着应用对敏感信息和功能的访问。我们在 AndroidManifest.xml 中声明所需的权限。
xml
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<!-- 声明网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 声明读取外部存储权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
从 Android 6.0(API 级别 23)开始,部分危险权限需要在运行时动态请求。以下是一个动态请求读取外部存储权限的示例代码。
java
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 检查是否已经有读取外部存储的权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// 如果没有权限,请求权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSION_REQUEST_READ_EXTERNAL_STORAGE);
} else {
// 已经有权限,执行相应操作
Toast.makeText(this, "Already have read external storage permission", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_READ_EXTERNAL_STORAGE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户授予了权限,执行相应操作
Toast.makeText(this, "Read external storage permission granted", Toast.LENGTH_SHORT).show();
} else {
// 用户拒绝了权限
Toast.makeText(this, "Read external storage permission denied", Toast.LENGTH_SHORT).show();
}
}
}
}
在上述代码中,ContextCompat.checkSelfPermission
方法用于检查应用是否已经拥有指定的权限。如果没有权限,使用 ActivityCompat.requestPermissions
方法请求权限。onRequestPermissionsResult
方法用于处理权限请求的结果,根据用户的选择执行相应的操作。
5.3 代码混淆的隐身衣
代码混淆就像是给我们的代码穿上了一件隐身衣,让反编译者难以理解代码的逻辑。在 Android 开发中,我们可以使用 ProGuard 或 R8 进行代码混淆。
首先,在 build.gradle
文件中开启代码混淆。
groovy
android {
buildTypes {
release {
minifyEnabled true // 开启代码混淆
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
minifyEnabled true
表示开启代码混淆,proguardFiles
指定了混淆规则文件。proguard-android-optimize.txt
是 Android 提供的默认混淆规则文件,proguard-rules.pro
是我们自定义的混淆规则文件。
以下是一个简单的 proguard-rules.pro
文件示例。
scala
# 保留 AndroidManifest.xml 中声明的类
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
# 保留实现了特定接口的类
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
}
# 保留注解
-keepattributes *Annotation*
# 保留 native 方法
-keepclasseswithmembernames class * {
native <methods>;
}
在上述规则中,-keep
指令用于保留指定的类和成员,避免被混淆。例如,保留了 Android 四大组件、实现了 Parcelable
接口的类、注解和 native 方法等。
六、新特性与架构模式的前沿探索
6.1 Android Jetpack的强大助力
Android Jetpack 是一系列库、工具和指南的集合,旨在帮助开发者更轻松地构建高质量的 Android 应用。下面我们来看看几个常用的 Jetpack 组件。
6.1.1 ViewModel
ViewModel 用于存储和管理与 UI 相关的数据,并且在配置更改(如屏幕旋转)时保持数据的存活。以下是一个简单的 ViewModel 示例。
java
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
private int count = 0;
// 获取计数器的值
public int getCount() {
return count;
}
// 增加计数器的值
public void incrementCount() {
count++;
}
}
在 Activity 中使用 ViewModel。
java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private MyViewModel viewModel;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取 ViewModel 实例
viewModel = new ViewModelProvider(this).get(MyViewModel.class);
textView = findViewById(R.id.textView);
updateUI();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 增加计数器的值
viewModel.incrementCount();
updateUI();
}
});
}
// 更新 UI
private void updateUI() {
int count = viewModel.getCount();
textView.setText("Count: " + count);
}
}
在上述代码中,MyViewModel
类继承自 ViewModel
,用于存储和管理计数器的值。在 MainActivity
中,使用 ViewModelProvider
获取 MyViewModel
的实例,并且在点击按钮时更新计数器的值并刷新 UI。由于 ViewModel 在配置更改时保持存活,所以即使屏幕旋转,计数器的值也不会丢失。
6.1.2 LiveData
LiveData 是一种可观察的数据持有者类,它可以感知 Activity、Fragment 等组件的生命周期,确保数据的更新只在组件处于活跃状态时才会通知观察者。以下是一个使用 LiveData 的示例。
java
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
private MutableLiveData<Integer> countLiveData = new MutableLiveData<>();
public MyViewModel() {
// 初始化计数器的值
countLiveData.setValue(0);
}
// 获取 LiveData 对象
public LiveData<Integer> getCountLiveData() {
return countLiveData;
}
// 增加计数器的值
public void incrementCount() {
int currentCount = countLiveData.getValue() == null ? 0 : countLiveData.getValue();
countLiveData.setValue(currentCount + 1);
}
}
在 Activity 中观察 LiveData。
java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private MyViewModel viewModel;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取 ViewModel 实例
viewModel = new ViewModelProvider(this).get(MyViewModel.class);
textView = findViewById(R.id.textView);
// 观察 LiveData 的变化
viewModel.getCountLiveData().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer count) {
// 当 LiveData 的值发生变化时,更新 UI
textView.setText("Count: " + count);
}
});
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 增加计数器的值
viewModel.incrementCount();
}
});
}
}
在上述代码中,MyViewModel
类中的 countLiveData
是一个 MutableLiveData
对象,用于存储计数器的值。在 MainActivity
中,使用 observe
方法观察 countLiveData
的变化,当值发生变化时,会自动调用 onChanged
方法更新 UI。
6.1.3 Room
Room 是一个 SQLite 对象映射库,它提供了一种更简单、更安全的方式来操作 SQLite 数据库。以下是一个使用 Room 的示例。
首先,定义实体类。
java
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "users")
public class User {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
然后,定义 DAO(数据访问对象)接口。
java
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
@Dao
public interface UserDao {
// 插入用户数据
@Insert
void insert(User user);
// 查询所有用户数据
@Query("SELECT * FROM users")
List<User> getAllUsers();
}
接着,定义数据库类。
java
import androidx.room.Database;
import androidx.room.RoomDatabase;
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
最后,在 Activity 中使用 Room 数据库。
java
import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private AppDatabase database;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取数据库实例
database = AppDatabase.getInstance(this);
textView = findViewById(R.id.textView);
// 插入用户数据
User user = new User("John", 25);
new InsertUserTask().execute(user);
// 查询所有用户数据
new GetAllUsersTask().execute();
}
// 插入用户数据的异步任务
private class InsertUserTask extends AsyncTask<User, Void, Void> {
@Override
protected Void doInBackground(User... users) {
database.userDao().insert(users[0]);
return null;
}
}
// 查询所有用户数据的异步任务
private class GetAllUsersTask extends AsyncTask<Void, Void, List<User>> {
@Override
protected List<User> doInBackground(Void... voids) {
return database.userDao().getAllUsers();
}
@Override
protected void onPostExecute(List<User> users) {
StringBuilder stringBuilder = new StringBuilder();
for (User user : users) {
stringBuilder.append("Name: ").append(user.getName()).append(", Age: ").append(user.getAge()).append("\n");
}
textView.setText(stringBuilder.toString());
}
}
}
在上述代码中,User
类是一个实体类,使用 @Entity
注解标记为数据库表。UserDao
接口是数据访问对象,使用 @Dao
注解标记,定义了插入和查询数据的方法。AppDatabase
类是数据库类,使用 @Database
注解标记,指定了实体类和数据库版本。在 MainActivity
中,使用 AppDatabase.getInstance
方法获取数据库实例,通过异步任务插入和查询数据。
6.2 MVVM架构模式的魅力展现
MVVM(Model - View - ViewModel)架构模式是一种流行的 Android 应用架构模式,它将视图(View)和业务逻辑(ViewModel)分离,提高了代码的可维护性和可测试性。以下是一个简单的 MVVM 示例。
首先,定义 Model 层。
java
// 定义用户数据模型
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
然后,定义 ViewModel 层。
java
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class UserViewModel extends ViewModel {
private MutableLiveData<User> userLiveData = new MutableLiveData<>();
// 初始化用户数据
public void initUser() {
User user = new User("Alice", 30);
userLiveData.setValue(user);
}
// 获取用户数据的 LiveData 对象
public LiveData<User> getUserLiveData() {
return userLiveData;
}
}
接着,定义 View 层(Activity)。
java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private UserViewModel viewModel;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取 ViewModel 实例
viewModel = new ViewModelProvider(this).get(UserViewModel.class);
textView = findViewById(R.id.textView);
// 初始化用户数据
viewModel.initUser();
// 观察用户数据的变化
viewModel.getUserLiveData().observe(this, new Observer<User>() {
@Override
public void onChanged(User user) {
// 当用户数据发生变化时,更新 UI
textView.setText("Name: " + user.getName() + ", Age: " + user.getAge());
}
});
}
}
在上述代码中,User
类是 Model 层,用于存储用户数据。UserViewModel
类是 ViewModel 层,使用 LiveData
来存储和管理用户数据,并且提供了初始化用户数据和获取用户数据的方法。MainActivity
是 View 层,通过 ViewModelProvider
获取 UserViewModel
的实例,观察 UserLiveData
的变化,当数据发生变化时更新 UI。通过这种方式,实现了视图和业务逻辑的分离。
七、总结与展望
7.1 总结
通过对 Android 大厂面试相关技术的深入剖析,我们全面了解了 Android 开发的各个方面。从 Android 系统的基础架构和启动流程,我们明白了系统的底层原理和运行机制,这为我们开发出更稳定、高效的应用奠定了基础。四大组件作为 Android 应用的核心,它们各自有着独特的生命周期和使用场景,合理运用它们可以构建出功能丰富、交互流畅的应用。
在性能优化方面,我们学习了内存优化、布局优化和电量优化的方法和技巧。内存优化可以避免应用出现内存泄漏和内存溢出的问题,提高应用的稳定性;布局优化可以减少布局嵌套,提高界面的加载速度;电量优化可以降低应用的电量消耗,提升用户体验。
多线程与异步处理让我们能够在应用中高效地处理耗时任务,避免阻塞主线程,保证应用的流畅性。安全方面,数据加密、权限管理和代码混淆等技术为我们的数据和应用提供了可靠的保护。
新特性和架构模式的探索,如 Android Jetpack 和 MVVM 架构模式,让我们能够跟上技术发展的步伐,使用更先进的工具和方法来开发应用,提高开发效率和代码质量。
7.2 展望
随着技术的不断发展,Android 开发领域也在不断演进。未来,我们可以期待更多创新的技术和特性出现在 Android 系统中。例如,人工智能和机器学习技术在 Android 应用中的应用将越来越广泛,我们可以利用这些技术实现图像识别、语音交互、智能推荐等功能,为用户带来更加智能、便捷的体验。
同时,随着 5G 技术的普及,Android 应用的网络性能将得到极大提升,我们可以开发出更加流畅、实时的在线应用,如高清视频直播、多人在线游戏等。
在架构模式方面,可能会出现更加先进、灵活的架构模式,进一步提高代码的可维护性和可扩展性。而且,随着跨平台开发技术的发展,Android 开发可能会与其他平台的开发更加融合,开发者可以使用一套代码同时开发 Android 和 iOS 等多个平台的应用。
作为 Android 开发者,我们需要不断学习和掌握新的技术和知识,紧跟技术发展的潮流,才能在激烈的竞争中脱颖而出,开发出更加优秀的 Android 应用,为用户带来更好的体验。