当前位置: 首页 > 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.dtcms.com/a/299113.html

相关文章:

  • uniapp+高德地图实现打卡签到、打卡日历
  • uniapp input 如何只读禁用输入可点击
  • ISIS GR实验案例
  • 机器学习特征工程:特征选择及在医学影像领域的应用
  • QT中启用VIM后粘贴复制快捷键失效
  • 电子电气架构 --- 车载软件交样评审流程
  • Python 数据分析(二):Matplotlib 绘图
  • Python点阵字生成与优化:从基础实现到高级渲染技术
  • P1064 [NOIP 2006 提高组] 金明的预算方案 题解
  • 主要分布在腹侧海马体(vHPC)CA1区域(vCA1)的混合调谐细胞(mixed-tuning cells)对NLP中的深层语义分析的积极影响和启示
  • LeetCode 刷题【15. 三数之和】
  • Ubuntu 18.04安装Fast-Lio2教程
  • 开发者说|RoboTransfer:几何一致视频世界模型,突破机器人操作泛化边界
  • Vue当中背景图无法占满屏幕的解决方法
  • JavaScript里的reduce
  • JavaScript 对象、字符串的统计和排序高频面试题
  • Spring Boot 3 如何整合 MinIO 实现分布式文件存储?
  • 【20】C# 窗体应用WinForm ——下拉列表框ComboBox属性、方法、实例应用
  • 掌握JavaScript函数封装与作用域
  • 【资讯】2025年软件行业发展趋势:AI驱动变革,云原生与安全成核心
  • C++/CLI与标准C++的语法差异(一)
  • 《jQuery Mobile 页面》
  • 统计学07:概率论基础
  • ICMPv6报文类型详解表
  • opencv学习(图像金字塔)
  • 算法第三十九天:动态规划part07(第九章)
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现沙滩小人检测识别(C#代码UI界面版)
  • Kafka MQ 消费者应用场景
  • 【C++】stack和queue的模拟实现
  • 【C++】定义常量