安卓开发 探究服务

前言:

  关于安卓开发的笔记,其实基本都是我复现一行代码中的代码,并加上我自己的理解并解说的,也就是自己记录着玩玩的,有问题欢迎评论区指正。

0x01 简介

服务service是安卓里面的四大组件之一,它的作用就是可以在应用程序关闭时,还可以继续运行,比如我们平常电脑或手机听歌的时候,我们会先打开

音乐软件,播放音乐后,切换别的应用,干活去了对吧,但是我们在切换应用的时候,按道理应用这时候是已经挂在后台了,但是音乐还是在正常播放的

也就是服务是支持应用程序在后台正常运行的手段。

0x02 安卓多线程编程

至于为什么先写多线程,一个是书上是这顺序,还有一个原因就是在于服务的干事的地方,基本都在子线程里面干的,而服务并不是自己创建子进程的,

这需要我们在服务内部代码中去实现的,管他呢,都得学2333

安卓多线程和java的多线程差不多的,也都是三种方式

1.继承Thread类,重写run方法,然后创建对应的线程对象,调用start()方法,启动线程

 class OneThread extends Thread{
        public void run()
        {
            Log.d("YenKoc", "重写");
        }
    }
OneThread one=new OneThread();
one.start();

2.实现Runnable接口,重写run方法,创建对应的实例,然后再新建一个Thread对象,将上面的实例传入Thread的构造方法中去,再调用start()

 class OneThread implements Runnable{
        public void run()
        {
    }
}
OneThread one </span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> OneThread();
</span><span style="color: #0000ff;">new</span> Thread(one).start();</pre>

3.匿名类创建子线程的方式

new Thread(new Runnable(){
        public void run()
        {
    }
}).start()</span></pre>

这种是是最简单省事的,也是用的多的

然后在子线程中是无法更新UI的,这里书里也提供了一个简单的案例,我就不提出来了,就是新建一个布局,然后设置一个按钮,一点就新建子线程去改变文本框的内容

由于子线程中无法更新ui,也就是会出现程序崩溃的情况,这里就提出另一种完美解决安卓子进程更新ui的操作,安卓提供了一套消息处理机制,其实之前在app启动的源码中

也看到了消息机制looper等,通过发信号的模式去启动的,这是题外话,这块我也好久没看了,又忘了233

这里通过实例来看

package com.example.servicetest;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.IpSecManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.nio.BufferUnderflowException;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private TextView text;
public static final int UPDATE_TEXT=1;
private Handler handler=new Handler(){
public void handleMessage(Message msg){
switch (msg.what)
{
case UPDATE_TEXT:
text.setText(
"Nice to meet you");
break;
default:
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button changeText
=(Button)findViewById(R.id.change_text);
changeText.setOnClickListener(
this);

}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onClick(View v)
{
    </span><span style="color: #0000ff;">switch</span><span style="color: #000000;"> (v.getId())
    {
        </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> R.id.change_text:
            </span><span style="color: #0000ff;">new</span> Thread(<span style="color: #0000ff;">new</span><span style="color: #000000;"> Runnable() {
                @Override
                </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() {
                    Message message</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> Message();
                    message.what</span>=<span style="color: #800080;">1</span><span style="color: #000000;">;
                    handler.sendMessage(message);
                }
            }).start();
        </span><span style="color: #0000ff;">default</span><span style="color: #000000;">:
            
                    
    }


}

}

新建一个handler对象,并重写了handlerMessage方法,里面主要是根据消息中的what字段来选择不同的处理方式,

然后在点击按钮后,实际上是通过创建子进程,然后在子进程中,发送了一个消息给主线程handler,然后由主线

程来更新ui,这种异步消息处理机制,太酷了233,想当于领导在子线程里面指挥,小弟在主线程里面干活。

至于原理也挺简单当,看图

 

 message:字面意思,作为通讯用的

handler: 用来处理消息的,要重写handleMessage方法

MessageQueue:消息队列,因为消息有先后顺序的,相当于消息容器,把消息都装到里面

looper:消息队列的管家,一旦运行会轮询消息队列,看看里面是否有消息,如果有就发送,没有的话就阻塞

之前使用的runOnUiThread其实就是上面那套的封装,所以很香,所以那里面是可以对ui操作的

0x02 服务

终于到服务了。。

package com.example.servicetest;
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;

public class MyService extends Service {
public MyService() {
}

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> IBinder onBind(Intent intent) {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> TODO: Return the communication channel to the service.</span>
    <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> UnsupportedOperationException(<span style="color: #800000;">"</span><span style="color: #800000;">Not yet implemented</span><span style="color: #800000;">"</span><span style="color: #000000;">);
}
</span><span style="color: #008000;">//</span><span style="color: #008000;">服务创建的时候调用</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onCreate()
{
    super.onCreate();
}
</span><span style="color: #008000;">//</span><span style="color: #008000;">服务每次启动时被调用</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> onStartCommand(Intent intent,<span style="color: #0000ff;">int</span> flags,<span style="color: #0000ff;">int</span><span style="color: #000000;"> startId)
{
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> super.onStartCommand(intent,flags,startId);
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onDestroy()
{
    super.onDestroy();
}

}

新建一个service类,然后重写onCreate()方法,onStartCommand()方法(主要逻辑是写到这里),onDestroy()方法,

2.服务的启动和停止,组件之间的启动都是通过intent对象来启动的

package com.example.servicetest;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.IpSecManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.nio.BufferUnderflowException;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

@Override
</span><span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  Button startService</span>=<span style="color: #000000;">(Button)findViewById(R.id.start_service);
    Button stopService</span>=<span style="color: #000000;">(Button)findViewById(R.id.stop_service);
    startService.setOnClickListener(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);
    stopService.setOnClickListener(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onClick(View v)
{
    </span><span style="color: #0000ff;">switch</span><span style="color: #000000;"> (v.getId()) {
        </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> R.id.start_service:
            Intent startIntent </span>= <span style="color: #0000ff;">new</span> Intent(<span style="color: #0000ff;">this</span>, MyService.<span style="color: #0000ff;">class</span><span style="color: #000000;">);
            startService(startIntent);
            </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
        </span><span style="color: #0000ff;">case</span><span style="color: #000000;"> R.id.stop_service:
            Intent stopIntent</span>=<span style="color: #0000ff;">new</span> Intent(<span style="color: #0000ff;">this</span>,MyService.<span style="color: #0000ff;">class</span><span style="color: #000000;">);
            stopService(stopIntent);
            </span><span style="color: #0000ff;">break</span><span style="color: #000000;">;
    }
}

}

然后在MyService类改下代码

package com.example.servicetest;
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;

public class MyService extends Service {
public MyService() {
}

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> IBinder onBind(Intent intent) {
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> TODO: Return the communication channel to the service.</span>
    <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> UnsupportedOperationException(<span style="color: #800000;">"</span><span style="color: #800000;">Not yet implemented</span><span style="color: #800000;">"</span><span style="color: #000000;">);
}
</span><span style="color: #008000;">//</span><span style="color: #008000;">服务创建的时候调用</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onCreate()
{
    super.onCreate();
    Log.d(</span><span style="color: #800000;">"</span><span style="color: #800000;">MyService</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">onCreate executed</span><span style="color: #800000;">"</span><span style="color: #000000;">);
}
</span><span style="color: #008000;">//</span><span style="color: #008000;">服务每次启动时被调用</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> onStartCommand(Intent intent,<span style="color: #0000ff;">int</span> flags,<span style="color: #0000ff;">int</span><span style="color: #000000;"> startId)
{
    Log.d(</span><span style="color: #800000;">"</span><span style="color: #800000;">MyService</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">onStartCommand: executed</span><span style="color: #800000;">"</span><span style="color: #000000;">);
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> super.onStartCommand(intent,flags,startId);
}
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onDestroy()
{
    super.onDestroy();
    Log.d(</span><span style="color: #800000;">"</span><span style="color: #800000;">MyService</span><span style="color: #800000;">"</span>, <span style="color: #800000;">"</span><span style="color: #800000;">onDestroy: executed</span><span style="color: #800000;">"</span><span style="color: #000000;">);
}

}

3.活动与服务之间的通信,因为之前这种方式都是活动启动完服务之后,就不管不顾了,控制不了服务器的逻辑,所以安卓想让活动和服务紧密一点,所以提出了Binder机制,还记得在创建service时自动继续了一个onBind()方法吗

实际就是在这里被派上用场的,之后再说,要使用Binder,需要在service中继承Binder类

 

 

``` package com.example.activityjiechi;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {
public MyService() {
}

@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    return mBinder;
}
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 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();
}

在Service类中,新建了一个内部类继承Binder,写了两个方法,这个是之后活动中需要去调用的。

  • 之后一步是活动和服务进行绑定,绑定后,才可以进行操作服务
package com.example.activityjiechi;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public Button startService;
    public Button stopService;
    public Button bindService;
    public Button UbindService;
    private MyService.DownloadBinder downloadBinder;
    private ServiceConnection connection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder=(MyService.DownloadBinder)service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService=findViewById(R.id.start_service);
        startService=findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        bindService.setOnClickListener(this);
        UbindService.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId())
        {
            case R.id.start_service:
                Intent intent=new Intent(this,MyService.class);
                startService(intent);
                break;
            case R.id.stop_service:
                Intent intent2=new Intent(this,MyService.class);
                stopService(intent2);
                break;
            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;
        }
    }
}

新建了一个ServiceConnection对象,并重写了onServiceConnected与onServiceDisconnected方法,并强转了 IBinder service类型
变成我们在service类中自定义的内部类,实际上是因为当活动和服务进行绑定时,会回调service的onBinder方法,会将我们之前service
中的自定义内部类的对象返回,传入这里,下面的两个按钮的触发事件才是绑定和解绑的代码,当绑定时,会调用onServiceConnected方法
,同样解绑后,也会调用onServiceDisconnected方法
4. 生命周期(挂个原话,偷懒ing)

posted @ 2020-10-25 17:18  YenKoc  阅读(226)  评论(0编辑  收藏  举报