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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值