安卓服务与多线程
Android 服务与多线程编程详解
一、服务基本概念
服务(Service)是Android中实现程序后台运行的重要组件,它适合执行不需要与用户交互且需要长期运行的任务。服务有以下特点:
- 独立于UI:服务运行不依赖于任何用户界面,即使程序被切换到后台也能正常运行
- 进程依赖:服务依赖于创建它的应用程序进程,当应用进程被杀死时,所有依赖该进程的服务都会停止
- 主线程运行:服务不会自动开启线程,所有代码默认在主线程执行,需要手动创建子线程处理耗时任务
二、Android多线程编程
Android的多线程编程与Java基本相同,创建线程的方式也类似:
class MyThread extends Thread {@Overridepublic void run() {// 线程执行的代码}
}// 启动线程
new MyThread().start();
但需要注意Android的UI线程模型:
1. UI线程模型
Android采用单线程模型处理UI操作,主线程(也称为UI线程)负责:
- 绘制和更新界面
- 处理用户交互事件
- 执行Activity生命周期回调方法
2. 子线程更新UI的问题
直接在子线程中更新UI会导致异常:
// 错误示例:子线程更新UI
new Thread(() -> {textView.setText("更新内容"); // 会抛出CalledFromWrongThreadException
}).start();
这是因为Android的UI组件不是线程安全的,所有UI操作必须在主线程执行。
三、异步消息处理机制
Android提供了异步消息处理机制来解决子线程与UI线程通信的问题,主要由4个部分组成:
- Message:线程间传递的消息,可携带少量数据
- Handler:消息的处理者,负责发送和处理消息
- MessageQueue:消息队列,存放所有通过Handler发送的消息
- Looper:消息循环器,不断从MessageQueue中取出消息并分发给Handler
1. 完整使用示例
public class MainActivity extends AppCompatActivity {public static final int UPDATE_TEXT = 1;private TextView textView;private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case UPDATE_TEXT:textView.setText("更新后的内容");break;// 可以处理更多消息类型}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = findViewById(R.id.textView);Button button = findViewById(R.id.button);button.setOnClickListener(v -> {// 创建子线程执行耗时操作new Thread(() -> {// 模拟耗时操作try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}// 发送消息到主线程更新UIMessage message = new Message();message.what = UPDATE_TEXT;handler.sendMessage(message);}).start();});}
}
2. 更简洁的实现方式 - Runnable
除了使用Message,还可以直接传递Runnable对象:
// 在主线程创建Handler
Handler handler = new Handler(Looper.getMainLooper());// 在子线程中
new Thread(() -> {// 耗时操作...// 在主线程执行UI更新handler.post(() -> {textView.setText("更新后的内容");});
}).start();
四、服务详解
1. 定义服务
服务需要继承Service类并实现关键方法:
public class MyService extends Service {private static final String TAG = "MyService";@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "服务创建了");// 初始化操作}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "服务启动了");// 执行后台任务return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "服务销毁了");// 释放资源}@Overridepublic IBinder onBind(Intent intent) {// 返回Binder对象用于Activity与Service通信return null;}
}
2. 服务的生命周期
- onCreate():服务第一次创建时调用
- onStartCommand():每次通过startService()启动服务时调用
- onBind():通过bindService()绑定服务时调用
- onUnbind():所有客户端解除绑定时调用
- onDestroy():服务销毁时调用
3. 启动和停止服务
启动服务:
Intent intent = new Intent(this, MyService.class);
startService(intent); // 启动服务
停止服务:
Intent intent = new Intent(this, MyService.class);
stopService(intent); // 停止服务
绑定服务:
private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 获取Binder对象}@Overridepublic void onServiceDisconnected(ComponentName name) {// 服务异常断开}
};Intent intent = new Intent(this, MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
解除绑定:
unbindService(connection);
五、活动与服务通信
1. 使用Binder实现通信
- 在Service中创建Binder子类:
public class MyService extends Service {private DownloadBinder mBinder = new DownloadBinder();class DownloadBinder extends Binder {public void startDownload() {Log.d(TAG, "开始下载");}public int getProgress() {Log.d(TAG, "获取下载进度");return 0;}}@Overridepublic IBinder onBind(Intent intent) {return mBinder;}
}
- 在Activity中绑定服务并获取Binder:
private MyService.DownloadBinder downloadBinder;private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {downloadBinder = (MyService.DownloadBinder) service;downloadBinder.startDownload();downloadBinder.getProgress();}@Overridepublic void onServiceDisconnected(ComponentName name) {}
};// 绑定服务
Intent intent = new Intent(this, MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
2. 服务的销毁规则
必须同时调用stopService()
和unbindService()
才能完全销毁服务:
- 如果只调用
stopService()
,但仍有客户端绑定,服务不会销毁 - 如果只调用
unbindService()
,但服务是通过startService()
启动的,服务也不会销毁
六、前台服务
前台服务比普通服务具有更高的优先级,系统更不容易杀死它,适合执行重要任务。
1. 创建前台服务
- 在AndroidManifest.xml中声明权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Android 13+ 需要 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- 在Service中创建通知并启动前台服务:
@Override
public void onCreate() {super.onCreate();// 创建通知渠道(Android 8.0+)if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationChannel channel = new NotificationChannel("channel_id", "Channel Name", NotificationManager.IMPORTANCE_DEFAULT);NotificationManager manager = getSystemService(NotificationManager.class);manager.createNotificationChannel(channel);}// 创建PendingIntentIntent intent = new Intent(this, MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);// 创建通知Notification notification = new NotificationCompat.Builder(this, "channel_id").setContentTitle("前台服务").setContentText("服务正在运行").setSmallIcon(R.drawable.ic_notification).setContentIntent(pendingIntent).build();// 启动前台服务startForeground(1, notification); // 1是通知ID
}
- 启动前台服务:
// Android 9.0+ 需要使用startForegroundService()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {startForegroundService(intent);
} else {startService(intent);
}
2. Android 13+的通知权限
从Android 13开始,需要动态申请通知权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.POST_NOTIFICATIONS},1);
}
七、IntentService
IntentService是Service的子类,它解决了Service不能自动创建线程的问题:
- 自动创建子线程处理任务
- 任务执行完毕后自动停止服务
1. 创建IntentService
public class MyIntentService extends IntentService {public MyIntentService() {super("MyIntentService"); // 指定线程名称}@Overrideprotected void onHandleIntent(Intent intent) {// 在这里执行耗时操作// 这个方法运行在子线程中}
}
2. 使用IntentService
Intent intent = new Intent(this, MyIntentService.class);
startService(intent); // 启动服务,会自动创建线程执行onHandleIntent()
八、总结
- 服务:适合执行后台任务,但需要注意生命周期管理和资源释放
- 多线程:Android UI操作必须在主线程执行,耗时操作应在子线程执行
- 通信机制:使用Handler、Binder等方式实现线程间和Activity-Service间通信
- 前台服务:适合重要任务,需要创建通知并处理权限问题
- IntentService:简化了Service的使用,自动处理线程和生命周期
通过合理使用服务和多线程技术,可以构建出响应迅速、功能完善的Android应用。