全部笔记All notes

Android Activity生命周期与组件通信完全指南

阅读 12m 29s12m 29s read

概述

Activity是Android应用的核心组件之一,代表一个用户界面。每个Activity都是一个独立的屏幕,用户可以与之交互。理解Activity的生命周期和组件通信机制是Android开发的基础。

学习目标

  • 掌握Activity完整生命周期
  • 理解Activity的启动模式
  • 熟练使用Intent进行组件通信
  • 掌握数据传递的各种方式
  • 了解Jetpack Navigation组件
  • 掌握Activity性能优化技巧

Activity基础

Activity是什么?

Activity是Android四大组件之一,提供了一个用户可以交互的屏幕。每个Activity都是android.app.Activity类的子类。

// Java实现
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
// Kotlin实现
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

在清单文件中注册

每个Activity都必须在AndroidManifest.xml中注册:

<manifest ...>
    <application ...>
        <activity 
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.MyApp">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <activity 
            android:name=".SecondActivity"
            android:exported="false"
            android:parentActivityName=".MainActivity" />
    </application>
</manifest>

生命周期详解

生命周期方法

Activity的生命周期由一系列的回调方法组成,这些方法在Activity的不同状态之间转换时被调用。

完整生命周期流程图

[启动Activity]
      ↓
  onCreate()    ← 创建Activity
      ↓
  onStart()     ← Activity即将可见
      ↓
  onResume()    ← Activity获得焦点,可交互
      ↓
[Activity运行中]
      ↓
  onPause()     ← Activity失去焦点
      ↓
  onStop()      ← Activity不可见
      ↓
  onDestroy()   ← Activity销毁
      ↓
[Activity结束]

生命周期状态详解

状态描述特点
创建(Created)Activity被创建但不可见执行初始化操作
启动(Started)Activity可见但不在前台用户可以看到界面
恢复(Resumed)Activity在前台且可交互用户可以操作
暂停(Paused)Activity部分可见失去焦点但仍可见
停止(Stopped)Activity完全不可见被其他Activity覆盖
销毁(Destroyed)Activity被销毁释放所有资源

生命周期方法实现

// Java完整实现
public class LifecycleActivity extends AppCompatActivity {
    private static final String TAG = "LifecycleActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate: Activity创建");
        setContentView(R.layout.activity_lifecycle);
        
        // 恢复保存的状态
        if (savedInstanceState != null) {
            String data = savedInstanceState.getString("key");
            Log.d(TAG, "onCreate: 恢复数据 - " + data);
        }
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart: Activity即将可见");
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume: Activity获得焦点");
        // 恢复暂停的操作,如动画、传感器等
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause: Activity失去焦点");
        // 暂停操作,如动画、传感器等
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: Activity不可见");
        // 停止耗时操作
    }
    
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart: Activity重新启动");
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: Activity销毁");
        // 释放资源
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState: 保存状态");
        outState.putString("key", "需要保存的数据");
    }
}
// Kotlin实现
class LifecycleActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "LifecycleActivity"
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate: Activity创建")
        setContentView(R.layout.activity_lifecycle)
        
        // 恢复保存的状态
        savedInstanceState?.let {
            val data = it.getString("key")
            Log.d(TAG, "onCreate: 恢复数据 - $data")
        }
    }
    
    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart: Activity即将可见")
    }
    
    override fun onResume() {
        super.onResume()
        Log.d(TAG, "onResume: Activity获得焦点")
    }
    
    override fun onPause() {
        super.onPause()
        Log.d(TAG, "onPause: Activity失去焦点")
    }
    
    override fun onStop() {
        super.onStop()
        Log.d(TAG, "onStop: Activity不可见")
    }
    
    override fun onRestart() {
        super.onRestart()
        Log.d(TAG, "onRestart: Activity重新启动")
    }
    
    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy: Activity销毁")
    }
    
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        Log.d(TAG, "onSaveInstanceState: 保存状态")
        outState.putString("key", "需要保存的数据")
    }
}

生命周期场景分析

场景1:正常启动和退出

启动:onCreate() → onStart() → onResume()
退出:onPause() → onStop() → onDestroy()

场景2:被其他Activity覆盖

被覆盖:onPause() → onStop()
返回:onRestart() → onStart() → onResume()

场景3:屏幕旋转

旋转前:onPause() → onStop() → onSaveInstanceState() → onDestroy()
旋转后:onCreate() → onStart() → onRestoreInstanceState() → onResume()

处理配置变更

防止Activity在配置变更时重建:

<activity 
    android:name=".MainActivity"
    android:configChanges="orientation|keyboardHidden|screenSize">
</activity>
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Log.d(TAG, "横屏模式");
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Log.d(TAG, "竖屏模式");
    }
}

固定屏幕方向

<!-- 强制竖屏 -->
<activity
    android:name=".MainActivity"
    android:screenOrientation="portrait" />

<!-- 强制横屏 -->
<activity
    android:name=".VideoActivity"
    android:screenOrientation="landscape" />

Activity管理

创建Activity

使用Android Studio创建

  1. 右键点击包名 → New → Activity → Empty Activity
  2. 输入Activity名称
  3. 选择是否生成布局文件
  4. 点击Finish

手动创建Activity

  1. 创建Activity类:
// Java
public class NewActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new);
    }
}
// Kotlin
class NewActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_new)
    }
}
  1. 创建布局文件 res/layout/activity_new.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Activity"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
</androidx.constraintlayout.widget.ConstraintLayout>
  1. 在AndroidManifest.xml中注册:
<activity 
    android:name=".NewActivity"
    android:exported="false" />

启动Activity

基本启动方式

// Java
public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Button button = findViewById(R.id.btn_start);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 显式Intent启动Activity
                Intent intent = new Intent(MainActivity.this, NewActivity.class);
                startActivity(intent);
            }
        });
    }
}
// Kotlin
class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        findViewById<Button>(R.id.btn_start).setOnClickListener {
            // 显式Intent启动Activity
            val intent = Intent(this, NewActivity::class.java)
            startActivity(intent)
            
            // 添加转场动画
            overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left)
        }
    }
}

关闭Activity

// 关闭当前Activity
finish();

// 关闭当前Activity并返回结果
Intent resultIntent = new Intent();
resultIntent.putExtra("result", "success");
setResult(RESULT_OK, resultIntent);
finish();

// 关闭整个应用
finishAffinity(); // API 16+

Activity启动模式

Activity的启动模式决定了Activity的实例如何被创建和复用。

四种启动模式

模式说明使用场景
standard默认模式,每次都创建新实例普通页面
singleTop栈顶复用,如果在栈顶则复用通知页面
singleTask栈内复用,如果存在则清除其上所有Activity主页面
singleInstance独立栈,全局唯一实例特殊功能页面

设置启动模式

方式1:在AndroidManifest.xml中设置

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask" />

方式2:通过Intent标志设置

Intent intent = new Intent(this, NewActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

常用的Intent标志:

  • FLAG_ACTIVITY_NEW_TASK:在新的任务栈中启动
  • FLAG_ACTIVITY_SINGLE_TOP:singleTop效果
  • FLAG_ACTIVITY_CLEAR_TOP:清除栈顶Activity
  • FLAG_ACTIVITY_CLEAR_TASK:清除整个任务栈

Intent与组件通信

Intent概述

Intent是Android中用于组件之间通信的消息对象。它可以用于:

  • 启动Activity
  • 启动Service
  • 发送广播
  • 启动ContentProvider查询

Intent类型

1. 显式Intent

明确指定要启动的组件类名:

// Java
Intent intent = new Intent(this, TargetActivity.class);
startActivity(intent);
// Kotlin
val intent = Intent(this, TargetActivity::class.java)
startActivity(intent)

2. 隐式Intent

不指定具体组件,而是声明要执行的操作:

// 打开网页
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.android.com"));
startActivity(intent);

// 拨打电话
Intent callIntent = new Intent(Intent.ACTION_DIAL);
callIntent.setData(Uri.parse("tel:10086"));
startActivity(callIntent);

// 发送邮件
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"test@example.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "邮件主题");
emailIntent.putExtra(Intent.EXTRA_TEXT, "邮件内容");
startActivity(Intent.createChooser(emailIntent, "选择邮件应用"));

IntentFilter配置

在AndroidManifest.xml中配置IntentFilter以响应隐式Intent:

<activity android:name=".MyActivity">
    <intent-filter>
        <action android:name="com.example.ACTION_CUSTOM" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="myapp" android:host="open" />
    </intent-filter>
</activity>

使用自定义Action启动:

Intent intent = new Intent("com.example.ACTION_CUSTOM");
intent.setData(Uri.parse("myapp://open"));
startActivity(intent);

Intent常用Action

Action说明示例
ACTION_VIEW查看数据打开网页、图片
ACTION_EDIT编辑数据编辑联系人
ACTION_DIAL拨号界面显示拨号界面
ACTION_CALL直接拨打电话需要权限
ACTION_SEND发送数据分享功能
ACTION_PICK选择数据选择图片

完整示例:显式和隐式Intent

// 主页面实现
public class IntentDemoActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_demo);
        
        // 显式Intent示例
        findViewById(R.id.btn_explicit).setOnClickListener(v -> {
            Intent intent = new Intent(this, SecondActivity.class);
            startActivity(intent);
        });
        
        // 隐式Intent示例
        findViewById(R.id.btn_implicit).setOnClickListener(v -> {
            Intent intent = new Intent("com.example.ACTION_DEMO");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            if (intent.resolveActivity(getPackageManager()) != null) {
                startActivity(intent);
            } else {
                Toast.makeText(this, "没有找到可以处理该Intent的Activity", 
                    Toast.LENGTH_SHORT).show();
            }
        });
        
        // 系统Intent示例
        findViewById(R.id.btn_system).setOnClickListener(v -> {
            // 选择图片
            Intent intent = new Intent(Intent.ACTION_PICK);
            intent.setType("image/*");
            startActivityForResult(intent, 100);
        });
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 100 && resultCode == RESULT_OK && data != null) {
            Uri imageUri = data.getData();
            // 处理选中的图片
        }
    }
}

PendingIntent

PendingIntent是对Intent的包装,允许外部应用执行Intent:

// 创建通知时使用PendingIntent
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
    this, 
    0, 
    notificationIntent, 
    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("通知标题")
    .setContentText("通知内容")
    .setContentIntent(pendingIntent)
    .setAutoCancel(true);

数据传递

传递基本数据类型

使用Intent.putExtra()

// Java - 发送数据
public class MainActivity extends AppCompatActivity {
    
    private void sendData() {
        Intent intent = new Intent(this, DetailActivity.class);
        
        // 传递基本数据类型
        intent.putExtra("name", "张三");
        intent.putExtra("age", 25);
        intent.putExtra("isVip", true);
        intent.putExtra("score", 98.5f);
        
        // 传递数组
        intent.putExtra("hobbies", new String[]{"编程", "读书", "运动"});
        
        startActivity(intent);
    }
}

// Java - 接收数据
public class DetailActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Intent intent = getIntent();
        String name = intent.getStringExtra("name");
        int age = intent.getIntExtra("age", 0); // 默认值0
        boolean isVip = intent.getBooleanExtra("isVip", false);
        float score = intent.getFloatExtra("score", 0f);
        String[] hobbies = intent.getStringArrayExtra("hobbies");
        
        // 使用接收到的数据
        Log.d("DetailActivity", "Name: " + name + ", Age: " + age);
    }
}
// Kotlin - 发送数据
class MainActivity : AppCompatActivity() {
    
    private fun sendData() {
        val intent = Intent(this, DetailActivity::class.java).apply {
            putExtra("name", "张三")
            putExtra("age", 25)
            putExtra("isVip", true)
            putExtra("score", 98.5f)
            putExtra("hobbies", arrayOf("编程", "读书", "运动"))
        }
        startActivity(intent)
    }
}

// Kotlin - 接收数据
class DetailActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        intent?.let {
            val name = it.getStringExtra("name")
            val age = it.getIntExtra("age", 0)
            val isVip = it.getBooleanExtra("isVip", false)
            val score = it.getFloatExtra("score", 0f)
            val hobbies = it.getStringArrayExtra("hobbies")
            
            Log.d("DetailActivity", "Name: $name, Age: $age")
        }
    }
}

使用Bundle传递数据

Bundle提供了更灵活的数据传递方式:

// Java - 使用Bundle
public class MainActivity extends AppCompatActivity {
    
    private void sendDataWithBundle() {
        Intent intent = new Intent(this, DetailActivity.class);
        
        // 创建Bundle
        Bundle bundle = new Bundle();
        bundle.putString("name", "李四");
        bundle.putInt("age", 30);
        bundle.putSerializable("date", new Date());
        
        // 传递自定义对象(需要实现Serializable或Parcelable)
        User user = new User("王五", 28);
        bundle.putSerializable("user", user);
        
        intent.putExtras(bundle);
        startActivity(intent);
    }
}

// 接收Bundle数据
public class DetailActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
            String name = bundle.getString("name");
            int age = bundle.getInt("age");
            Date date = (Date) bundle.getSerializable("date");
            User user = (User) bundle.getSerializable("user");
        }
    }
}

传递对象

方式1:实现Serializable接口

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // getter和setter方法
}

方式2:实现Parcelable接口(推荐)

public class Student implements Parcelable {
    private String name;
    private int age;
    private List<String> courses;
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        this.courses = new ArrayList<>();
    }
    
    protected Student(Parcel in) {
        name = in.readString();
        age = in.readInt();
        courses = in.createStringArrayList();
    }
    
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
        dest.writeStringList(courses);
    }
    
    @Override
    public int describeContents() {
        return 0;
    }
    
    public static final Creator<Student> CREATOR = new Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel in) {
            return new Student(in);
        }
        
        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };
}
// Kotlin中使用@Parcelize注解(需要添加插件)
@Parcelize
data class Student(
    val name: String,
    val age: Int,
    val courses: List<String> = emptyList()
) : Parcelable

Activity之间的数据回传

使用startActivityForResult(已废弃)

// 旧方式(已废弃)
public class MainActivity extends AppCompatActivity {
    private static final int REQUEST_CODE = 1001;
    
    private void startForResult() {
        Intent intent = new Intent(this, SelectActivity.class);
        startActivityForResult(intent, REQUEST_CODE);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        
        if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
            String result = data.getStringExtra("result");
            // 处理返回的数据
        }
    }
}

使用Activity Result API(推荐)

// Java - 新方式
public class MainActivity extends AppCompatActivity {
    
    // 注册结果回调
    private final ActivityResultLauncher<Intent> selectLauncher = 
        registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    Intent data = result.getData();
                    if (data != null) {
                        String selectedItem = data.getStringExtra("selected_item");
                        // 处理返回的数据
                        updateUI(selectedItem);
                    }
                }
            }
        );
    
    private void startSelectActivity() {
        Intent intent = new Intent(this, SelectActivity.class);
        selectLauncher.launch(intent);
    }
}

// 返回数据的Activity
public class SelectActivity extends AppCompatActivity {
    
    private void returnResult(String item) {
        Intent resultIntent = new Intent();
        resultIntent.putExtra("selected_item", item);
        setResult(RESULT_OK, resultIntent);
        finish();
    }
}
// Kotlin - 使用Activity Result API
class MainActivity : AppCompatActivity() {
    
    // 注册结果回调
    private val selectLauncher = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            result.data?.let { data ->
                val selectedItem = data.getStringExtra("selected_item")
                // 处理返回的数据
                updateUI(selectedItem)
            }
        }
    }
    
    private fun startSelectActivity() {
        val intent = Intent(this, SelectActivity::class.java)
        selectLauncher.launch(intent)
    }
}

使用ViewModel共享数据

对于复杂的数据共享场景,推荐使用ViewModel:

// 共享的ViewModel
class SharedViewModel : ViewModel() {
    private val _selectedItem = MutableLiveData<String>()
    val selectedItem: LiveData<String> = _selectedItem
    
    fun selectItem(item: String) {
        _selectedItem.value = item
    }
}

// Activity A
class ActivityA : AppCompatActivity() {
    private lateinit var viewModel: SharedViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        viewModel = ViewModelProvider(this).get(SharedViewModel::class.java)
        
        // 观察数据变化
        viewModel.selectedItem.observe(this) { item ->
            // 更新UI
        }
    }
}

示例:putExtra 与 Bundle 传值

在首页创建两个按钮

<Button
    android:id="@+id/btn1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="使用 putExtra 传递数据" />

<Button
    android:id="@+id/btn2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="使用 Bundle 传递数据" />

方法

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    Button btn1, btn2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn1 = findViewById(R.id.btn1);
        btn1.setOnClickListener(this);
        btn2 = findViewById(R.id.btn2);
        btn2.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn1:
//                使用 putExtra 传递数据
                Intent intent = new Intent(MainActivity.this, FirstActivity.class);
                intent.putExtra("name", "王小明");
                intent.putExtra("age", 12);
                intent.putExtra("isPassed", true);
                startActivity(intent);
                break;
            case R.id.btn2:
//                使用 Bundle 传递数据
                Intent intent1 = new Intent(MainActivity.this, SecondActivity.class);

//                创建 Bundle 对象
                Bundle bundle = new Bundle();
                bundle.putString("name","王小明");
                bundle.putInt("age",12);
                intent1.putExtras(bundle);
                startActivity(intent1);
                break;
        }

    }
}

另外两个页面

    <Button
        android:id="@+id/btn3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="接收 putExtra 传递的数据" />

    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/btn4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="接收 Bundle 传递的数据" />

    <TextView
        android:id="@+id/text2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

接收方法

public class FirstActivity extends AppCompatActivity {
    Button btn3;
    TextView text1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        text1=findViewById(R.id.text1);
        btn3=findViewById(R.id.btn3);
        btn3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                接收数据并显示在text1
                Intent intent=getIntent();
                String name = intent.getStringExtra("name");
                int age = intent.getIntExtra("age",0);
                boolean isPassed = intent.getBooleanExtra("isPassed",true);
                text1.setText(name+":"+age+":"+isPassed);
            }
        });
    }
}
public class SecondActivity extends AppCompatActivity {
    Button btn4;
    TextView text2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        text2 = findViewById(R.id.text2);
        btn4 = findViewById(R.id.btn4);
        btn4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                接收数据并显示在text2
                Bundle bundle = getIntent().getExtras();
                String name = bundle.getString("name");
                int age = bundle.getInt("age");
                text2.setText(name + ":" + age);
            }
        });

    }
}

image-20221011112153331

Jetpack组件

Jetpack Navigation简化了应用内导航的实现:

1. 添加依赖

dependencies {
    def nav_version = "2.5.3"
    
    // Java
    implementation "androidx.navigation:navigation-fragment:$nav_version"
    implementation "androidx.navigation:navigation-ui:$nav_version"
    
    // Kotlin
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

2. 创建导航图

res/navigation/nav_graph.xml:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/homeFragment">
    
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.example.HomeFragment"
        android:label="Home"
        tools:layout="@layout/fragment_home">
        
        <action
            android:id="@+id/action_home_to_detail"
            app:destination="@id/detailFragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right" />
    </fragment>
    
    <fragment
        android:id="@+id/detailFragment"
        android:name="com.example.DetailFragment"
        android:label="Detail"
        tools:layout="@layout/fragment_detail">
        
        <argument
            android:name="itemId"
            app:argType="integer"
            android:defaultValue="0" />
    </fragment>
    
</navigation>

3. 在Activity中设置Navigation

class MainActivity : AppCompatActivity() {
    
    private lateinit var navController: NavController
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController
        
        // 设置ActionBar
        setupActionBarWithNavController(navController)
        
        // 设置BottomNavigationView
        val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav)
        bottomNav.setupWithNavController(navController)
    }
    
    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
}

4. 导航操作

// 简单导航
findNavController().navigate(R.id.detailFragment)

// 传递参数
val bundle = bundleOf("itemId" to 123)
findNavController().navigate(R.id.detailFragment, bundle)

// 使用Safe Args(推荐)
val action = HomeFragmentDirections.actionHomeToDetail(itemId = 123)
findNavController().navigate(action)

Activity结果API

新的Activity Result API替代了过时的startActivityForResult:

class MainActivity : AppCompatActivity() {
    
    // 选择图片
    private val pickImage = registerForActivityResult(
        ActivityResultContracts.GetContent()
    ) { uri: Uri? ->
        uri?.let {
            // 处理选中的图片
            imageView.setImageURI(it)
        }
    }
    
    // 请求权限
    private val requestPermission = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // 权限已授予
            takePhoto()
        } else {
            // 权限被拒绝
            showPermissionDeniedDialog()
        }
    }
    
    // 拍照
    private val takePicture = registerForActivityResult(
        ActivityResultContracts.TakePicture()
    ) { success: Boolean ->
        if (success) {
            // 照片已保存
        }
    }
    
    private fun selectImage() {
        pickImage.launch("image/*")
    }
    
    private fun requestCameraPermission() {
        requestPermission.launch(Manifest.permission.CAMERA)
    }
}

性能优化

1. 避免内存泄漏

class MyActivity : AppCompatActivity() {
    
    // 避免内部类持有外部类引用
    companion object {
        class MyHandler(activity: MyActivity) : Handler(Looper.getMainLooper()) {
            private val weakReference = WeakReference(activity)
            
            override fun handleMessage(msg: Message) {
                weakReference.get()?.let { activity ->
                    // 处理消息
                }
            }
        }
    }
    
    private lateinit var handler: MyHandler
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        handler = MyHandler(this)
    }
    
    override fun onDestroy() {
        super.onDestroy()
        handler.removeCallbacksAndMessages(null)
    }
}

2. 优化启动速度

// 使用懒加载
class MainActivity : AppCompatActivity() {
    
    private val heavyObject by lazy {
        // 延迟初始化重量级对象
        HeavyObject()
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // 异步加载数据
        lifecycleScope.launch {
            val data = withContext(Dispatchers.IO) {
                loadDataFromDatabase()
            }
            updateUI(data)
        }
    }
}

3. 管理Activity栈

object ActivityManager {
    private val activities = mutableListOf<WeakReference<Activity>>()
    
    fun addActivity(activity: Activity) {
        activities.add(WeakReference(activity))
    }
    
    fun removeActivity(activity: Activity) {
        activities.removeAll { it.get() == activity || it.get() == null }
    }
    
    fun finishAll() {
        activities.forEach { it.get()?.finish() }
        activities.clear()
    }
}

最佳实践

1. 使用AndroidX和Jetpack

// 使用AppCompatActivity而不是Activity
class MainActivity : AppCompatActivity() {
    // 使用ViewBinding
    private lateinit var binding: ActivityMainBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // 直接访问视图
        binding.textView.text = "Hello"
        binding.button.setOnClickListener {
            // 处理点击
        }
    }
}

2. 处理配置变更

class MainActivity : AppCompatActivity() {
    
    // 使用ViewModel保存数据
    private val viewModel: MainViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ViewModel中的数据在配置变更后仍然存在
        viewModel.data.observe(this) { data ->
            updateUI(data)
        }
    }
}

3. 权限处理

class PermissionActivity : AppCompatActivity() {
    
    private val requestMultiplePermissions = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        permissions.entries.forEach { entry ->
            val permission = entry.key
            val isGranted = entry.value
            
            when {
                isGranted -> {
                    // 权限已授予
                }
                shouldShowRequestPermissionRationale(permission) -> {
                    // 显示权限说明
                }
                else -> {
                    // 权限被永久拒绝
                }
            }
        }
    }
    
    private fun requestPermissions() {
        val permissions = arrayOf(
            Manifest.permission.CAMERA,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
        requestMultiplePermissions.launch(permissions)
    }
}

调试技巧

1. 生命周期日志

open class BaseActivity : AppCompatActivity() {
    
    protected val TAG = javaClass.simpleName
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate")
    }
    
    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart")
    }
    
    // 其他生命周期方法...
}

2. 使用ADB命令

# 查看Activity栈
adb shell dumpsys activity activities

# 启动Activity
adb shell am start -n com.example.app/.MainActivity

# 强制停止应用
adb shell am force-stop com.example.app

# 查看当前Activity
adb shell dumpsys activity top

3. 使用Layout Inspector

在Android Studio中:

  1. Tools → Layout Inspector
  2. 选择进程和Activity
  3. 查看视图层级和属性

常见问题

问题1:Activity未注册

错误信息:

android.content.ActivityNotFoundException: Unable to find explicit activity class

解决方案: 在AndroidManifest.xml中注册Activity:

<activity android:name=".YourActivity" />

问题2:数据丢失

问题描述: 旋转屏幕后数据丢失

解决方案:

  1. 使用onSaveInstanceState保存数据
  2. 使用ViewModel
  3. 在manifest中配置android:configChanges

问题3:内存泄漏

常见原因:

  • Handler持有Activity引用
  • 静态变量持有Activity
  • 监听器未注销

解决方案:

override fun onDestroy() {
    super.onDestroy()
    // 移除所有回调
    handler.removeCallbacksAndMessages(null)
    // 注销监听器
    unregisterReceiver(receiver)
    // 取消协程
    job?.cancel()
}

相关文章

Android开发基础

组件通信

进阶主题

总结

Activity是Android应用的核心组件,掌握其生命周期和使用方法对于开发高质量应用至关重要。

🎯 核心要点

  • 生命周期管理:理解并正确处理各个生命周期方法
  • 数据传递:掌握Intent、Bundle等数据传递方式
  • 导航管理:使用Navigation组件简化导航逻辑
  • 性能优化:避免内存泄漏,优化启动速度

🛠️ 开发建议

  • 使用Jetpack组件提高开发效率
  • 遵循单一职责原则,避免Activity过于臃肿
  • 合理使用启动模式管理Activity栈
  • 重视用户体验,提供流畅的页面转场