• Android四大组件之- Service的创建与应用


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    前言

    Service分为两种:一种是普通的Service,一种是IntentService。
    启动Service的方式也有两种:一种是StartService()启动,一种是BindService()启动。本文重点介绍两种Service的区别和两种启动方式的区别。
    本文主要是代码居多,通过代码运行的log打印,观察service的生命周期和特性来达到理解service的目的

    一、startservice启动service

    启动:
    it = new Intent(MainActivity.this, StartFiring.class);
    startService(it);
    关闭:stopService(it);

    StartFiring.java

    public class StartFiring extends Service {
        public StartFiring() {
        }
        
        //该方法是Service都必须实现的方法,该方法会返回一个 IBinder对象,app通过该对象与Service组件进行通信!
        //不需要通信时不会调用此方法
        @Override
        public IBinder onBind(Intent intent) {
            Log.d("StartFiring", "onBind()");
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
    
        }
    
        //当Service第一次被创建后立即回调该方法,该方法在整个生命周期 中只会调用一次!
        @Override
        public void onCreate() {
            super.onCreate();
            Log.d("StartFiring", "onCreate()");
        }
    
    
        //    1.使用startService启动servic时调用
        //   2.多次使用startService启动servic时,不会创建新的Service对象(也就是不会多次调用onCreate方法),但是会多次调用onStartCommand()方法
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d("StartFiring", "onStartCommand()");
            return super.onStartCommand(intent, flags, startId);
        }
    
        //当Service被关闭时会回调该方法,该方法只会回调一次!
        @Override
        public void onDestroy() {
            Log.d("StartFiring", "onDestroy()");
            super.onDestroy();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    二、bindservice启动service

    bindservice启动稍微复杂一点,直接上代码,文章最后会有对比总结

    MainActivity.java

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private TextView bt;
        private TextView bt2;
        private TextView bt3;
        private Intent it = null;
        MyService.MyBinder binder;
        private ServiceConnection conn = new ServiceConnection() {
    
            //Service服务被意外销毁时调用,如内存资源不足
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d("MainActivity", "onServiceDisconnected()断开连接");
            }
    
            //Activity与Service连接成功时回调该方法
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d("MainActivity", "onServiceConnected()连接成功");
                binder = (MyService.MyBinder) service;  //获取servicer的数据
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
    
        private void initView() {
            bt = (TextView) findViewById(R.id.bt);
            bt2 = (TextView) findViewById(R.id.bt2);
            bt3 = (TextView) findViewById(R.id.tex);
            bt3.setOnClickListener(this);
            bt.setOnClickListener(this);
            bt2.setOnClickListener(this);
            it = new Intent(MainActivity.this, MyService.class);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.bt:
                    //绑定service
                    bindService(it, conn, Service.BIND_AUTO_CREATE);
                    break;
                case R.id.bt2:
                    //解除绑定
                    unbindService(conn);
                    break;
                case R.id.tex:
                    Log.d("MainActivity", "count值为:" + binder.getCount());
                    break;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    MyService.java

    public class MyService extends Service {
        private int count;
        private boolean quit = true;
        
        /*
            1.自定义一个内部类继承Binder,类中定义读取service数据的方法,将servie要传递给activity的数据放入Binder对象中
            2.创建内部类对象,onBind方法返回这个对象
            3.activity中通过ServiceConnection的回调方法onServiceConnected()拿到service传递的binder对象
            4.activity调用binder对象中的方法读取servie传递的数据
    
        */
        //自定义一个内部类继承Binder,类中定义读取service数据的方法,将
        public class MyBinder extends Binder {
            //定义读取service数据的方法
            public int getCount() {
                return count;
            }
        }
    
        private MyBinder binder = new MyBinder();
    
        //与activity交互,返回给activity一个IBinder对象
        //
        @Override
        public IBinder onBind(Intent intent) {
            Log.d("MyService", "onBind()");
            return binder;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.d("MyService", "onCreate()");
            new Thread() {
                public void run() {
                    while (quit) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count++;
                    }
                }
            }.start();
        }
    
        @Override
        public void onDestroy() {
    
            Log.d("MyService", "onDestroy()");
            super.onDestroy();
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            quit = false;
            Log.d("MyService", "onUnbind()");
            return super.onUnbind(intent);
        }
    
        @Override
        public void onRebind(Intent intent) {
            super.onRebind(intent);
            Log.d("MyService", "onRebind()");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    三、Intentservice

    MainActivity.java :做了三个启动按钮,每个启动携带的参数不一样,更直观的看到Intentservice的生命周期

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private Button bt;
        private Button tex;
        private Button bt2;
        private Intent it = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
    
        private void initView() {
            bt = (Button) findViewById(R.id.bt);
            tex = (Button) findViewById(R.id.tex);
            bt2 = (Button) findViewById(R.id.bt2);
    
            bt.setOnClickListener(this);
            tex.setOnClickListener(this);
            bt2.setOnClickListener(this);
            it = new Intent(this, MyIntentService.class);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.bt:
                    Bundle bd = new Bundle();
                    bd.putString("a", "a");
                    it.putExtras(bd);
                    startService(it);
                    break;
                case R.id.tex:
                    Bundle bd2 = new Bundle();
                    bd2.putString("a", "b");
                    it.putExtras(bd2);
                    startService(it);
                    break;
                case R.id.bt2:
                    Bundle bd3 = new Bundle();
                    bd3.putString("a", "c");
                    it.putExtras(bd3);
                    startService(it);
                    break;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    MyIntentService.java :可通过Intent传递的不同数据执行不同的代码块

    public class MyIntentService extends IntentService {
        //必须实现父类的构造方法
        public MyIntentService() {
            super("MyIntentService");
        }
    
        //必须重写的核心方法,通过activity传递的intent数据执行不同的代码
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.d("MyIntentService", "onHandleIntent");
            String actin = intent.getExtras().getString("a");
            if (actin.equals("a")) {
                Log.d("MyIntentService", "第一个启动按钮");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //执行具体事务
                        try {
                            Thread.sleep(10000);
                            Log.d("MyIntentService", "Thread1停止");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            } else if (actin.equals("b")) {
                Log.d("MyIntentService", "第二个启动按钮");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //执行具体事务
                        try {
                            Thread.sleep(10000);
                            Log.d("MyIntentService", "Thread2停止");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            } else if (actin.equals("c")) {
                Log.d("MyIntentService", "第三个启动按钮");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //执行具体事务
                        try {
                            Thread.sleep(10000);
                            Log.d("MyIntentService", "Thread3停止");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            } else {
                Log.d("MyIntentService", "其他");
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            Log.d("MyIntentService", "onBind");
            return super.onBind(intent);
        }
    
        @Override
        public void onCreate() {
            Log.d("MyIntentService", "onCreate");
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d("MyIntentService", "onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void setIntentRedelivery(boolean enabled) {
            super.setIntentRedelivery(enabled);
            Log.d("MyIntentService", "setIntentRedelivery");
        }
    
        @Override
        public void onDestroy() {
            Log.d("MyIntentService", "onDestroy");
            super.onDestroy();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    四、Intentservice和全局变量结合使用

    首先MainActivity还是与上文Intentservice一样三个启动按钮,每个启动按钮启动携带不同的参数,创建一个Handler和计时器定时读取全局变量的值

    然后创建一个实体类:EntityTest.java

    public class EntityTest{
        public static int a = 0;
        public static int b = 0;
        public static int c = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    最后是Intentservice中的核心代码(部分需要重写的方法没有贴上)

    public class MyIntentService extends IntentService {
        private boolean x = true;
        private boolean m = true;
        private boolean y = true;
    
        //必须实现父类的构造方法
        public MyIntentService() {
            super("MyIntentService");
        }
        //必须重写的核心方法,通过activity传递的intent数据执行不同的代码
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.d("MyIntentService", "onHandleIntent");
            String actin = intent.getExtras().getString("a");
            if (actin.equals("a")) {
                Log.d("MyIntentService", "第一个启动按钮");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //执行具体事务
                        while (x) {
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            MyBinder.a++;
                            if (MyBinder.a == 20) {
                                x = false;
                            }
                        }
                    }
                }).start();
            } else if (actin.equals("b")) {
                Log.d("MyIntentService", "第二个启动按钮");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //执行具体事务
                        while (m) {
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            MyBinder.b++;
                            if (MyBinder.b == 20) {
                                m = false;
                            }
                        }
                    }
                }).start();
            } else if (actin.equals("c")) {
                Log.d("MyIntentService", "第三个启动按钮");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //执行具体事务
                        while (y) {
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            MyBinder.c++;
                            if (MyBinder.c == 20) {
                                y = false;
                            }
                        }
                    }
                }).start();
            } else {
                Log.d("MyIntentService", "其他");
            }
    
        }
        @Override
        public IBinder onBind(Intent intent) {
            Log.d("MyIntentService", "onBind");
            return null;
        }
    }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    五、前台服务的实现

    前台服务启动和关闭同样与讲解的启动方式一样,这里贴一下service的代码
    MyService.java

    public class MyService extends Service {
        String id = "logcat";
        String name = null;
        NotificationManager ntmg = null;
        NotificationChannel notcl;
        NotificationCompat.Builder bud;
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            throw new UnsupportedOperationException("Not yet implemented");
        }
        
        //当Service第一次被创建后立即回调该方法,该方法在整个生命周期 中只会调用一次!
        @Override
        public void onCreate() {
            super.onCreate();
            Log.d("StartFiring", "onCreate()");
    
            //发送log打开的通知
            name = getString(R.string.app_name);
            ntmg = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            // 1.创建NotificationChannel对象,传入id name 和 重要级别
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                notcl = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH);
                // 2.创建通知的通道
                ntmg.createNotificationChannel(notcl);
            }
            Intent intents = new Intent(MyService.this, MainActivity.class);
            PendingIntent pits = PendingIntent.getActivity(MyService.this, 0, intents, 0);
            bud = new NotificationCompat.Builder(MyService.this, id);
            bud.setContentTitle("前台service服务端")
                    .setContentText("正在运行...")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(MyService.this.getResources(), R.drawable.ic_launcher_foreground))
                    .setContentIntent(pits);
            //发送通知( id唯一,可用于更新通知时对应旧通知; 通过mBuilder.build()拿到notification对象 )
            startForeground(1,bud.build());
            ntmg.notify(1, bud.build());
    
        }
    
        //    1.使用startService启动servic时调用
        //   2.多次使用startService启动servic时,不会创建新的Service对象(也就是不会多次调用onCreate方法),但是会多次调用onStartCommand()方法
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d("StartFiring", "onStartCommand()");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            Log.d("StartFiring", "onDestroy()");
            super.onDestroy();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    六、后台服务的实现

    同样只贴service核心代码,以下代码执行流程:在activity中打开一次service,进入到service后执行具体的事物,并且间隔两秒发送一个广播,收到广播后再次自动启动service,如此形成循环,涉及到广播的内容下一篇讲解

    /*
        手动打开一次线程后,执行具体的事务,然后间隔2秒进入广播,进入广播后在广播中再次启动线程,如此形成循环操作
    */
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            //这里开辟一条线程,用来执行具体的逻辑操作:
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //循环执行的事务
                    Log.d("BackService", new Date().toString());
                }
            }).start();
    
            manager = (AlarmManager) getSystemService(ALARM_SERVICE);
            //设置循环时间,每隔两秒循环一次
            int anHour = 2 * 1000;
            long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
            Intent i = new Intent(this, MyReceiver.class);
            pi = PendingIntent.getBroadcast(this, 0, i, 0);
            manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
            return super.onStartCommand(intent, flags, startId);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    总结

    startservice启动普通service:无法通信,可以启动多次,多次启动仅执行一次onCreate方法,但执行多次onStartCommand方法
    startservice启动IntentService:可通过inten传递数据到service
    bindservice启动普通service:颗获取service中的数据,只能启动一次
    bindservice启动IntentService:无实际应用

    启动IntentService:
    1.activity可以通过inten传递数据到service
    2.service通过传递过来的不同参数执行不同操作
    3.service执行完毕后会自动关闭

  • 相关阅读:
    Linux-操作1(替换文本内容)
    基于springboot+vue的中小企业财务管理系统(源码+论文)
    【微服务实战之Docker容器】第四章-【微服务实战之Docker容器】第三章-镜像仓库
    2023研究生数学建模D题思路
    数字化转型导师鹏:政府数字化转型政务服务类案例研究
    面试学习总结
    自学视觉SLAM(1)
    【基础建设】浅谈企业网络安全运营体系建设
    暴雪和网易分手百万玩家何去何从
    《视觉 SLAM 十四讲》V2 第 10 讲 后端优化2 简化BA 【位姿图】
  • 原文地址:https://blog.csdn.net/2301_77563065/article/details/132584924