服务的学习(通过第一行代码)


首先要知道什么是服务,服务就是Android中用来实现后台运行的,一般要长期运行且不与用户交互的任务通过服务来执行。服务不依赖界面,当程序切换到后台或打开另一个程序都不影响服务运行。
但服务不会开启子线程,所有代码都是在主线程运行的,我们要自己在服务中开启子线程。

Android多线程编程

首先,Android中不允许在子线程中进行UI操作,所以我们可以使用异步消息处理机制来解决这类问题。
解析异步处理机制
Android中异步处理由4个部分组成,分别时:Message、Handle、MessageQueue和Looper。
1.Message:
Message是在线程中传递的信息,它可以在内部携带少量信息,用于在不同线程间交换数据。
2.Handler:
Handler是处理者,用来处理Message。用法例如:在主线程中创建Handler对象,重定义handleMessage()方法,然后在子线程中创建Message对象,调用Handler对象的sendMessage()方法传递Message对象,保存在MessageQueue中,通过Looper传到handleMessage()中,因为Handler对象是在主线程中创建的,在主线程中执行handleMessage()方法,根据传过来的Message对象判断执行如更新UI,这样就实现异步,更新UI。
3.MessageQueue:
MessageQueue是消息队列,主要用于存放所有Handler发送的消息。这些消息会存放在消息队列中,等待处理,每个线程有一个MessageQueue对象。
4.Looper:
Looper是每个线程中MessageQueue的管家,调用Looper的loop()方法后,进入无限循环,每当MessageQueue中有一条消息,就会取出,传递到Handler对象的handMessage()方法中。每个线程也只有一个Looper对象。

总而言之,来过一遍异步消息处理机制的运行过程:
首先在主线程中创建一个Handler对象,重写handleMessage()方法。当子线程中需要进行UI操作时,就创建一个Message对象,并通过Handler对象的sendMessage()方法发送出去。之后这条消息会被添加到MessageQueue的队列中等待被处理,Looper则会一直尝试从MessageQueue中取出待处理消息,最后分发会Handler对象的handleMessage()方法中。由于Handler对象是在主线程中创建的,所以此时handleMessage()方法是在主线程中运行,这时就可以进行UI操作。流程图:
在这里插入图片描述
例子:

package com.example.hankzz.androidthread;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
public final static int UPDATE_TEXT = 1;
private Button button;
private TextView textView;
private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if(msg.what == UPDATE_TEXT){
            textView.setText("hello world!");
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    button = (Button) findViewById(R.id.change_button);
    textView = (TextView) findViewById(R.id.textview);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new Thread(new Runnable(){
                public void run(){
                    Message message = new Message();
                    message.what = UPDATE_TEXT;
                    handler.sendMessage(message);
                }
            }).start();
        }
    });
}
}

使用AsyncTask
为了方便在子线程中进行UI操作,Android提供的AsyncTask可以很简单的从子线程切换到主线程,同样AsyncTask的实现原理也是基于异步处理机制,只是很好的封装了。
AsyncTask时一个抽象类,创建一个类继承它并为AsyncTask类指定3个泛型参数,这3个参数是:
Params,执行AsyncTask时传入的参数,在doInBackground(Params …)后台执行任务中使用。
Progress,如需显示任务进度,这就是指定的进度类型。
Result,结果的返回类型。
继承后需要重写AsyncTask的几个方法,常用的是以下四个方法:
1.onPreExecute()
在后台任务开始前,执行一些初始化界面的操作。
2.doInBackground(Params …)
这个方法中的代码会在子线程中运行,就是开了一个子线程,代码在其中运行,在这里处理耗时任务(如网络操作),任务完成后,通过return语句返回执行结果,返回结果的类型就是前面定义的。当然如果在子线程中要更新UI操作时,调用publishProgress(Progress …)方法来完成,之后由onProgressUpdate(Progress …)来执行UI操作。
3.onProgressUpdate(Progress …)
在子线程的后台任务调用publishProgress(Progress …)方法后调用此方法,可以利用传过来的参数值更新UI。
4.onPostExecute(Result …)
在子线程的后台任务返回一个执行结果后调用,可根据传过来的参数执行相应操作。
例子:

package com.example.hankzz.androidthread;

import android.os.AsyncTask;
import android.widget.ProgressBar;

public class MyAsyncTask extends AsyncTask<Void,Integer,Boolean> {
private static int time = 0;
@Override
protected void onPreExecute() {
    super.onPreExecute();

}

@Override
protected Boolean doInBackground(Void... voids) {
    while(true){
        int downloadPercent = time++;
        publishProgress(downloadPercent);
        if(downloadPercent>=100){
            break;
        }
    }
    return false;
}

@Override
protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
}

@Override
protected void onPostExecute(Boolean aBoolean) {
    super.onPostExecute(aBoolean);
}
}

要启动的话new MyAsyncTask().execute()来启动这个任务。

服务基本用法

创建一个服务
直接项目new一个Service,同样需要在AndroidManifest.xml中注册,但系统会自动帮我们注册,向其他的四大组件一样。
重写四个方法:
onCreate():服务被创建后调用。
onStartCommand():启动服务后调用。
onDestroy():服务销毁后调用。
onBind():用于与活动进行通信。
在服务中调用stopSelf()方法会停止服务。

public class MyService extends Service {
class DownloadBinder extends Binder {
    public void downloadpogress(){
        Log.d("MyService","it's 6:45");
    }
    public void downloadwhat(){
        Log.d("MyService","girls like you");
    }
}
private DownloadBinder binder = new DownloadBinder();

public MyService() {

}

@Override
public IBinder onBind(Intent intent) {
    return binder;
}

@Override
public void onCreate() {
    super.onCreate();
    Log.d("MyService","MyService is born");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("MyService","MyService is doing its work");
    return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d("MyService","MyService is died");
}
}

启动停止服务
启动服务:startService(Intent intent),启动一个服务,如果服务还没创建会先创建,调用onCreate(),后调用startCommand(),后来再启动服务时只调用startCommand()。
停止服务:stopService(Intent intent),停止服务,调用onDestroy()方法。
活动和服务进行通信
先创建一个类继承Binder类,在里面声明想要的方法、成员变量。在onBind()方法正return一个IBinder对象。在活动中通过匿名内部类创建ServiceConnection对象,重写onServiceConnected()、onServiceDIsconnected()方法,这个对象用于在活动和服务绑定后,服务调用onBind()方法后,调用onServiceConnected()方法,可以获取Binder对象,进行相应处理通信。最后调用bindService(Intent,ServviceConnection,int)绑定服务和活动,如果没有创建服务会先创建服务,调用服务的onCreate(),后调用服务的onBind()方法,之后调用onServiceConnected()。unbindService(ServiceConnection)方法解绑,调用服务的onUnBind()方法接着调用onDestroy()方法。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MyService.DownloadBinder binder;
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d("MainActivity","Bind");
        binder = (MyService.DownloadBinder) service;
        binder.downloadpogress();
        binder.downloadwhat();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d("MainActivity","Unbind");
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button start = (Button) findViewById(R.id.start_button);
    start.setOnClickListener(this);
    Button stop = (Button) findViewById(R.id.stop_button);
    stop.setOnClickListener(this);
    Button bind = (Button) findViewById(R.id.bind_button);
    bind.setOnClickListener(this);
    Button unbind = (Button) findViewById(R.id.unbind_button);
    unbind.setOnClickListener(this);
    Button startintentservice = (Button) findViewById(R.id.startintentsevice_button);
    startintentservice.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    switch(v.getId()){
        case R.id.start_button:
            Intent startintent = new Intent(this,MyService.class);
            startService(startintent);
            break;
        case R.id.stop_button:
            Intent stopintent = new Intent(this,MyService.class);
            stopService(stopintent);
            break;
        case R.id.bind_button:
            Intent bindintent = new Intent(this,MyService.class);
            bindService(bindintent,connection,BIND_AUTO_CREATE);
            break;
        case R.id.unbind_button:
            unbindService(connection);
            break;
        case R.id.startintentsevice_button:
            Log.d("MainActivity","main thread id is "+Thread.currentThread().getId());
            Intent intent = new Intent(this,MyIntentService.class);
            startService(intent);
        default:
            break;
    }
}
}

服务的生命周期
onCreate()、onStartCommand()、onDestroy()、onBind()都是在生命周期内可回调的函数。
在项目中调用Context的startService()方法,相应服务就会启动起来,并回调onStartCommand()。如果服务没有被创建过,onCreate()方法会优先于onStartCommand()方法执行。服务启动后会一直执行,直到stopService()或stopSelf()方法被调用后,服务停止。
同样可以通过Context的bindService来获取服务的一个连接,回调服务中的onBind()方法。同样服务如果没有创建,会先调用onCreate()方法。只要与服务的连接没有断开,服务就会一直运行。
当调用startService()方法,有去调用stopService()方法,这时服务中的onDestroy()方法就会调用,表失服务已销毁。类似,当调用bindService()后又去调用unbindService()方法,onUnbBind()和onDestroy()也会执行。但是如果即调用了startService()也调用了bindService()时,必须同时调用stopService()和unbindService()方法,onDestroy()方法才会调用。

服务的更多技巧

使用前台服务
后台服务系统优先级较低,当内存不足时可能会被回收。如果要服务保持一直运行,可采用前台服务。前台服务会有一个图标在状态栏中显示,类似通知(因为就是用通知做的)。
因为在Android O(8.0,api26)后,通知必须要添加通知渠道,所以前台服务也需要改变,原来只需要创建一个通知对象,调用startForeground()设置为前台服务即可,现在首先创建NotificationManager对象,创建NotificationChannel对象,再给通知添加渠道,调用startForeground(),需要版本判断。
且在8.0后在活动中开启前台服务需要进行版本判断如果api版本高于26,调用startForegroundService(Intent)方法开启前台服务,低于则直接startService(Intent).
同样在9.0后,使用前台服务需要添加权限:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

例子:
MyService:

public class MyService extends Service {
......
	//在服务的onCreate()中:
@Override
public void onCreate() {
    super.onCreate();
    Log.d("MyService","MyService is born");
    Aheadservice();
}
......
private void Aheadservice(){
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        String channelid = "ahead_channel";
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel channel = new NotificationChannel(channelid,"ahead",
                NotificationManager.IMPORTANCE_DEFAULT);
        manager.createNotificationChannel(channel);
        Intent intent = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);
        Notification notification = new NotificationCompat.Builder(this,channelid)
                .setContentTitle("this is title")
                .setContentText("this is text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pendingIntent).build();
        startForeground(1,notification);
    }
}
}

MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MyService.DownloadBinder binder;
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d("MainActivity","Bind");
        binder = (MyService.DownloadBinder) service;
        binder.downloadpogress();
        binder.downloadwhat();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.d("MainActivity","Unbind");
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button start = (Button) findViewById(R.id.start_button);
    start.setOnClickListener(this);
    Button stop = (Button) findViewById(R.id.stop_button);
    stop.setOnClickListener(this);
    Button bind = (Button) findViewById(R.id.bind_button);
    bind.setOnClickListener(this);
    Button unbind = (Button) findViewById(R.id.unbind_button);
    unbind.setOnClickListener(this);
    Button startintentservice = (Button) findViewById(R.id.startintentsevice_button);
    startintentservice.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    switch(v.getId()){
        case R.id.start_button:
            Intent startintent = new Intent(this,MyService.class);
            if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
                startForegroundService(startintent);
            }else{
                startService(startintent);
            }
            break;
        case R.id.stop_button:
            Intent stopintent = new Intent(this,MyService.class);
            stopService(stopintent);
            break;
        case R.id.bind_button:
            Intent bindintent = new Intent(this,MyService.class);
            bindService(bindintent,connection,BIND_AUTO_CREATE);
            break;
        case R.id.unbind_button:
            unbindService(connection);
            break;
        case R.id.startintentsevice_button:
            Log.d("MainActivity","main thread id is "+Thread.currentThread().getId());
            Intent intent = new Intent(this,MyIntentService.class);
            startService(intent);
        default:
            break;
    }
}
}

AndroidManifest.xml:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

使用IntentService
一般服务是自己先开一个子线程,在里面进行耗时的操作,服务执行完毕后调用stopSelf()停止服务。IntentService类可以直接实现。
可以直接通过快捷方式生成IntentService(直接在包名new一个),但会生成一些用不到的代码,故直接创建一个类继承IntentService,再在构造函数中显示调用父类构造函数。重写onHandleIntent(Intent)方法,这就是执行耗时操作的函数,开启子线程,任务结束后会停止服务。

public class MyIntentService extends IntentService {
public MyIntentService(){
    super("MyIntentService");
}

@Override
protected void onHandleIntent(Intent intent) {
    Log.d("MyIntentService","thread id is "+Thread.currentThread().getId());
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d("MyIntentService","MyIntentSevice is dead");
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值