四大组件-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);
            }
        }
    }
}
相关推荐
aqi001 小时前
FFmpeg开发笔记(九十二)基于Kotlin的开源Android推流器StreamPack
android·ffmpeg·kotlin·音视频·直播·流媒体
Aileen_0v04 小时前
【Gemini3.0的国内use教程】
android·人工智能·算法·开源·mariadb
浩浩的代码花园4 小时前
自研端侧推理模型实测效果展示
android·深度学习·计算机视觉·端智能
踢球的打工仔11 小时前
PHP面向对象(7)
android·开发语言·php
安卓理事人11 小时前
安卓socket
android
安卓理事人17 小时前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学18 小时前
Android M3U8视频播放器
android·音视频
q***577418 小时前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober19 小时前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android