Android第一行代码——第十章探究服务

服务是什么

 服务是Android中实现程序后台运行解决方案,非常适合去执行那些不需要和用户交互而且还要长期运行的任务。

Android多线程编程

线程的基本用法

Android多线程和java多线程基本都使用相同的语法,下面展示两种写法

 class MyThread extends Thread{
    
    
                    public void run(){
    
    
                        //具体的操作逻辑
                    }
                }
                new MyThread().start();
 class MyRunable implements Runnable{
    
    

                    @Override
                    public void run() {
    
    

                    }
                }
                new Thread(new MyRunable()).start();

在子线程中更新UI

 Android中UI是线程不安全的,如果要更新应用程序里的UI元素,必须在主线程中进行
  异步消息处理机制:完美的解决了子线程中进行UI操作的问题

  1. 原理: 由4部分组成
方法 解析
Message 用于线程之间传递信息,在不同的线程间交换数据
handler 处理者的意思,用于发送和处理信息
MessageQueue 消息队列,用于存放所有通过Handler发送的信息,每个线程中只有一个MessageQueue对象
Looper 每个线程中MessageQueue的管家,调用Looper的loop()方法之后,就会进入到一个无限循环中,每当发现MessageQueue中存在一条消息,就会将他取出,并传递到Handler的handleMessage()

流程:当创建一个Message对象,并通过header将这条消息发送出去时,这条消息就会被添加到消息队列中等待被处理,而looper则会一直尝试从MessageQueue中取出待处理的信息,最后分发回Header的handleMessage()方法中。由于Hander是在主线程创建的,所以此时的handerMessage()方法在主线程运行
在这里插入图片描述

  1. 应用
    runOnUIThread():他是一个异步消息处理机制的接口封装。
 runOnUiThread(new Runnable() {
    
    
        @Override
        public void run() {
    
    
        这里可用于更新UI
        }
});

AsyncTask()
android提供的方便在子线程中对UI操作的工具,原理也是基于异步消息处理机制。
他是一个抽象类,想要使用他就要创建一个子类去继承他。有三个参数

参数名 作用
Params 在执行AsyncTask时需要传入的参数,可用于在后台任务中使用
Progress 后台任务执行时,如果需要显示进度,使用这里指定的泛型作为进度单位
Result 当任务执行完毕后,如果需要对结果返回,实用这里的泛型作为返回类型
	TextView textView;
    ProgressDialog progressDialog;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.text);
        new MyAskncTask().execute();        //调用

    }
 class MyAskncTask extends AsyncTask<Void,Integer,Boolean> {
    
    
        private int downloadPercent;
        @Override
        protected void onPreExecute() {
    
    
            //后台任务执行之前调用,进行一些界面的初始化操作
            super.onPreExecute();
            progressDialog = new ProgressDialog(MainActivity.this);
            progressDialog.show();
        }


        @Override
        protected Boolean doInBackground(Void... voids) {
    
    
            //这个方法所有的代码都在子线程中运行,在这里处理费时操作
            while (true){
    
    
                downloadPercent+=1;
                publishProgress(downloadPercent);
                if(downloadPercent>=10000)
                    break;
            }
            return true;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
    
    
            //当后台任务中调用了publishProgress(Progress...)方法之后,该方法很快被调用,可进行一些UI操作
            progressDialog.setTitle("123");
            progressDialog.setMessage(values[0]+"%");
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPostExecute(Boolean aBoolean) {
    
    
            //当后台任务执行完毕并通过return语句返回时,这个方法很快被调用,返回的数据会传入到这个方法中
            super.onPostExecute(aBoolean);

        }
    }

服务的基本用法

定义一个服务

可用Android stdio的快捷创建方式,右击com.example.app->new->Service->Service。
也可自定义服务

  1. 创建一个类继承自Service类,重写onBind()方法,这个是用于和活动通信的。
public class ServiceTest extends Service {
    
    
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    
    
        return null;
    }
}
  1. 在AndroidMAnifest.xml文件中注册
 <service
     android:name=".MyService"
     android:enabled="true"		//是否启用这个服务
     android:exported="true">	//是否允许除了当前程序之外的其他程序访问这个服务
 </service>

服务的生命周期

onCreate() 首次创建时调用
onStartCommand() 启动服务的时候调用,调用startService方法或者startForegroundService方法,回调此方法,如果这个服务还没有被创建过,onCreate()方法会先于这个方法调用
onBind() 在使用bindService()与服务绑定后回调此方法
onDestroy() 服务销毁时调用,比如调用了stopService(),stopSelf(),unbindService()方法

创建前台服务

  1. 权限申请
    面向Android 9(API级别28)或更高版本并使用前台服务的应用必须请求 FOREGROUND_SERVICE 权限
 <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 
  1. 启动前台服务
    要请求您的服务在前台运行,使用startForeground()。此方法有两个参数:一个用于在状态栏中唯一标识通知的正整数和 Notification对象本身。通知的优先级必须为PRIORITY_LOW或更高。
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    
    
            NotificationChannel channel = new NotificationChannel("1","1",NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(channel);
        }
        Notification notification = new NotificationCompat.Builder(MyService.this,"1")
                .setChannelId("1")
                .setContentTitle("this is Title")
                .setContentText("this is text")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))

                .build();
    startForeground(1,notification);
  1. 从前台删除服务
    要从前台删除服务,使用 stopForeground()。此方法采用一个布尔值,该布尔值指示是否也要删除状态栏通知。请注意该服务继续运行。

如果在前台运行该服务时停止该服务,则其通知将被删除。

启动服务,停止服务

启动服务:
Android 8.0 有一项复杂功能;系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即 Context.startForegroundService(),以在前台启动新服务。
在系统创建服务后,应用有5秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。如果应用在此时间限制内未调用 startForeground(),则系统将停止服务并声明此应用为 ANR。
所以我们在启动服务时要用startForegroundService()启动服务,并在service的onCreate方法中调用startForeground()。

扫描二维码关注公众号,回复: 12895568 查看本文章
Intent intent = new Intent(MainActivity.this,MyService.class);
                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    
    
                    startForegroundService(intent);
                }else
                    startService(intent);
public void onCreate() {
    
    
        super.onCreate();
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
    
    
            NotificationChannel channel = new NotificationChannel("1","1",NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(channel);
        }
        Notification notification = new NotificationCompat.Builder(MyService.this,"1")
                .setChannelId("1")
                .setContentTitle("this is Title")
                .setContentText("this is text")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))

                .build();
            startForeground(1,notification);

    }

停止服务:

 Intent intent1 = new Intent(MainActivity.this,MyService.class);
                stopService(intent1);

活动与服务间的通信

主要借助Binder()方法。
Sevice里的逻辑:

 private download d = new download();
 // 获取Binder子类对象
    class download extends Binder{
    
    
        public void start(){
    
    
            Log.d("MtService","start");
        }
        public int getProgress(){
    
    
            Log.d("MtService","success");
            return 0;
        }
    }
  public IBinder onBind(Intent intent) {
    
    
      
        return d;	//返回该子类对象的实例
    }   

Activity的逻辑:

private MyService.download download;
    private int progress;
    // 创建ServiceConnection实例
    private ServiceConnection connection = new ServiceConnection() {
    
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
    
    
        //与服务成功绑定时调用
        // 可通过向下转型得到服务中Binder的子类实例
            download = (MyService.download)service;
            download.start();
            progress = download.getProgress();
        }
		//与服务断开连接时调用
        @Override
        public void onServiceDisconnected(ComponentName name) {
    
    

        }
    };
  Intent intent2 = new Intent(MainActivity.this,MyService.class);
  bindService(intent2,connection,BIND_AUTO_CREATE);       //绑定服务  

bindService方法接收三个参数,第一个是刚创建的Intent对象,第二个是ServiceConnected实例,第三个是一个标志位,这里传入BIND_AUTO_CREATE表示在活动和服务进行绑定时自动创建服务。
原理:当调用bindService()方法后,就会回调服务中的onBind()方法,在ServiceConnected实例的onServiceConnected()方法中会接收到onBind()返回的IBinder对象,就可得到服务中Binder自类对象的实例,调用他里面的方法。

使用IntentService

可以简单的创建一个异步的,会自动停止的服务。

public class MyIntentService extends IntentService {
    
    

    public MyIntentService() {
    
    
        super("MyIntentService");		
        //注意这里是提供无参构造器,在内部调用父类的有参构造器
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
    
    
        //这个方法是在子线程运行的
    }

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

注册:

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

调用:

 Intent intent3 = new Intent(MainActivity.this,MyIntentService.class);
 startService(intent3);

猜你喜欢

转载自blog.csdn.net/haazzz/article/details/108741152