Service

本文是阅读《第一行代码》第10章学习笔记

Service 是一种计算型组件,用于在后台处理一系列计算任务。
Service的两种状态:启动和绑定。
Service本身运行在主线程中,因此耗时的操作仍然需要在单独的线程中去完成。
Service 组件处于绑定状态时,这时候同样可以进行后台计算,但是处于这种状态时外界很方便和Service组件进行通信。
任何一个服务在整个程序范围内都是通用的,即MyService可以和任何一个Activity进行绑定。
onBind 返回一个Binder对象给绑定者,是因为Service组件可能是运行在两个不同的应用进程中的。

1.继承Service

public class MyService extends Service {

    private DownLoadBinder downLoadBinder = new DownLoadBinder();

    public class DownLoadBinder extends Binder {

        public void startDownload() {
            Log.e("MyService", "DownLoadBinder execute.");
        }

        public int getProgress() {
            Log.e("MyService", "DownLoadBinder getProgress.");
            return 0;
        }

    }

    public MyService() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return downLoadBinder;
    }
//创建时调用
    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        Log.e("MyService", "onCreate");
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent paIntent = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("title")
                .setContentText("content")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.ic_btn_speak_now)
                .setLargeIcon(
                        BitmapFactory.decodeResource(getResources(),
                                R.drawable.ic_btn_speak_now))
                .setContentIntent(paIntent).build();
        startForeground(1, notification);

    }

    // 一开始就开始执行的任务 将其逻辑写在 onStartCommand
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("MyService", "onStartCommand");
        new Thread(new Runnable() {

            @Override
            public void run() {
                // 处理的具体逻辑
                Log.e("MyService", "onStartCommand run");
//              stopSelf();
            }
        }).start() ;


        return super.onStartCommand(intent, flags, startId);
    }

    // 服务销毁时调用 在onDestroy销毁那些不再使用的资源。
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        Log.e("MyService", "onDestroy");
        super.onDestroy();
    }

}

2.每一个服务都需要在AndroidManifest,xml中注册

  <!--
             exported 允许当前程序之外的其他程序访问这个服务 
             enabled 属性表示是否启用这个服务   
        -->
        <service
            android:name="service.MyService"
            android:enabled="true"
            android:exported="true" >
        </service>

3.启动、停止服务

a.在Activity中启动服务、停止服务。b.在服务中调用stopSelf()方法停止服务。

// 启动服务
            Intent startIntent = new Intent(this, MyService.class);
            startService(startIntent);
            break;
// 停止服务
            Intent stopIntent = new Intent(this, MyService.class);
            stopService(stopIntent);

4.活动和服务进行通信

onBind(), 新建一个DownLoadBinder继承自Binder,在Activity中调用。
在Activity中新建一个ServiceConnection的匿名类,onServiceConnected、onServiceDisconnected分别在Activity和Service绑定成功和解除绑定时调用。在onServiceConnected中又通过向下转型得到了DownLoadBinder,有了这个实例活动和服务之间的关系就十分紧密了。在Activity中可以调用服务所有public方法。

public class MainActivity extends Activity implements OnClickListener {
    private MyService.DownLoadBinder downLoadBinder;
//  活动和服务之间的通信
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downLoadBinder = (DownLoadBinder) service;
            downLoadBinder.startDownload();
            downLoadBinder.getProgress();
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn_startService).setOnClickListener(this);
        findViewById(R.id.btn_stopService).setOnClickListener(this);
        findViewById(R.id.btn_bindService).setOnClickListener(this);
        findViewById(R.id.btn_unbindService).setOnClickListener(this);
        findViewById(R.id.start_intent_service).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_startService:
            // 启动服务
            Intent startIntent = new Intent(this, MyService.class);
            startService(startIntent);
            break;
        case R.id.btn_stopService:
            // 停止服务
            Intent stopIntent = new Intent(this, MyService.class);
            stopService(stopIntent);
            break;
        case R.id.btn_bindService:
            // 绑定服务
            Intent bindIntent = new Intent(this, MyService.class);
//          BIND_AUTO_CREATE 表示活动和服务进行绑定后自动创建服务。
            bindService(bindIntent, connection, BIND_AUTO_CREATE);
            break;
        case R.id.btn_unbindService:
//          解绑服务
            unbindService(connection);
        break;
        case R.id.start_intent_service:
//
            // 打印当前线程的id
            Log.e("MainActivity", "Thread  id is "
                    + Thread.currentThread().getId());
            Intent intentService = new Intent(this, MyIntentService.class);
            startService(intentService);
            break;
        default:
            break;
        }
    }
}

5.服务的生命周期。

a.在项目的任何位置调用了Context的startService()方法,相应的服务就会启动起来,并回调onStartCommand()方法。
b.如果服务没有创建过,onCreate()方法会先于onStartCommand()方法执行。
c.服务启动后会一直保持运行状态,直到stopService()或stopSelf()方法被调用。
d.每调用一次startService(),onStartCommand()就执行一次,但实际上每个服务都只会存在一个实例,所以不管你调用了多少次startService(),只需调用一次stopService()或stopSelf(),服务就会停下来。
e.若调用Context的bindService()来获取一个服务的持久连接这时就会,回掉服务中的onBind()方法。类似的这个服务之前还没有创建过,onCreate()方法会先于onBind()方法执行。之后,调用方可以获取到onBind()方法里返回的IBinder对象实例,这样就能自由的和服务进行通信了。只要调用方和服务方之间的链接没有断开,服务就一直保持运行状态。
f.调用过startService()后,再调用stopService() ,onDestroy()执行服务销毁。
调用过bindService()后,再调用unbindService() ,onDestroy()执行服务销毁。
既调用startService(),又调用bindService() 后,根据Android设计机制,一个服务只要被绑定或者启动后,就会一直处于运行状态,必须让以上两个状态同时不满足才能被销毁,所以这中状态下要同时调用stopService()和unbindService()方法,onDestroy()才会执行。

6.前台服务。

服务一般都是在后台运行的,服务的系统优先级比价低的,当系统出现内存不足的情况时,就有可能回收后台正在运行的服务。前台服务可以解决这个问题,当然特殊的需求也会要求必须使用前台服务,比如天气预报软件。
前台服务和普通服务的最大区别,他会一直有一个正在运行的图标在系统的状态显示栏,下拉状态栏后会看见更加详细的信息,非常类似于通知的效果。
在MyService的onCreate中添加代码。
startForeground(int id, Notification notification)方法第一个参数是通知的id,类似于notify()方法的第一个参数,第二个参数表示创建出的Notification对象,调用startForeground()方法后就会让MyService变成一个前台服务,并在系统状态栏显示出来。
调用startService()或bindService()MyService就会以前台服务的模式启动了,并且在系统状态栏显示一个通知图标。
PendingIntent是在将来某个不确定时刻发生。Intent是立刻发生。PendingIntent支持3种特定的意图:启动Activity、启动Service和发送广播。

@Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        Log.e("MyService", "onCreate");
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent paIntent = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("title")
                .setContentText("content")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.ic_btn_speak_now)
                .setLargeIcon(
                        BitmapFactory.decodeResource(getResources(),
                                R.drawable.ic_btn_speak_now))
                .setContentIntent(paIntent).build();
        startForeground(1, notification);

    }

7.使用IntentService

Service本身运行在主线程中,因此耗时的操作仍然需要在单独的线程中去完成。
关闭服务的方法:stopService()、stopSelf() (服务执行完毕后自动停止)、使用IntentService。

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("MyService", "onStartCommand");
        new Thread(new Runnable() {

            @Override
            public void run() {
                // 处理的具体逻辑
                Log.e("MyService", "onStartCommand run");
                // stopSelf(); 服务执行完毕后自动停止
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

使用IntentService
提供一个无参构造函数,必须调用父类的有参构造函数。然后在子类中实现onHandleIntent(),在这个方法中可以处理一些具体的逻辑,由于该方法运行在子线程中,不用担心出现ANR的问题。

public class MyIntentService extends IntentService {

    public MyIntentService() {
//      必须调用父类的有参构造函数
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印当前线程的id
        Log.e("MyIntentService", "Thread  id is "
                + Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("MyIntentService", "onDestroy executed.");
    }
}

启动:

Intent intentService = new Intent(this, MyIntentService.class);
            startService(intentService);
### Service的生命周期和状态 Service在Android系统中可以分为两种主要状态:启动状态和绑定状态。当一个Service被启动后,它会在后台长时间运行,即使启动它的组件已经被销毁,Service仍然可以继续运行[^2]。如果一个Service既被启动又被绑定,那么它会同时处于这两种状态。 ### Service的生命周期方法 自定义的Service需要继承`Service`基类,并且通常需要重写一些生命周期方法来实现特定的功能: - `onCreate()`:当Service第一次创建时调用。如果Service已经存在,则不会调用此方法。 - `onStartCommand(Intent intent, int flags, int startId)`:当其他组件通过调用`startService()`方法请求启动Service时调用。在这个方法里可以处理长时间运行的操作。 - `onBind(Intent intent)`:当其他组件通过调用`bindService()`方法绑定到Service时调用。该方法返回一个`IBinder`接口,允许客户端与Service进行通信。 - `onUnbind(Intent intent)`:当所有绑定到Service的客户端都解绑后调用。 - `onDestroy()`:当Service不再使用并被销毁时调用。这是释放资源的好时机。 ### 启动状态下的Service 当一个Service通过调用`startService()`方法启动时,它进入启动状态。在这种状态下,Service独立于启动它的组件运行,直到它自己停止或被系统终止。要停止这样的Service,可以在Service内部调用`stopSelf()`方法,或者从外部组件调用`stopService()`方法[^1]。 ### 绑定状态下的Service 当组件通过调用`bindService()`方法绑定Service时,Service进入绑定状态。此时,组件可以通过`ServiceConnection`对象获取到Service提供的`IBinder`对象,从而与Service进行交互。绑定状态下的Service可以被多个组件绑定,只有当所有绑定的组件都解绑后,Service才会被销毁[^3]。 ### Service的声明 无论哪种类型的Service,都需要在`AndroidManifest.xml`文件中声明。声明格式如下: ```xml <service android:name=".Demo2Service" /> ``` 其中`.Demo2Service`是你的Service类名[^2]。 ### Service的绑定过程 为了与Service进行交互,组件需要创建一个`ServiceConnection`实例,并实现其`onServiceConnected()`和`onServiceDisconnected()`回调方法。例如: ```java private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { // 这里 IBinder类型的service 就是我们要绑定的那个service // 通过这个service,Activity就可以调用MyBindService.MyBinder中的方法 } @Override public void onServiceDisconnected(ComponentName name) { Log.i(TAG, "onServiceDisconnected: "); } }; ``` 然后,组件可以通过调用`bindService()`方法来绑定Service,并在不需要时调用`unbindService()`方法来解绑[^5]。 ### Service的应用场景 Service非常适合用来执行那些不需要用户界面但需要长时间运行的任务。比如播放音乐、下载文件、处理网络请求等。此外,Service还可以与其他组件进行交互,包括跨进程通信(IPC)[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值