9.服务

服务是什么

服务是无需UI在后台运行的代码,所以会用到多线程。android服务并不是独立运行的,而是在app的进程中。

android多线程编程

android中,定义一个线程直接继承Thread即可。

class MyThread extends Thread{
    @Override
    public void run(){
        //业务逻辑
    }
}
new MyThread().start();

也可以直接实现Runnable接口来定义一个线程

class MyThread implements Runable{
    @Override
    public void run(){
        //业务逻辑
    }
}

MyThread myThread = new MyThread();
new Thread(myThread).start()

也可以通过匿名类来创建:

new Thread(new Runnable(){
    @Override
    public void run(){
        //业务逻辑
    } 
}).start();

异步消息处理机制

需要注意的是,android中,ui的更新处理不能放在子线程中。那么如果我们需要在子线程里执行一些业务然后更新UI怎么办?这时候就可以使用异步消息来处理。

异步消息有Message Handler MessageQueue Looper四部分组成。

1.Message

是线程直接传递一些简单的消息类。what字段、arg1、arg2传递整形数字。obj传递Object对象。

2、Handler

用于发送及处理消息。sendMessage()是发送,handleMessge()是接收。

3、MessageQueue

是消息队列。handler发来的消息都会在MessageQueue中存储。每个线程中会有一个队列。

4、Looper

Looper是线程中管理MessageQueue的类,通过Looper.loop()方法,会进入无线循环,每当发现MesageQueue存在一条消息,loop就会将她取出,并传递给handler的handleMessage()方法中。

通过四个对象可见,handler负责发送及接受消息。所以handler需要定义在线程外部,根据handleMessage里的消息进行做出响应的操作。

下面举个简单根据线程执行情况更新UI的例子:

public class ThreadActivity extends AppCompatActivity {
    //线程通信及消息处理
    Handler handler= new Handler(){
        //接收消息进行处理
        @Override
        public void handleMessage(@NonNull Message msg) {
            if(msg.what==1){
                EditText et=findViewById(R.id.thread_text);
                et.setText("我收到线程的来写:"+msg.what);
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);

        //点击激活线程更新
        Button btn = findViewById(R.id.thread_btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //线程更新文本
                MyThread thread = new MyThread();
                thread.start();
            }
        });
    }

    class MyThread extends Thread{
        @Override
        public void run() {
            //要发送的消息
            Message msg = new Message();
            msg.what=1;
            handler.sendMessage(msg);
        }
    }
}

布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ThreadActivity">

    <com.google.android.material.button.MaterialButton
        android:id="@+id/thread_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击线程运行"
        tools:ignore="InvalidId" />
    <EditText
        android:id="@+id/thread_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="等线程执行完更新本文字!!"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

服务

服务通常用来处理比较耗时的业务,这时会阻塞主进程的运行,导致UI假卡死,这时可以就用到线程了。

服务本身有分为前台后服务和后台服务。前台服务是指app没有处于激活状态,也会运行,会在android的消息栏的列表中看到。

后台服务是指当app不处于激活状态,有可能就不会运行了。如果没有外部干涉,服务都会一直运行的。所以服务需要启动和停止来管理服务。

另外服务需要在androidMainfest.xml声明,以及包括权限的声明。


public class MyService extends Service {
    public MyService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
    @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();
    }
}

在action中调用:

        Intent rx1 = new Intent(this,MyService.class);
        startService(rx1);//启动
        Intent rx2 = new Intent(this,MyService.class);
        stopService(rx2);//停止

需要注意的是,服务可以创建实例启动,也可以创建个实例停止。

active和服务的通信

上面的例子,服务在activity中实例化后就没有其他交互了。实际上,服务完成的进度如何,activity还是需要知道的。

这个时候,服务内部首先需要有个内部类实现IBinder()接口的类,这个类获取服务的相关进度,然后通过onBinder()返回这个类。

然后activity在通过ServiceConnetion对象的onServiceConnected()和onServiceDisconnected来实例化服务后,就可以直接调用内部类的相关方法。

首先改写一些服务,在里面增加一个实现Binder的监控内部情况的监督类,该类通过服务的onBind()返回:


public class MyService extends Service {
   //服务监督的内部类,通过onBind返回
   private MyIBinder myIBinder = new MyIBinder();
   public MyService() {
   }
   //返回监督类
   @Override
   public IBinder onBind(Intent intent) {
       return myIBinder;
   }
   @Override
   public void onCreate() {
       //初始化要执行的
       super.onCreate();
   }
   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
       //启动时要执行的
       Log.v(this.getClass().getName(),"服务启动执行业务");
       return super.onStartCommand(intent, flags, startId);
   }

   @Override
   public void onDestroy() {
       //销毁时要执行的
       super.onDestroy();
   }

   //服务监控类
   class MyIBinder extends Binder {
       //假设返回服务的执行状态
       public String getServiceStatus(){
           return "ok";
       }
   }
}

然后回到activity中,创建ServiceConnetion,在里面访问服务的内部类方法,获取服务的情况。

  //服务
   MyService.MyIBinder myIBinder;
   private ServiceConnection connection=new ServiceConnection() {
       @Override
       public void onServiceConnected(ComponentName name, IBinder service) {
           //连接中
           //初始化内部类,调用七方法访问服务
           myIBinder=(MyService.MyIBinder)service;
           String status=myIBinder.getServiceStatus();
           Button test =findViewById(R.id.finish_button);
           test.setText(status);
       }

       @Override
       public void onServiceDisconnected(ComponentName name) {
           //
       }
   };

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       
        //绑定服务
       Intent it = new Intent(MainActivity.this, MyService.class);
       bindService(it, connection, this.BIND_AUTO_CREATE);
       //解绑
       unbindService(connection);
   }

前台服务

上面说了后台服务在后台不是活动状态是,可能会被回收。而前台服务不会。所以后台服务可以修改一下改成前台服务。所谓前台服务就是通知。在通知中可以看到执行的服务。

将服务的onCreate方法改成如下即可:

 @Override
   public void onCreate() {
       //初始化要执行的
       super.onCreate();
       //前台服务
       NotificationManager manager= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
       NotificationChannel channl;
       String id="";
       if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
           channl=new NotificationChannel("我的","我的消息",NotificationManager.IMPORTANCE_DEFAULT);
           id=channl.getId();
           manager.createNotificationChannel(channl);
       }

       //前台通知代码
       Intent intent = new Intent(this,MainActivity.class);
       PendingIntent pi= PendingIntent.getActivity(this,0,intent,0);
       Notification notification = new NotificationCompat.Builder(this,id)
               .setContentTitle("我是服务啊")
               .setContentText("服务内容的描述")
               .setWhen(System.currentTimeMillis())
               .setSmallIcon(R.mipmap.ic_launcher)
               .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
               .setContentIntent(pi).build();
       startForeground(1,notification);
   }

服务使用线程

重写服务的onStartCommand方法即可:

@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);
   }

另外也可以继承IntendService服务。在onHandleIntent()方法中执行相关业务逻辑。

IntendService启动方式与与Service相同。

public class MyIntentService extends IntentService {

   public MyIntentService() {
       super("MyIntentService");
   }

   @Override
   protected void onHandleIntent(Intent intent) {
       //业务逻辑
       Log.v("MyIntentService","打印当前线程ID"+Thread.currentThread().getName());
   }

   @Override
   public void onDestroy() {
       super.onDestroy();
       Log.v("MyIntentService","服务线程执行完结速时,我会执行");
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT老卢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值