美文网首页
服务的基本用法

服务的基本用法

作者: TTTqiu | 来源:发表于2016-05-07 19:33 被阅读279次
    • 服务(Service)是 Android 中实现程序后台运行的解决方案,它非常适合用于去执行那些不需要和用户交互而且还要求长期运行的任务。
    • 服务并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行。
    • 服务并不会自动开启线程,所有的代码都是默认运行在主线程当中的。也就是说,我们需要在服务的内部手动创建子线程,并在这里执行具体的任务。

    一、定义服务


    public class MyService extends Service {
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    }
    
    • **onBind() **方法,用于活动和服务进行通信。
    • **onCreate() **方法会在服务创建的时候调用。
    • **onStartCommand() **方法会在每次服务启动的时候调用。
    • **onDestroy() **方法会在服务销毁的时候调用。
    • 需要在 AndroidManifest.xml 文件中进行注册:
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.servicetest"
        android:versionCode="1"
        android:versionName="1.0" >
    ......
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
    ......
            <service android:name=".MyService" >
            </service>
    
        </application>
    </manifest>
    

    二、启动和停止服务


    1. 创建 Intent,再在活动中用 startService() 方法启动服务。
    Intent startIntent = new Intent(this, MyService.class);
    startService(startIntent); // 启动服务
    
    • 服务还未创建过onCreate()、**onStartCommand() **两个方法都会执行。
    • 服务已经创建过,则只有 **onStartCommand() **方法可以得到执行了。
    2. 创建 Intent,再在活动中用 stopService() 方法停止服务。
    Intent stopIntent = new Intent(this, MyService.class);
    stopService(stopIntent); // 停止服务
    
    • 若要服务自己停止,只需要在服务类的任何一个位置调用 **stopSelf() **方法就行。

    三、活动和服务进行通信


    在 MyService 中:

    1. 创建内部类 MyBinder 继承自 Binder,里面是活动需要调用的内容。
    2. 在 MyService 中创建 MyBinder 的实例。
    3. 在 onBind() 方法里返回这个实例 mBinder。
    public class MyService extends Service {
        private DownloadBinder mBinder = new DownloadBinder();
        class DownloadBinder extends Binder {
            public void startDownload() {
                Log.d("MyService", "startDownload executed");
            }
            public int getProgress() {
                Log.d("MyService", "getProgress executed");
                return 0;
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    .....
    }
    

    在 MainActivity 中:

    1. 创建 ServiceConnection 的匿名类实例,重写 onServiceConnected() 方法和 onServiceDisconnected() 方法。
    • 这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用。
    2. 在 onServiceConnected() 方法中,通过向下转型得到 MyBinder 的实例。
    • 有了这个实例,可以在活动中根据具体的场景来调用 MyBinder 中的任何 public 方法。

    绑定活动和服务:

    1. 创建 Intent。
    2. 用 bindService() 方法绑定活动和服务。
    • 第一个参数:Intent
    • 第二个参数:ServiceConnection 的实例
    • 第三个参数:这里传入** BIND_AUTO_CREATE** 表示在活动和服务进行绑定后自动创建服务,即执行 onCreate() 方法。
    3. 用 unbindService() 方法解除绑定。
    • 参数:ServiceConnection 的实例
    public class MainActivity extends Activity implements OnClickListener {
        private Button startService;
        private Button stopService;
        private Button bindService;
        private Button unbindService;
    
        private MyService.DownloadBinder downloadBinder;
    
        private ServiceConnection connection = new ServiceConnection() {
    
            @Override
                public void onServiceDisconnected(ComponentName name) {
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                downloadBinder = (MyService.DownloadBinder) service;
                downloadBinder.startDownload();
                downloadBinder.getProgress();
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ......
            bindService = (Button) findViewById(R.id.bind_service);
            unbindService = (Button) findViewById(R.id.unbind_service);
            bindService.setOnClickListener(this);
            unbindService.setOnClickListener(this);
        }
    
        @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;
            }
        }
    }
    

    四、服务的生命周期


    1. 调用 **startService() 方法,相应的服务就会启动起来,并回调 onStartCommand() 方法。如果这个服务之前还没有创建过onCreate() 方法会先于 onStartCommand() **方法执行。
    2. 服务启动了之后会一直保持运行状态,直到 stopService() 或 **stopSelf() **方法被调用。
    3. 还可以调用** bindService() 来获取一个服务的持久连接,这时就会回调服务中的 onBind() 方法。如果这个服务之前还没有创建过onCreate()** 方法会**先于 onBind() **方法执行。
    4. 当调用了** startService() **方法后,又去调用 stopService() 方法,这时服务中的 onDestroy() 方法就会执行,表示服务已经销毁了。
    5. 当调用了 **bindService() **方法后,又去调用 unbindService() 方法,onDestroy() 方法也会执行
    6. 需要注意的是,当对一个服务既调用了 startService() 方法又调用了 bindService() 方法一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被销毁。所以,这种情况下要同时调用 stopService() 和 unbindService() 方法onDestroy() 方法才会执行

    五、服务的更多技巧


    1. 使用前台服务

    • 前台服务会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。如天气应用经常要用到。
    • 希望服务可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台服务。
    Notification.Builder builder = new Notification.Builder(MainActivity.this);
    builder.setSmallIcon(R.drawable.ic_launcher);
    builder.setContentTitle("title");
    builder.setContentText("text");
    builder.setWhen(System.currentTimeMillis()); // 显示时间
    
    Intent intent=new Intent(MainActivity.this,Main2Activity.class);
    PendingIntent pi=PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);
    builder.setContentIntent(pi);
    
    Notification notification = builder.build();
    
    startForeground(1, notification);
    

    使用很简单,就是把创建 Notification 方法里的 manager.notify(1, notification); 换成 startForeground(1, notification);

    2. 使用 IntentService

    • 服务中的代码都是默认运行在主线程当中的,如果直接在服务里去处理一些耗时的逻辑,就很容易出现 ANR(Application Not Responding)的情况。
    • 所以对于一些耗时操作,需要在服务中开启子线程执行。
    • 因为服务启动后会一直处于开启状态,有时也会希望服务在执行完毕后自动停止。可以这样写。
    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);
        }
    }
    
    • 为了可以简单地创建一个异步的、会自动停止的服务,Android 专门提供了一个 IntentService 类:
    public class MyIntentService extends IntentService {
    
        public MyIntentService() {
            super("MyIntentService"); // 调用父类的有参构造函数
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            // 打印当前线程的id
            Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d("MyIntentService", "onDestroy executed");
        }
    }
    
    1. 首先要提供一个无参的构造函数,并且必须在其内部调用父类的有参构造函数。
    2. 在子类中去实现** onHandleIntent()** 这个抽象方法,这个方法已经是在子线程中运行的了。
    3. 根据 IntentService 的特性,这个服务在运行结束后应该是会自动停止的,即执行** onDestroy()** 方法。

    相关文章

      网友评论

          本文标题:服务的基本用法

          本文链接:https://www.haomeiwen.com/subject/izvrrttx.html