四大组件-Activity

一、Activity 架构设计理念

1.1 设计思想与定位

Activity 作为 Android 四大组件之首,体现了 Google 对移动应用交互的深刻理解:

核心设计理念:

  • 单一屏幕原则:每个 Activity 代表一个完整的用户交互界面
  • 组合优于继承:通过 Intent 机制实现松耦合的组件通信
  • 生命周期感知:系统统一管理,开发者只需关注状态回调
  • 任务栈导航:符合用户心理模型的"返回"体验

在 MVC/MVP/MVVM 中的角色:

java 复制代码
// 传统 MVC 中 Activity 扮演 Controller 角色
public class UserActivity extends Activity {
    // View
    private TextView mUserNameText;
    // Model  
    private UserModel mUserModel;
    
    // Controller 逻辑
    private void updateUserInfo() {
        String name = mUserModel.getName();
        mUserNameText.setText(name); // 更新 View
    }
}

// 现代架构中 Activity 作为 View 层
public class UserActivity extends AppCompatActivity {
    private UserViewModel mViewModel;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mViewModel = new ViewModelProvider(this).get(UserViewModel.class);
        
        // 观察数据变化
        mViewModel.getUserLiveData().observe(this, user -> {
            updateUI(user); // 响应式更新
        });
    }
}

二、Activity 底层机制剖析

2.1 ActivityThread 与 AMS 的交互

启动流程深度解析:

java 复制代码
// 1. 应用进程内部流程
class ActivityThread {
    // 主消息循环
    final H mH = new H();
    
    private class H extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY:
                    handleLaunchActivity(msg); // 创建并启动 Activity
                    break;
                case RESUME_ACTIVITY:
                    handleResumeActivity(msg); // 恢复 Activity
                    break;
            }
        }
    }
    
    private void handleLaunchActivity(ActivityClientRecord r) {
        // 1. 创建 Activity 实例
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(cl, r.activityInfo.name, r.intent);
        } catch (Exception e) {
            // 反射创建失败处理
        }
        
        // 2. 调用 attach 方法
        activity.attach(appContext, this, getInstrumentation(), r.token,
                r.ident, app, r.intent, r.activityInfo, ...);
        
        // 3. 调用 onCreate
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
}

// 2. 系统服务端流程
class ActivityManagerService {
    public final int startActivity(IApplicationThread caller, ...) {
        // 权限检查、进程管理、任务栈管理
        return startActivityAsUser(caller, ..., UserHandle.getCallingUserId());
    }
    
    private int startActivityAsUser(IApplicationThread caller, ...) {
        // 解析 Intent、验证目标 Activity
        // 处理启动模式、任务栈调整
        // 通知目标进程创建 Activity
    }
}

2.2 Window 与 View 系统的桥梁

Activity 的窗口管理机制:

java 复制代码
public class Activity extends ContextThemeWrapper {
    private Window mWindow;
    private WindowManager mWindowManager;
    
    // Activity 与 Window 的关联
    public void attach(Context context, ...) {
        // 创建 PhoneWindow
        mWindow = new PhoneWindow(this, windowToken);
        mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString());
        
        mWindowManager = mWindow.getWindowManager();
    }
    
    // 设置内容视图的完整流程
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar(); // 初始化 ActionBar
    }
}

// PhoneWindow 内部实现
public class PhoneWindow extends Window {
    private DecorView mDecor;
    
    @Override
    public void setContentView(int layoutResID) {
        // 1. 确保 DecorView 存在
        if (mDecor == null) {
            installDecor();
        }
        
        // 2. 将用户布局添加到 contentParent
        View in = mLayoutInflater.inflate(layoutResID, null);
        mContentParent.addView(in, ...);
    }
    
    private void installDecor() {
        if (mDecor == null) {
            // 创建根视图 DecorView
            mDecor = generateDecor(-1);
        }
        
        if (mContentParent == null) {
            // 创建内容容器
            mContentParent = generateLayout(mDecor);
        }
    }
}

三、启动模式的底层实现

3.1 任务栈管理机制

ActivityStack 与 TaskRecord:

java 复制代码
// 系统服务中的栈管理
class ActivityStack {
    final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
    
    // 根据启动模式查找或创建 Activity
    ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
        // singleTask 查找逻辑
        if (launchMode == LAUNCH_SINGLE_TASK) {
            // 查找匹配的 TaskRecord
            TaskRecord task = findTaskLocked(intent, info);
            if (task != null) {
                // 清理栈顶 Activity
                task.performClearTaskLocked();
                return task.getTopActivity();
            }
        }
        
        // singleTop 栈顶复用逻辑
        if (launchMode == LAUNCH_SINGLE_TOP) {
            ActivityRecord top = topRunningActivityLocked();
            if (top != null && top.realActivity.equals(component)) {
                return top; // 复用栈顶实例
            }
        }
        
        return null; // 需要创建新实例
    }
}

// 任务记录
class TaskRecord {
    final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
    int taskId; // 任务ID
    String affinity; // 任务亲和性
    
    // 清理任务栈
    void performClearTaskLocked() {
        // 移除所有位于目标 Activity 之上的 Activity
        for (int i = mActivities.size() - 1; i >= 0; i--) {
            ActivityRecord r = mActivities.get(i);
            if (r == targetActivity) break;
            r.finishIfPossible();
        }
    }
}

3.2 Intent Flag 的优先级与冲突解决

Flag 处理策略:

java 复制代码
class ActivityStarter {
    private int computeLaunchingTaskFlags() {
        // Intent Flags 覆盖 Manifest 设置
        if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0) {
            // 强制在新任务中启动
            launchFlags |= FLAG_ACTIVITY_NEW_TASK;
        }
        
        // 解决 Flag 冲突
        if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            if ((launchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
                // 总是创建新任务
            } else {
                // 查找现有任务
            }
        }
    }
}

四、生命周期的状态机模型

4.1 完整状态转换图

java 复制代码
// Activity 生命周期状态机
enum ActivityState {
    INITIALIZING,   // 初始状态
    CREATED,        // onCreate 完成
    STARTED,        // onStart 完成  
    RESUMED,        // onResume 完成
    PAUSING,        // onPause 执行中
    PAUSED,         // onPause 完成
    STOPPING,       // onStop 执行中
    STOPPED,        // onStop 完成
    DESTROYING,     // onDestroy 执行中
    DESTROYED       // onDestroy 完成
}

// 状态转换控制器
class ActivityLifecycleController {
    private ActivityState mCurrentState = ActivityState.INITIALIZING;
    
    void moveToState(ActivityState newState) {
        switch (mCurrentState) {
            case INITIALIZING:
                if (newState == ActivityState.CREATED) {
                    callOnCreate();
                    mCurrentState = ActivityState.CREATED;
                }
                break;
            case CREATED:
                if (newState == ActivityState.STARTED) {
                    callOnStart();
                    mCurrentState = ActivityState.STARTED;
                } else if (newState == ActivityState.DESTROYED) {
                    callOnDestroy();
                    mCurrentState = ActivityState.DESTROYED;
                }
                break;
            // 其他状态转换...
        }
    }
}

4.2 配置变化时的状态保存与恢复

View 状态保存机制:

java 复制代码
public class Activity {
    // 状态保存入口
    protected void onSaveInstanceState(Bundle outState) {
        // 1. 保存 Activity 级别状态
        outState.putString("key", value);
        
        // 2. 委托 Window 保存视图状态
        mWindow.saveHierarchyState();
    }
}

class PhoneWindow {
    void saveHierarchyState() {
        // 遍历视图树,保存有 id 的视图状态
        SparseArray<Parcelable> states = new SparseArray<>();
        mDecor.saveHierarchyState(states);
        
        // 存储到 Bundle
        outState.putSparseParcelableArray(WINDOW_HIERARCHY_TAG, states);
    }
}

public class View {
    public void saveHierarchyState(SparseArray<Parcelable> container) {
        // 保存自身状态
        if (mID != NO_ID) {
            container.put(mID, onSaveInstanceState());
        }
        
        // 递归保存子视图状态
        for (int i = 0; i < getChildCount(); i++) {
            getChildAt(i).saveHierarchyState(container);
        }
    }
    
    protected Parcelable onSaveInstanceState() {
        // 视图子类重写此方法保存特定状态
        // 如 EditText 的文本、CheckBox 的选中状态等
        return new BaseSavedState(super.onSaveInstanceState());
    }
}

五、性能优化深度策略

5.1 启动性能优化

冷启动优化全流程:

java 复制代码
public class MainActivity extends Activity {
    // 1. 主题优化:使用启动主题避免白屏
    // styles.xml
    // <style name="AppTheme.Launcher">
    //     <item name="android:windowBackground">@drawable/launch_background</item>
    // </style>
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 2. 在 super.onCreate 前恢复主题
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
        
        // 3. 异步初始化策略
        initAsync();
        
        // 4. 延迟初始化非关键组件
        getWindow().getDecorView().post(() -> {
            initHeavyComponents(); // 在首帧渲染后执行
        });
    }
    
    private void initAsync() {
        // 使用 IntentService 或线程池初始化第三方 SDK
        Executors.newSingleThreadExecutor().execute(() -> {
            // 后台初始化
            ThirdPartySDK.init();
            
            // 完成后通知主线程
            runOnUiThread(() -> {
                onAsyncInitComplete();
            });
        });
    }
}

// 5. 启动器模式优化
class AppStartupManager {
    public void optimizeStartup() {
        // 使用 ContentProvider 自动初始化 (慎重使用)
        // 使用 App Startup 库统一管理初始化顺序
    }
}

5.2 内存泄漏防护体系

常见泄漏场景与解决方案:

java 复制代码
public class SafeActivity extends AppCompatActivity {
    // 场景1:静态引用泄漏
    private static Context sLeakedContext;
    private static WeakReference<Context> sSafeContext;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 错误做法
        sLeakedContext = this; // 内存泄漏!
        
        // 正确做法
        sSafeContext = new WeakReference<>(this);
    }
    
    // 场景2:Handler 泄漏
    private final Handler mLeakyHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // 隐式持有 Activity 引用
        }
    };
    
    // 安全 Handler
    private static class SafeHandler extends Handler {
        private final WeakReference<SafeActivity> mActivity;
        
        SafeHandler(SafeActivity activity) {
            mActivity = new WeakReference<>(activity);
        }
        
        @Override
        public void handleMessage(Message msg) {
            SafeActivity activity = mActivity.get();
            if (activity != null && !activity.isFinishing()) {
                activity.handleSafeMessage(msg);
            }
        }
    }
    
    // 场景3:匿名内部类泄漏
    private void setupListeners() {
        // 错误做法:匿名内部类隐式持有外部类引用
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 可能造成泄漏
            }
        });
        
        // 正确做法:使用静态类或方法引用
        mButton.setOnClickListener(this::onButtonClick);
    }
    
    private void onButtonClick(View v) {
        // 安全的点击处理
    }
    
    @Override
    protected void onDestroy() {
        // 清理资源
        mHandler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }
}

六、高级应用场景

6.1 多窗口模式适配

分屏与画中画处理:

java 复制代码
public class MultiWindowActivity extends Activity {
    private boolean mIsInMultiWindowMode;
    private boolean mIsInPictureInPictureMode;
    
    @Override
    public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
        super.onMultiWindowModeChanged(isInMultiWindowMode);
        mIsInMultiWindowMode = isInMultiWindowMode;
        
        // 调整 UI 布局
        adjustLayoutForMultiWindow(isInMultiWindowMode);
        
        // 暂停/恢复后台任务
        if (isInMultiWindowMode) {
            pauseNonCriticalTasks();
        } else {
            resumeNonCriticalTasks();
        }
    }
    
    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
        super.onPictureInPictureModeChanged(isInPictureInPictureMode);
        mIsInPictureInPictureMode = isInPictureInPictureMode;
        
        if (isInPictureInPictureMode) {
            // 简化 UI,只保留核心内容
            enterPictureInPictureMode();
        } else {
            // 恢复完整 UI
            exitPictureInPictureMode();
        }
    }
    
    // 配置画中画参数
    private void enterPictureInPictureMode() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            PictureInPictureParams params = new PictureInPictureParams.Builder()
                .setAspectRatio(new Rational(16, 9))
                .setSourceRectHint(getSourceRectHint())
                .setActions(getPipActions())
                .build();
            enterPictureInPictureMode(params);
        }
    }
}

6.2 动态特性模块

按需加载 Activity:

java 复制代码
public class DynamicFeatureActivity extends Activity {
    private SplitInstallManager mSplitInstallManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSplitInstallManager = SplitInstallManagerFactory.create(this);
        
        // 检查特性是否已安装
        checkFeatureAvailability();
    }
    
    private void checkFeatureAvailability() {
        if (mSplitInstallManager.getInstalledModules().contains("premium_feature")) {
            // 特性已安装,直接启动
            launchPremiumFeature();
        } else {
            // 请求安装特性模块
            requestFeatureInstall();
        }
    }
    
    private void requestFeatureInstall() {
        SplitInstallRequest request = SplitInstallRequest.newBuilder()
            .addModule("premium_feature")
            .build();
            
        mSplitInstallManager.startInstall(request)
            .addOnSuccessListener(sessionId -> {
                // 安装成功
                launchPremiumFeature();
            })
            .addOnFailureListener(exception -> {
                // 安装失败处理
                handleInstallFailure(exception);
            });
    }
}

七、测试与调试

7.1 生命周期测试策略

自动化测试框架:

java 复制代码
@RunWith(AndroidJUnit4.class)
public class ActivityLifecycleTest {
    @Rule
    public ActivityScenarioRule<MainActivity> rule = 
        new ActivityScenarioRule<>(MainActivity.class);
    
    @Test
    public void testConfigurationChange() {
        // 模拟配置变化
        ActivityScenario<MainActivity> scenario = rule.getScenario();
        
        // 验证状态保存
        onView(withId(R.id.edit_text)).perform(typeText("test"));
        
        // 旋转设备
        scenario.recreate();
        
        // 验证状态恢复
        onView(withId(R.id.edit_text)).check(matches(withText("test")));
    }
    
    @Test
    public void testLowMemoryScenario() {
        // 模拟低内存情况
        ActivityScenario<MainActivity> scenario = rule.getScenario();
        
        scenario.onActivity(activity -> {
            // 触发 onTrimMemory
            activity.getApplication().onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
            
            // 验证资源正确释放
            assertTrue(activity.areResourcesReleased());
        });
    }
}

7.2 性能监控工具

自定义性能监控:

java 复制代码
public class PerformanceMonitor {
    private long mActivityCreateTime;
    private long mActivityResumeTime;
    
    public void onActivityCreate() {
        mActivityCreateTime = System.currentTimeMillis();
    }
    
    public void onActivityResume() {
        mActivityResumeTime = System.currentTimeMillis();
        long startupTime = mActivityResumeTime - mActivityCreateTime;
        
        // 记录启动时间
        Log.d("Performance", "Activity startup: " + startupTime + "ms");
        
        // 上传到监控平台
        uploadMetrics(startupTime);
    }
    
    // 监控内存使用
    private void monitorMemoryUsage() {
        Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
        Debug.getMemoryInfo(memoryInfo);
        
        long totalPss = memoryInfo.getTotalPss();
        if (totalPss > MEMORY_THRESHOLD) {
            // 内存使用过高警告
            reportMemoryWarning(totalPss);
        }
    }
}

八、未来演进趋势

8.1 Jetpack Compose 的影响

kotlin 复制代码
// Compose 时代的 Activity 角色转变
class ComposeActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Activity 退化为纯粹的容器
        setContent {
            MyAppTheme {
                // 整个 UI 由 Composable 函数构建
                MainScreen(
                    onItemClick = { item ->
                        // 导航逻辑
                        navigateToDetail(item)
                    }
                )
            }
        }
    }
    
    private fun navigateToDetail(item: Item) {
        // 仍然使用 Activity 进行页面跳转
        val intent = Intent(this, DetailActivity::class.java)
        startActivity(intent)
    }
}

8.2 响应式架构的普及

java 复制代码
// 完全的响应式 Activity
public class ReactiveActivity extends AppCompatActivity {
    private final CompositeDisposable mDisposables = new CompositeDisposable();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 响应式数据绑定
        mDisposables.add(
            RxView.clicks(mButton)
                .throttleFirst(500, TimeUnit.MILLISECONDS)
                .flatMap(click -> apiService.loadData())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(data -> updateUI(data), this::handleError)
        );
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mDisposables.clear(); // 自动管理生命周期
    }
}

总结

Activity 作为 Android 应用开发的基石,经历了多年的演进但核心地位不变。深度理解其内部机制、生命周期管理、性能优化策略,对于构建高质量 Android 应用至关重要。随着新技术栈的出现,Activity 的角色正在从"全能控制器"向"生命周期容器"转变,但其作为用户交互入口的核心价值依然不可替代。

开发者应该:

  1. 掌握底层原理:理解 ActivityThread、Window 系统等底层机制
  2. 精通状态管理:熟练处理各种场景下的生命周期和状态恢复
  3. 注重性能体验:优化启动速度,防止内存泄漏
  4. 拥抱架构演进:适应 Compose、响应式编程等新技术趋势
  5. 强化测试保障:建立完善的生命周期测试体系

Android Activity 面试题详解

一、Activity 基础概念

  1. 什么是 Activity?它在 Android 中扮演什么角色?
  • Activity 是 Android 四大组件之一,是用户交互的入口点
  • 它代表一个具有用户界面的单一屏幕,负责处理用户交互
  • 每个 Activity 都有其生命周期,系统通过回调方法管理生命周期状态
  • Activity 通过 setContentView() 方法加载布局文件来展示 UI
  1. Activity 的生命周期
java 复制代码
// 1. onCreate() - Activity 首次创建时调用
// 用于初始化工作:加载布局、绑定数据、初始化变量
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

// 2. onStart() - Activity 变为可见但还未进入前台
@Override
protected void onStart() {
    super.onStart();
}

// 3. onResume() - Activity 进入前台,可与用户交互
@Override
protected void onResume() {
    super.onResume();
}

// 4. onPause() - Activity 失去焦点,但部分可见
// 用于暂停动画、释放相机等占用资源
@Override
protected void onPause() {
    super.onPause();
}

// 5. onStop() - Activity 完全不可见
@Override
protected void onStop() {
    super.onStop();
}

// 6. onRestart() - 从停止状态重新启动
@Override
protected void onRestart() {
    super.onRestart();
}

// 7. onDestroy() - Activity 被销毁前调用
@Override
protected void onDestroy() {
    super.onDestroy();
}

二、Activity 启动模式深度解析

  1. 四种启动模式及其应用场景

standard(标准模式)

  • 特点:每次启动都创建新实例,遵循"后进先出"原则
  • 任务栈:新 Activity 放入启动它的任务栈

singleTop(栈顶复用模式)

  • 特点:目标 Activity 在栈顶时复用实例,调用 onNewIntent()
  • 任务栈:检查栈顶,不在栈顶时行为同 standard
  • 应用场景:
java 复制代码
// 防止重复点击创建多个相同页面
// 通知跳转、搜索页面等
<activity 
    android:name=".SearchActivity"
    android:launchMode="singleTop"/>

singleTask(栈内复用模式)

  • 特点:在整个任务栈中保持唯一实例,清除其上所有 Activity
  • 任务栈:创建新任务栈或寻找 affinity 匹配的栈
  • 应用场景:
java 复制代码
// 应用主页、登录页等入口页面
<activity 
    android:name=".MainActivity"
    android:launchMode="singleTask"
    android:taskAffinity="com.example.app.main"/>

singleInstance(单实例模式)

  • 特点:独占一个任务栈,栈中只有该 Activity
  • 任务栈:完全隔离的任务栈
  • 应用场景:
java 复制代码
// 来电接听、系统Launcher等需要完全隔离的场景
<activity 
    android:name=".CallActivity"
    android:launchMode="singleInstance"/>
  1. taskAffinity 是什么?它与 singleTask 有什么关系?
  • 定义:Activity 的归属倾向,默认与应用包名相同
  • 作用:指定 Activity 希望运行在哪个任务栈中
xml 复制代码
<!-- 当启动 singleTask Activity 时,系统会寻找匹配 affinity 的任务栈 -->
<activity 
    android:name=".ShareActivity"
    android:launchMode="singleTask"
    android:taskAffinity="com.example.share"/>

与 singleTask 关系:

  • 必须一起用吗? 不是必须的。
  • 可以单独使用 taskAffinity(通常与其他属性如 allowTaskReparenting 配合)。
  • 也可以单独使用 singleTask(它会使用默认的 taskAffinity,在当前应用栈内实现单例效果)。
  • 但当你希望一个 singleTask Activity 一定运行在一个独立的任务栈中时,你就必须为它指定一个与默认值不同的 taskAffinity。在这种情况下,它们是"黄金搭档"。
  1. Intent Flag 如何影响 Activity 启动行为?
java 复制代码
// 常用 Flag 组合
Intent intent = new Intent(this, TargetActivity.class);

// 场景1:清除任务栈并创建新实例
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 
                Intent.FLAG_ACTIVITY_CLEAR_TASK);

// 场景2:如果存在则提到前台,否则新建
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 
                Intent.FLAG_ACTIVITY_CLEAR_TOP);

// 场景3:单例模式(类似 singleTop)
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

// 场景4:不保留历史记录
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

三、生命周期场景分析

  1. 场景:Activity A 启动 Activity B,然后按返回键
css 复制代码
A onCreate → A onStart → A onResume
→ (点击启动B) A onPause 
→ B onCreate → B onStart → B onResume 
→ A onStop
→ (按返回键) B onPause 
→ A onRestart → A onStart → A onResume 
→ B onStop → B onDestroy
  1. 屏幕旋转时生命周期如何变化?如何保存数据?
java 复制代码
public class MainActivity extends Activity {
    private static final String KEY_DATA = "data";
    private String mImportantData;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 恢复数据
        if (savedInstanceState != null) {
            mImportantData = savedInstanceState.getString(KEY_DATA);
        }
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // 保存数据
        outState.putString(KEY_DATA, mImportantData);
    }
    
    // 或者使用 ViewModel + LiveData 更好的解决方案
}

四、数据传递与通信

  1. Activity 之间如何传递数据?
java 复制代码
// 方法1:Intent 传递基本数据
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra("key_string", "value");
intent.putExtra("key_int", 100);
intent.putExtra("key_boolean", true);
startActivity(intent);

// 接收数据
String value = getIntent().getStringExtra("key_string");

// 方法2:传递对象(实现 Parcelable 或 Serializable)
public class User implements Parcelable {
    private String name;
    private int age;
    
    // Parcelable 实现...
}

// 方法3:使用 Activity Result API(推荐)
private final ActivityResultLauncher<Intent> mGetContent = 
    registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
        result -> {
            if (result.getResultCode() == RESULT_OK) {
                Intent data = result.getData();
                // 处理返回数据
            }
        });
  1. startActivity() 和 startActivityForResult() 有什么区别?
  • startActivity():单向启动,不需要返回结果

  • startActivityForResult():启动并期望返回结果(已过时)

  • 新的 Activity Result API:

    java 复制代码
    // 注册结果回调
    private ActivityResultLauncher<Intent> launcher = 
        registerForActivityResult(new StartActivityForResult(), 
            result -> {
                if (result.getResultCode() == RESULT_OK) {
                    // 处理结果
                }
            });
    
    // 启动
    launcher.launch(new Intent(this, TargetActivity.class));

五、任务栈与回退栈

  1. 什么是任务栈(Task)?它与进程有什么区别?
  • 任务栈:包含一系列 Activity 的栈结构,遵循用户导航体验
  • 进程:应用的运行实例,可以包含多个任务栈

区别:

  • 任务栈是逻辑概念,进程是物理概念
  • 一个进程可以包含多个任务栈
  • 任务栈可以跨进程(不同应用的 Activity 可在同一任务栈)
  1. 如何配置 Activity 在最近任务列表中的显示?
xml 复制代码
<activity
    android:name=".SensitiveActivity"
    android:excludeFromRecents="true" <!-- 不在最近任务中显示 -->
    android:taskAffinity=""
    android:launchMode="singleInstance"/>

六、高级话题与最佳实践

  1. 如何处理 Activity 内存泄漏?
java 复制代码
public class MainActivity extends Activity {
    // 错误示例:静态引用 Activity 上下文
    private static Context sContext;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 错误做法
        sContext = this;
        
        // 正确做法:使用 Application Context
        sContext = getApplicationContext();
    }
    
    // 异步任务导致的内存泄漏
    private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        // 隐式持有 Activity 引用
        
        @Override
        protected Void doInBackground(Void... voids) {
            // 长时间运行的任务
            return null;
        }
        
        // 解决方案:使用静态内部类 + 弱引用
    }
    
    // 使用弱引用的正确实现
    private static class SafeAsyncTask extends AsyncTask<Void, Void, Void> {
        private WeakReference<MainActivity> mActivityRef;
        
        SafeAsyncTask(MainActivity activity) {
            mActivityRef = new WeakReference<>(activity);
        }
        
        @Override
        protected Void doInBackground(Void... voids) {
            MainActivity activity = mActivityRef.get();
            if (activity != null && !activity.isFinishing()) {
                // 使用 activity
            }
            return null;
        }
    }
}
  1. Activity 与 Fragment 如何通信?
java 复制代码
// 方法1:接口回调(推荐)
public interface OnItemClickListener {
    void onItemClick(String item);
}

public class MainActivity extends Activity implements OnItemClickListener {
    @Override
    public void onItemClick(String item) {
        // 处理 Fragment 的回调
    }
}

// 方法2:ViewModel(现代方式)
public class SharedViewModel extends ViewModel {
    private final MutableLiveData<String> selectedItem = new MutableLiveData<>();
    
    public void selectItem(String item) {
        selectedItem.setValue(item);
    }
    
    public LiveData<String> getSelectedItem() {
        return selectedItem;
    }
}

// Activity 和 Fragment 共享同一个 ViewModel
SharedViewModel model = new ViewModelProvider(this).get(SharedViewModel.class);
  1. 如何实现 Activity 的懒加载?
java 复制代码
public abstract class LazyFragment extends Fragment {
    private boolean isViewCreated = false;
    private boolean isFirstLoad = true;
    
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        isViewCreated = true;
        tryLoadData();
    }
    
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        tryLoadData();
    }
    
    private void tryLoadData() {
        if (getUserVisibleHint() && isViewCreated && isFirstLoad) {
            loadData();
            isFirstLoad = false;
        }
    }
    
    protected abstract void loadData();
}

七、实际场景问题

  1. 应用在后台被杀死,重启时如何恢复状态?
java 复制代码
public class MainActivity extends AppCompatActivity {
    private static final String KEY_USER_DATA = "user_data";
    private UserData mUserData;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        if (savedInstanceState != null) {
            // 从 savedInstanceState 恢复
            mUserData = (UserData) savedInstanceState.getSerializable(KEY_USER_DATA);
        } else {
            // 正常初始化
            mUserData = new UserData();
        }
        
        // 使用 ViewModel 更好的处理配置变化
        MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class);
    }
    
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putSerializable(KEY_USER_DATA, mUserData);
    }
}
  1. 如何实现深链接(Deep Link)?
xml 复制代码
<activity android:name=".ProductActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="example.com"
            android:pathPrefix="/product"
            android:scheme="https" />
    </intent-filter>
</activity>
java 复制代码
public class ProductActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 处理深链接
        Intent intent = getIntent();
        if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
            Uri data = intent.getData();
            if (data != null) {
                String productId = data.getQueryParameter("id");
                loadProduct(productId);
            }
        }
    }
}
相关推荐
xiangpanf7 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
robotx10 小时前
安卓线程相关
android
消失的旧时光-194310 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon11 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon11 小时前
VSYNC 信号完整流程2
android
dalancon11 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户693717500138412 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android13 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才13 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶14 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle