天天看点

Android学习-四大组件(Service)

今天复习Service,包括如何启动并结束一个服务、自定义服务、IntentService、活动与服务之间的通信、前台服务、异步处理以及书上写的一个无线循环的服务实践。

根据四大组件的特性,每定义一个新的服务,都要在AndroidManifest里面进行注册

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

自定义服务

自定义服务继承Service,然后可以重写里面的方法来实现逻辑

public class MyService extends Service{
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        Log.d("myservice", "onBind执行");
        return null;
    }
}
           

onBind()是父类中的抽象方法,必须实现。之后就是常见的onCreate,onStartCommand,onDestroy了

onCreate可以执行一些初始化的操作,只有在活动被创建的时候调用

onStartCommand执行主要的逻辑

onDestroy用来收尾

@Override
public void onCreate() {
    // TODO Auto-generated method stub
    Log.d("myservice", "onCreate执行");
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // TODO Auto-generated method stub
    Log.d("myservice", "onStartCommand执行");
    return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
    // TODO Auto-generated method stub
    Log.d("myservice", "onDestory执行");
    super.onDestroy();
}
           

启动和停止服务

在MainActivity中实现按钮操作即可

case R.id.start_service:
            Intent startService=new Intent(this,MyService.class);
            startService(startService);
            break;
case R.id.stop_service:
            Intent stopService=new Intent(this,MyService.class);
            stopService(stopService);
            break;
           

IntentService

IntentService可以在活动执行一次后自动结束,新建一个IntentService,并在MainActivity中绑定一个按钮,按钮点击事件同时打印MainActivity的线程id

public class MyIntentService extends IntentService{

    public MyIntentService() {
        super("MyIntentService");
        // TODO Auto-generated constructor stub
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // TODO Auto-generated method stub
        Log.d("myservice", "this thread id"+Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        Log.d("myservice", "intentService destroy");
        super.onDestroy();
    }
}
           

MainActivity中的点击事件

case R.id.start_intentservice:
            Intent intentService=new Intent(this,MyIntentService.class);
            Log.d("myservice", "main thread id"+Thread.currentThread().getId());
            startService(intentService);
            break;
           

log

Android学习-四大组件(Service)

服务和活动之间的通信

利用之前新建自定义活动的时候实现的onBind()函数,可以让服务与活动间进行通信

private MyBinder binder=new MyBinder();//新建MyBinder的对象

    class MyBinder extends Binder{//自定义内部类继承Binder,在里面用来实现自己需要的逻辑,比如这里的下载和返回下载进度

        public void startDownload() {
            Log.d("myservice", "startDownload");
        }

        public int downloadProgress() {
            Log.d("myservice", "downloadProgress");
            return ;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        Log.d("myservice", "onBind执行");
        return binder;//返回自定义类对象
    }
           

在活动中,利用ServiceConnection类来执行之前在Service中的自定义类里的方法

private MyService.MyBinder mybinder;
private ServiceConnection connection=new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {//绑定后会执行里面的操作
            // TODO Auto-generated method stub
            mybinder=(MyService.MyBinder)service;//向下转型
            mybinder.startDownload();
            int i=mybinder.downloadProgress();
            Log.d("myservice", ""+i);
        }
    };
           

然后在按钮事件中通过bindService和unbindService来绑定和取消绑定服务

case R.id.bind_service:
            Intent bindService=new Intent(this,MyService.class);
            bindService(bindService, connection, BIND_AUTO_CREATE);//标志位,传入BIND_AUTO_CREATE表示在活动和服务进行绑定后自动创建服务
            break;
        case R.id.unbind_service:
            unbindService(connection);
            break;
           

前台服务

比后台服务多一个正在运行的图标在状态栏里面,可以直接在onCreate里面写入一个Notification

@SuppressLint("NewApi")
    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        Notification.Builder nBuilder=new Notification.Builder(this);
        Intent intent=new Intent(this,Activity02.class);
        PendingIntent pIntent=PendingIntent.getActivity(this, , intent, );
        nBuilder.setTicker("前台通知来了")
                .setContentTitle("前台通知")
                .setContentText("这是一个前台通知")
                .setContentIntent(pIntent)
                .setSmallIcon(R.drawable.ic_launcher);
        startForeground(, nBuilder.build());
        Log.d("myservice", "onCreate执行");
        super.onCreate();
    }
           

一个Notification必须具备以下几个元素,不然不能显示

1.setSmallIcon

2.setContentText

3.setContentTitle

这样,服务启动的时候就可以自动创建一个前台通知一直在通知栏里

异步消息处理

Android不允许在子线程中进行UI的操作,所以可以通过异步消息处理来进行UI的操作

新建一个CHANGE参数用来识别操作,新建一个Handler用来操作UI

private Handler handler=new Handler(){

        public void handleMessage(Message msg) {
            switch (msg.what) {
            case CHANGE:
                textView.setText("Text02");
                break;

            default:
                break;
            }
        }
    };
           

因为这个是在主线程中的,所以可以对UI进行操作,然后用子线程通过发送Message来让handler执行对应的操作,从而起到改变UI的效果

case R.id.change_text:
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    Message message=new Message();
                    message.what=CHANGE;
                    handler.sendMessage(message);
                }
            }).start();//别忘了start
            break;
           
start在最后面,有时候容易忽略而忘记启动线程,这里要注意一下

后台定时循环操作

整体的实现思路是

自定义服务-onStartCommand里执行需要的操作(比如打印此时的时间),然后利用AlarmManager来执行定时操作,操作中利用广播在广播接收器中再次打开服务

public class AlarmBroadcast extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        Intent intent2=new Intent(context,AlarmService.class);
        context.startService(intent2);
    }
}
           
注意这里是Context

AlarmManager使用方法

1.新建AlarmManager类

2.定义执行的时间

3.AlarmManager.set()执行操作

public class AlarmService extends Service{

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        Log.d("myservice", "Alarm onCreate");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                Log.d("myservice", "Time is "+new Date().toString());
            }
        }).start();//记得start
        AlarmManager alarmManager=(AlarmManager) getSystemService(ALARM_SERVICE);
        long triggerTime=SystemClock.elapsedRealtime()+*;//获取开机以来的毫秒数+30秒
        Intent intent2=new Intent(this,AlarmBroadcast.class);
        PendingIntent pIntent=PendingIntent.getBroadcast(this, , intent2, );//此处应调用getBroadcast
        /*
         * 下面第一个参数表示类型,此处的表示任务执行时间为从开机时间算起之后多少多少毫秒
         * 这里就是上面的triggerTime
         * 并且唤醒CPU
        */
        alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, pIntent);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        Log.d("myservice", "Alarm onDestroy");
        super.onDestroy();
    }

}
           

AlarmManager.set()中第一个参数表示执行操作的模式,一共有4中,分别是ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC和RTC_WAKEUP,他们的作用如下

参数名 作用
ELAPSED_REALTIME 定时任务的触发时间从系统开机开始算起,但不会唤醒CPU
ELAPSED_REALTIME_WAKEUP 定时任务的触发时间从系统开机开始算起,会唤醒CPU
RTC 定时任务的触发时间从1970年1月1日0点开始算起,但不会唤醒CPU
RTC_WAKEUP 定时任务的触发时间从1970年1月1日0点开始算起,会唤醒CPU

第二个参数表示以第一个参数为参考,操作执行的延迟时间,比如这里第一个参数是ELAPSED_REALTIME_WAKEUP,延迟时间为SystemClock.elapsedRealtime()+30*1000毫秒,SystemClock.elapsedRealtime()用来获取开机以后到现在为止的毫秒数,所以这里的意思就是说,以开机时间为起点,操作在(已开机的时间+30秒)后执行

第三个参数就是PendingIntent,即要执行的操作,这里因为是要调用广播接收器,所以用的是getBroadcast而不是getActivity

执行结果

Android学习-四大组件(Service)