Android开发四大组件详解

Android开发四大组件详解

Android应用程序的四大组件是Android架构的核心,它们分别是:

  1. Activity(活动) - 用户界面组件
  2. Service(服务) - 后台处理组件
  3. BroadcastReceiver(广播接收器) - 消息通信组件
  4. ContentProvider(内容提供者) - 数据共享组件

1. Activity(活动)

作用说明

Activity是Android应用中的用户界面组件,每个Activity代表一个屏幕界面。就像一本书的每一页,用户可以在不同的Activity之间切换,完成不同的操作。

生命周期

Activity有完整的生命周期,主要包括:

  • onCreate() - 创建时调用
  • onStart() - 开始可见时调用
  • onResume() - 获得焦点时调用
  • onPause() - 失去焦点时调用
  • onStop() - 不可见时调用
  • onDestroy() - 销毁时调用

核心代码示例

java 复制代码
public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 初始化界面组件
        Button loginButton = findViewById(R.id.login_button);
        loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 跳转到另一个Activity
                Intent intent = new Intent(MainActivity.this, LoginActivity.class);
                startActivity(intent);
            }
        });
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        // Activity重新获得焦点时的操作
        Log.d("MainActivity", "Activity已恢复");
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        // Activity失去焦点时保存数据
        saveUserData();
    }
    
    private void saveUserData() {
        // 保存用户数据的逻辑
    }
}

2. Service(服务)

作用说明

Service是在后台运行的组件,即使用户切换到其他应用,Service仍然可以继续工作。就像手机的音乐播放器,即使你在聊微信,音乐依然在后台播放。

服务类型

  • 前台服务 - 用户可感知,如音乐播放
  • 后台服务 - 用户不可感知,如数据同步
  • 绑定服务 - 与其他组件绑定使用

核心代码示例

java 复制代码
public class MusicService extends Service {
    private MediaPlayer mediaPlayer;
    
    @Override
    public void onCreate() {
        super.onCreate();
        // 服务创建时初始化
        mediaPlayer = new MediaPlayer();
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 服务启动时执行的操作
        String action = intent.getStringExtra("action");
        
        if ("PLAY".equals(action)) {
            playMusic();
        } else if ("PAUSE".equals(action)) {
            pauseMusic();
        }
        
        // 返回START_STICKY表示服务被杀死后会自动重启
        return START_STICKY;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        // 返回null表示这是一个启动服务,不是绑定服务
        return null;
    }
    
    private void playMusic() {
        try {
            mediaPlayer.setDataSource("music_file_path");
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void pauseMusic() {
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.release();
        }
    }
}

// 在Activity中启动服务
public class MainActivity extends AppCompatActivity {
    
    private void startMusicService() {
        Intent intent = new Intent(this, MusicService.class);
        intent.putExtra("action", "PLAY");
        startService(intent);
    }
}

3. BroadcastReceiver(广播接收器)

作用说明

BroadcastReceiver用于接收系统或应用发送的广播消息。就像收音机接收电台信号一样,当系统发生某些事件(如电池电量低、网络连接变化)时,BroadcastReceiver可以接收到这些消息并做出响应。

广播类型

  • 系统广播 - 系统发送的广播(如开机完成、电池电量变化)
  • 自定义广播 - 应用自己发送的广播
  • 有序广播 - 按优先级顺序接收
  • 无序广播 - 同时接收

核心代码示例

java 复制代码
public class NetworkReceiver extends BroadcastReceiver {
    
    @Override
    public void onReceive(Context context, Intent intent) {
        // 接收到广播时的处理逻辑
        String action = intent.getAction();
        
        if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
            // 网络状态发生变化
            ConnectivityManager cm = (ConnectivityManager) 
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = cm.getActiveNetworkInfo();
            
            if (networkInfo != null && networkInfo.isConnected()) {
                // 网络已连接
                Toast.makeText(context, "网络已连接", Toast.LENGTH_SHORT).show();
                // 可以开始网络请求
                syncData(context);
            } else {
                // 网络已断开
                Toast.makeText(context, "网络已断开", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    private void syncData(Context context) {
        // 网络连接后同步数据的逻辑
    }
}

// 在Activity中注册广播接收器
public class MainActivity extends AppCompatActivity {
    private NetworkReceiver networkReceiver;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // 动态注册广播接收器
        networkReceiver = new NetworkReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(networkReceiver, filter);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消注册广播接收器
        if (networkReceiver != null) {
            unregisterReceiver(networkReceiver);
        }
    }
    
    // 发送自定义广播
    private void sendCustomBroadcast() {
        Intent intent = new Intent("com.example.CUSTOM_ACTION");
        intent.putExtra("message", "这是自定义广播消息");
        sendBroadcast(intent);
    }
}

4. ContentProvider(内容提供者)

作用说明

ContentProvider用于在不同应用之间共享数据。就像图书馆的管理员,负责管理数据的存取,其他应用可以通过标准的接口来访问这些数据,而不需要知道数据的具体存储方式。

主要功能

  • 数据封装和安全访问
  • 跨应用数据共享
  • 统一的数据访问接口
  • 数据权限控制

核心代码示例

java 复制代码
public class ContactProvider extends ContentProvider {
    private static final String AUTHORITY = "com.example.contactprovider";
    private static final String TABLE_NAME = "contacts";
    
    // URI匹配器
    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    private static final int CONTACTS = 1;
    private static final int CONTACT_ID = 2;
    
    static {
        uriMatcher.addURI(AUTHORITY, TABLE_NAME, CONTACTS);
        uriMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", CONTACT_ID);
    }
    
    private SQLiteDatabase database;
    
    @Override
    public boolean onCreate() {
        // 初始化数据库
        ContactDBHelper dbHelper = new ContactDBHelper(getContext());
        database = dbHelper.getWritableDatabase();
        return database != null;
    }
    
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                       String[] selectionArgs, String sortOrder) {
        // 查询数据
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(TABLE_NAME);
        
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                // 查询所有联系人
                break;
            case CONTACT_ID:
                // 查询特定ID的联系人
                String id = uri.getLastPathSegment();
                queryBuilder.appendWhere("_id = " + id);
                break;
            default:
                throw new IllegalArgumentException("未知URI: " + uri);
        }
        
        return queryBuilder.query(database, projection, selection,
                                selectionArgs, null, null, sortOrder);
    }
    
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // 插入数据
        long rowId = database.insert(TABLE_NAME, null, values);
        if (rowId > 0) {
            Uri newUri = ContentUris.withAppendedId(
                Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME), rowId);
            getContext().getContentResolver().notifyChange(newUri, null);
            return newUri;
        }
        throw new SQLException("插入数据失败: " + uri);
    }
    
    @Override
    public int update(Uri uri, ContentValues values, String selection,
                     String[] selectionArgs) {
        // 更新数据
        int count = 0;
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                count = database.update(TABLE_NAME, values, selection, selectionArgs);
                break;
            case CONTACT_ID:
                String id = uri.getLastPathSegment();
                count = database.update(TABLE_NAME, values,
                    "_id = " + id + (!TextUtils.isEmpty(selection) ? 
                    " AND (" + selection + ")" : ""), selectionArgs);
                break;
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
    
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // 删除数据
        int count = 0;
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                count = database.delete(TABLE_NAME, selection, selectionArgs);
                break;
            case CONTACT_ID:
                String id = uri.getLastPathSegment();
                count = database.delete(TABLE_NAME,
                    "_id = " + id + (!TextUtils.isEmpty(selection) ? 
                    " AND (" + selection + ")" : ""), selectionArgs);
                break;
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
    
    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                return "vnd.android.cursor.dir/vnd.example.contact";
            case CONTACT_ID:
                return "vnd.android.cursor.item/vnd.example.contact";
            default:
                throw new IllegalArgumentException("未知URI: " + uri);
        }
    }
}

// 在其他应用中使用ContentProvider
public class MainActivity extends AppCompatActivity {
    
    private void queryContacts() {
        Uri uri = Uri.parse("content://com.example.contactprovider/contacts");
        ContentResolver resolver = getContentResolver();
        
        Cursor cursor = resolver.query(uri, null, null, null, null);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndex("name"));
                String phone = cursor.getString(cursor.getColumnIndex("phone"));
                Log.d("Contact", "姓名: " + name + ", 电话: " + phone);
            }
            cursor.close();
        }
    }
    
    private void insertContact() {
        Uri uri = Uri.parse("content://com.example.contactprovider/contacts");
        ContentValues values = new ContentValues();
        values.put("name", "张三");
        values.put("phone", "13800138000");
        
        Uri newUri = getContentResolver().insert(uri, values);
        if (newUri != null) {
            Toast.makeText(this, "联系人添加成功", Toast.LENGTH_SHORT).show();
        }
    }
}

四大组件总结

组件间的协作关系

  1. Activity 负责用户界面交互
  2. Service 在后台处理长时间运行的任务
  3. BroadcastReceiver 处理系统和应用间的消息通信
  4. ContentProvider 提供数据共享机制

实际应用场景举例

  • 音乐播放器应用
    • Activity:显示播放界面、歌曲列表
    • Service:后台播放音乐
    • BroadcastReceiver:接收耳机插拔、来电等事件
    • ContentProvider:共享音乐文件信息给其他应用

配置文件注册

所有组件都需要在AndroidManifest.xml中注册:

xml 复制代码
<application>
    <!-- Activity注册 -->
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    
    <!-- Service注册 -->
    <service android:name=".MusicService" />
    
    <!-- BroadcastReceiver注册 -->
    <receiver android:name=".NetworkReceiver">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>
    
    <!-- ContentProvider注册 -->
    <provider
        android:name=".ContactProvider"
        android:authorities="com.example.contactprovider"
        android:exported="true" />
</application>
相关推荐
木辰風2 小时前
idea npm install 很慢(nodejs)
前端·npm·node.js
阿笑带你学前端2 小时前
Drift数据库开发实战:类型安全的SQLite解决方案
前端·flutter
FE_C_P小麦2 小时前
Git 常用指令
前端·后端·github
北城笑笑2 小时前
Server 13 ,CentOS 上使用 Nginx 部署多个前端项目完整指南( 支持多端口与脚本自动化 )
linux·服务器·前端·nginx·centos
卓伊凡2 小时前
完整的苹果内购in-purchase实例-采用object-c语言使用苹果的Storyboard开发模式的完整购买实例
前端
用泥种荷花2 小时前
【web音频学习(一)】音频基础
前端
Mintopia2 小时前
Next.js自建部署:Docker + PM2 + Nginx
前端·javascript·全栈
艾小码2 小时前
还在重复造轮子?3个Vue3组合函数让你开发效率翻倍!
前端·javascript·vue.js
一枚前端小能手3 小时前
🎨 CSS-in-JS到底香不香?性能陷阱让我重新思考了
前端·javascript·css