当前位置: 首页 > news >正文

安卓服务与多线程

Android 服务与多线程编程详解

一、服务基本概念

服务(Service)是Android中实现程序后台运行的重要组件,它适合执行不需要与用户交互且需要长期运行的任务。服务有以下特点:

  1. 独立于UI:服务运行不依赖于任何用户界面,即使程序被切换到后台也能正常运行
  2. 进程依赖:服务依赖于创建它的应用程序进程,当应用进程被杀死时,所有依赖该进程的服务都会停止
  3. 主线程运行:服务不会自动开启线程,所有代码默认在主线程执行,需要手动创建子线程处理耗时任务

二、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个部分组成:

  1. Message:线程间传递的消息,可携带少量数据
  2. Handler:消息的处理者,负责发送和处理消息
  3. MessageQueue:消息队列,存放所有通过Handler发送的消息
  4. 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实现通信

  1. 在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;}
}
  1. 在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. 创建前台服务

  1. 在AndroidManifest.xml中声明权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Android 13+ 需要 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  1. 在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
}
  1. 启动前台服务:
// 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. 自动创建子线程处理任务
  2. 任务执行完毕后自动停止服务

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()

八、总结

  1. 服务:适合执行后台任务,但需要注意生命周期管理和资源释放
  2. 多线程:Android UI操作必须在主线程执行,耗时操作应在子线程执行
  3. 通信机制:使用Handler、Binder等方式实现线程间和Activity-Service间通信
  4. 前台服务:适合重要任务,需要创建通知并处理权限问题
  5. IntentService:简化了Service的使用,自动处理线程和生命周期

通过合理使用服务和多线程技术,可以构建出响应迅速、功能完善的Android应用。

http://www.lryc.cn/news/600749.html

相关文章:

  • 学习嵌入式的第三十天-数据结构-(2025.7.21)网络编程
  • 系统性学习C语言-第二十三讲-文件操作
  • 台式电脑有多个风扇开机只有部分转动的原因
  • Matlab自学笔记六十五:解方程的数值解法(代码速成)
  • Nacos-服务注册,服务发现(二)
  • 八股文整理——计算机网络
  • 容器化成本优化:K8s资源请求与限制的黄金法则——从资源画像分析到25%成本削减的实战指南
  • 记录和分享抓取的数字货币和大A时序数据
  • 什么是ICMP报文?有什么用?
  • Matlab学习笔记:自定义函数
  • java基础(day16)set-map
  • DAY24 元组和OS模块
  • 【安全漏洞】网络守门员:深入理解与应用iptables,守护Linux服务器安全
  • Java基础-文件操作
  • spring Could 高频面试题
  • 面试问题总结——关于OpenCV(二)
  • 详解力扣高频SQL50题之619. 只出现一次的最大数字【简单】
  • 《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——6. 传统算法实战:用OpenCV测量螺丝尺寸
  • 人工智能之数学基础:概率论之韦恩图的应用
  • Java 镜像减肥记:Docker 多阶段构建全攻略
  • 统计学08:概率分布
  • 【SSM】第二章 网上蛋糕项目商城-首页
  • lottie 动画使用
  • MySQL数据库本地迁移到云端完整教程
  • 《每日AI-人工智能-编程日报》--2025年7月26日
  • 使用Netty搭建一个网络聊天室
  • Java面试题及详细答案120道之(041-060)
  • 图片查重从设计到实现(5)Milvus可视化工具
  • 力扣872. 叶子相似的树
  • 如何在 Ubuntu 24.04 或 22.04 中创建自定义 Bash 命令