《第一行代码》笔记之 Service

本文是《第一行代码》笔记,详细介绍了Android中的Service,包括多线程编程、异步消息处理机制、AsyncTask的使用,以及服务的基本用法和生命周期。服务适合后台执行长时间任务,注意在主线程外处理耗时操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Service(服务)

本篇内容整理自郭霖的 《第一行代码》

  • 服务是 Android 中实现程序后台运行的解决方案,适合执行不需要和用户交互长期运行的任务。
  • 应用进程被杀掉,所依赖该进程的服务也终止。
  • 服务不会自动开启线程,默认运行在主线程。
  • 服务内部创建子线程,并实现业务处理。

Android 多线程编程

  • 耗时操作放在子线程运行,否则主线程会被阻塞

线程的基本用法

1.实现Runnable接口实现

class MyThread implements Runnable{
	public void run(){
		//处理具体的业务逻辑
	}
}
MyThread myThread = new MyThread();
new Thread(myThread).start();

2.匿名类写法(常用)

new Thread(new Runnable(){
	public void run(){
		//处理具体的业务逻辑
	}
}).start();

在子线程中更新UI

Android UI 是线程不安全的,要更新UI,必须在主线程当中

  • 很简单,异步处理机制可以解决子线程中进行UI操作的问题
public static final int UPDATE_TEXT = 1;

public Handler handler = new Handler(){
	public void handleMessage(Message msg){
		switch(msg.what){
		case UPDATE_TEXT:
		//在这里进行UI操作
		break;
		default:
		break;
		}
	}
};

public void onClick(){
	new Thread(new Runnable(){
		Message message = new Message();
		message.what = UPDATE_TEXT;
		handler.sendMessage(message); // 将 Message 对象发出去
	}).start();
}

运用 Message 把消息传递出去交由 handleMessage 来处理业务逻辑


解析异步消息处理机制

  • 很简单,Android 中异步消息处理主要由四个部分组成:
  1. Message
  • Message 是线程之间传递的消息,它可以携带少量的信息在线程之间交换数据
    例如:arg1、arg2 字段携带整型数据;obj 字段携带一个 Object 对象;what 字段携带…
  1. Handler
    • Handler(处理者)主要是用于发送处理消息的。
      发送:sendMessage()
      处理:handleMessage()
  2. MessageQueue
  • 消息队列,存放 Handler 发送的消息。
  • 消息会一直存放在 MessageQueue 中等待被处理
  • 每个线程只会有一个 MessageQueue 对象
  1. Looper
    • 管理 MessageQueue 。调用 Looper 的 loop() 方法后,就会进入一个无限循环,只要 MessageQueue 中存在一条消息,就会将它取出并传递到 handleMessage() 中处理。
    • 每个线程只有一个 Looper 对象

这里写图片描述


使用AsyncTask

  • 借助 AsyncTask 也可以很简单地从子线程切换到主程序(背后的实现原理也是基于异步消息处理机制,android 已经封装好了

AsyncTask 泛型三参数:
第一:Params 在执行 AsyncTask 时使用;在后台任务中使用

第二:Progress 后台任务执行时需要在界面显示当前进度时使用;作为进度单位

第三:Result 后台任务执行完毕,需要对结果进行返回时使用;作为返回值类型

class DownloadTask extends AsyncTask<Void, Integer, Boolean>{
	// void 不需要传入参数给后台任务;Integer 整型数据来作为进度显示单位; Boolean 布尔型数据来反馈执行结果
}
  • 重写 AsyncTask 中的方法,完成对任务的定制。常用四个方法:
  1. onPreExecute()
  • 后台任务开始执行前调用
  • 用于界面初始化操作。 eg:显示进度条对话框
  1. doInBackground(Params…)
  • 这个方法的代码会在子线程中运行,这儿处理耗时任务。
  • 任务完成 return AsyncTask 泛型第三个参数类型的结果,为空不返回。
  • 不可以进行UI操作。如果需要 UI 操作调用 publishProgress(Progress…) 方法
  1. onProgressUpdate(Progress…)
  • 后台任务调用 publishProgress(Progress…) ,这个方法就被调用。
  • 参数由后台任务传进
  • 在此方法中更新 UI
  1. onPostExecute(Result)
  • 后台任务通过 return 返回时,此方法被调用
  • 利用返回的数据进行 UI 操作
class DownloadTask extends AsyncTask<Void, Integer, Boolean>{
	
	// 后台任务执行前
	protected void onPreExecute(){
		progressDialog.show(); //显示进度对话框
	}

	// 后台任务执行中(此方法即在子线程中跑)
	protected Boolean doInBackground(Void... params){
		try{
			int downloadPercent = doDownload(); //虚构方法
			publishProgress(downloadPercent);
			if(downloadPercent >= 100){
				break;
			}
		}catch(Exception e){
			return false;
		}
		return true;
	}

	// 后台任务调用 publishProgress()时
	protected void onProgressUpdate(Integer... values){
		progressDialog.setMessage("Downloaded" + values[0] + "%");//更新下载进度
	}

	//  后台任务通过 return 时
	protected void onPostExecute(Boolean result){
		progressDialog.dismiss();//关闭对话框
		if(result){
			Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();
		}else{
			Toast.makeText(context, "Download failed", Toast.LENGTH_SHORT).show();
		}
	}
}

//启动
new DownloadTask().execute();

AsyncTask 诀窍:在 doInBackground() 中执行具体耗时任务,在 onProgressUpdate() 中进行UI操作,在 onPostExecute()中执行一些任务收尾工作

服务的基本用法


定义一个服务

1、新建一个 MyService 类,继承 Service

  • onBind() 方法是 Service 唯一的抽象方法,必须在子类中实现
public class MyService extends Service{
	@Override
	public IBinder onBind(Intent intent){
		return null;
	}
}

2、服务常用的三个方法

  • onCreate()
    • 服务创建时候调用(仅创建那一次
  • onStartCommand(Intent intent, int flags, int startId)
    • 每次启动服务时调用
  • onDestroy()
    • 服务销毁的时调用

3、在 AndroidManifest.xml 中注册服务

<application
....>
	<service android:name=".MyService">
	</service>
</application>

启动和停止服务

  • 借助 Intent 实现
public void onClick(View v){
	switch(v.getId()){
	case R.id.start_service:
		Intent startIntent = new Intent(this, MyService.class);
		startService(startIntent); // 启动服务
		break;
	case R.id.stop_service:
		Intent stopIntent = new Intent(this, MyService.class);
		stopService(stopIntent); // 停止服务
		break;
	default:
		break;
	}
}

活动和服务进行通信

  • onBind() 活动(Activity)指挥服务(Service)去干什么

活动开启、查看服务下载功能的例子:

服务(Service)

public class MyService extends Service{
// (2)实例化内部类
	private DownloadBinder mBinder = new DownloadBinder();

// (1)创建内部类
	class DownloadBinder extends Binder{
		
		public void startDownload(){
			//执行下载逻辑
		}
		public int getProgress(){
			//执行查看下载状态逻辑
		}
// (3)返回内部类实例
		@Override
		pubilc IBinder onBind(Intent intent){
			return mBinder;
		}
	}
}

活动(Activity)

private MyService.DownloadBinder downloadBinder; // 下载服务

//创建匿名类。重写解除绑定时调用的 onServiceDisconnected() 方法,绑定时调用的 ServiceConnected() 方法
private ServiceConnection connection = new ServiceConnection(){
	
	@Override
	public void onServiceDisconnected(ComponentName name){
		// 解除绑定的时候调用
	}

	@Override
	public void ServiceConnected(ComponentName name, IBinder service){
		//绑定时调用
		downloadBinder = (MyService.DownloadBinder) service;
		downloadBinder.startDownload();
		downloadBinder.getProgress();
	}
};

	@Override
	public void onClick(View v){
		switch(v.getId()){
		case R.id.bind_service:
			Intent bindIntent = new Intent(this, MyService.class);
			bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
		break;
		case R.id.unbind_service:
			unbindService(connection); //解绑服务
		break;
		default:
		break;
	}
}

服务的生命周期

  • 不管你调用了多少次 startService() 方法,只需要调用一次 stopService() 或 stopSelf() 方法,服务就会停止下来。
  • 服务没创建过,onCreate() 方法优先于任何方法执行。
  • 执行了 stopService() 和 unbindService() 都会调用 onDestroy() 方法。一个服务同时调用了 startService() 和 bindService() 要销毁服务必须同时调用stopService() 和 unbindService() 服务才会执行 onDestroy()。
  • 开启服务且绑定了服务,必须关闭且解绑才能销毁服务

这里写图片描述

服务的更多技巧


使用前台服务

public class MyService extends Service{
	...
	@Override
	public void onCreate(){
		...
		Notification notification = new Notification(R.drawable.ic_launcher, "Notification comes", System.currentTimeMillis());
		Intent notificationIntent = new Intent(this, MainActivity.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
		notification.setLatestEventInfo(this, "This is title", "This is content", pendingIntent);
		startForeground(1, notification);
		...
	}
	...
}

没有调用 NotificationManage 的 notify() 来将通知显示出来,而是调用了startForegrounnd( 第一:id第二:Notification对象 ),调用此方法就会让服务变成一个前台服务并在系统状态栏显示出来。


使用IntentService

  • 如果在服务里处理耗时操作会出现 ANR(Application Not Responding)情况。因此可以借助 Android 的多线程技术,即标准的服务形式如下:
public class MyService extends Service{
	
	@Override
	public IBinder onBind(Intent intent){
		return null;
	}
	@Override
	public int onStartCommand(Intent intent, int flags, int startId){
		new Thread(new Runnable(){
			@Override
			public void run(){
				//处理具体逻辑
				stopSelf(); //此服务开启后会一直处于运行状态。要想让它执行完毕后自动停止应进行此操作
			}
		}).start();
		return super.onStartCommand(intent, flags, startId);
	}
}
  • 总会有程序员忘记开启线程,并调用 stopSelf() 方法,因此 Android 提供了一个 IntentService类 来创建一个异步的会自动停止的服务

1、服务 Service

public class MyIntentService extends IntentService{
	
	public MyIntentService(){
		super("MyIntentService"); // 调用父类的有参构造函数
	}
	@Override
	protected void onHandleIntent(Intent intent){
		//处理一些具体的逻辑,而且不用担心ANR的问题。此方法已经在子线程中运行了
	}
	@Override
	public void onDestroy(){
		//这个服务在运行结束后会自动停止
		super.onDestroy();
	}
}

2、活动 Activity

Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);

3、AndroidManifest 注册

<service android:name=".MyIntentService"></service>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值