美文网首页
Service与Thread的使用和区别

Service与Thread的使用和区别

作者: 小小的coder | 来源:发表于2020-05-18 20:08 被阅读0次

服务既不是进程也不是线程,它们之间的关系如下:
首先要说明的是,进程是系统最小资源分配单位,而线程是则是最小的执行单位,线程需要的资源通过它所在的进程获取。

服务:服务是Android四大组件之一,非常适合执行那些不需要与用户交互且要求长期执行的任务。需要注意:服务依赖于创建服务时所在的应用程序进程。

线程:线程是程序执行的最小单元,可以用Thread来执行一些异步的操作。

常用使用及其区别:

1子线程的使用:我们通常会使用子线程来进耗时任务。但是有些时候我们需要根据任务的执行结果来更新显示相应的UI控件,要知道Android的UI与许多其他GUI库一样是线程不安全的,必须在主线程中操作于是我们需要采用异步消息机制,为了方便起见,我们还是使用基于异步消息机制的的AsyncTask抽象类:使用的AsyncTask诀窍在于在doInBackground(//运行在子线程中)方法执行耗时操作,在onProgressUpdate(//运行在主线程中)方法中进行UI操作,在onPostExcute(//运行在主线程中)方法中执行任务的收尾工作。

2服务的使用:服务我们最初理解是在后台处理一些耗时操作,但是我们不要被其所谓的后台概念迷惑,实际上服务不会自动开启线程,所有的代码都是默认运行在主线程之中的,如果我们直接在服务中进行耗时操作必定会阻塞主线程,出现ANR的情况。因此我们需要在服务中手动创建子线程,在子线程中进行耗时操作。因此一个比较标准的服务如下:

public class MyService extends Service {
...
@Override
public int onStartCommand(Intent intent,int flags,int startId)
{
new Thread(new Runnable()
{
public void run()
{
//处理具体逻辑
}
}).start();
return super.onStartCommand(intent,flags,startId);
}
}
但是这种服务一旦启动,必须​​调用stopSelf()方法或stopService()方法才能停止该服务。为了简单地创建一个异步的,会自动停止的服务,Android专门提供了一个IntentService类,我们只需要新建一个MyIntentService继承于IntentService类,在onHandlerIntent()方法中执行耗时操作即可,因为这个方法是在子线程中运行的,且这个服务在运行结束后会自动停止。

3 额,既然在服务里也要创建一个子线程,那为什么不直接在活性里创建呢?这是因为活动很难对线程进行控制,当活动被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个活动中创建的子线程,另一个活动无法对其进行操作。但是服务就不同了(因为任何活动都可以控制同一个服务,而系统也只会创建一个对应服务的实例),所有的活动都可以与服务进行关联,然后可以很方便地操作其中的方法,即使活动被销毁了,之后只要重新与服务建立关联,就又能够获取到原有的因此,使用服务来处理后台任务,活动就可以放心地完成,完全不需要担心无法对后台任务进行控制的情况。因此可以把服务想象成一种消息服务,可以在任何有上下文的地方调用Context.startService,C ontext.stopService,Context.bindService,Context.unbindService来控制它,也可以在Service里注册BroadcastReceiver,通过发送广播来达到控制的目的,这些都是线程做不到的。

以下解析第一行代码中的一个下载实例:

1首先定义回调接口监听类,对下载过程的状态进行监听并对其作出具体反应,我们会在DownloadService类中实现该类

public interface DownloadListener {
void onProgress(int progress);
void onSuccess();
void onFailed();
void onPaused();
void onCanceled();

}
2开始编写下载功能,新建DownloadTask类继承于AsyncTask

public class DownloadTask extends AsyncTask<String,Integer,Integer> {
public static final int TYPE_SUCCESS=0;
public static final int TYPE_FAILED=1;
public static final int TYPE_PAUSED=2;
public static final int TYPE_CANCELED=3;
private DownloadListener listener;
private boolean isCanceled=false;
private boolean isPaused=false;
private int lastProgress;
public DownloadTask(DownloadListener listener){
this.listener=listener;
}
@Override
protected Integer doInBackground(String...params){
InputStream is=null;
RandomAccessFile savedFile=null;
File file=null;
try{
long downloadedLength=0;//
String downloaUrl=params[0];
String fileName=downloaUrl.substring(downloaUrl.lastIndexOf("/"));
String directory= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
file=new File(directory+fileName);
if(file.exists()){
downloadedLength=file.length();
}
long contentLength=getContentLength(downloaUrl);
if(contentLength==0){
return TYPE_FAILED;
}else if(contentLength==downloadedLength){return TYPE_SUCCESS;}
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().addHeader("RANGE","bytes="+downloadedLength+"-")
.url(downloaUrl)
.build();
Response response=client.newCall(request).execute();
if(response!=null){
is=response.body().byteStream();
savedFile=new RandomAccessFile(file,"rw");
savedFile.seek(downloadedLength);
byte[]b=new byte[1024];
int total=0;
int len;
while((len=is.read())!=-1){
if(isCanceled){
return TYPE_CANCELED;
} else if (isPaused) {
return TYPE_PAUSED;
}
else {
total+=len;
savedFile.write(b,0,len);
int progress=(int)((total+downloadedLength)*100/contentLength);
publishProgress(progress);
}
}
response.body().close();
return TYPE_SUCCESS;
}
}catch (Exception e){
e.printStackTrace();
}finally {
try{if (is!=null)
is.close();
if(savedFile!=null)savedFile.close();
if(isCanceled&&file!=null)file.delete();
}catch (Exception e){
e.printStackTrace();
}

    }

return TYPE_FAILED;
}
@Override
protected void onProgressUpdate(Integer...values){
int progress=values[0];
if(progress>lastProgress){
listener.onProgress(progress);
lastProgress=progress;
}
}
@Override
protected void onPostExecute(Integer status){
switch (status){
case TYPE_SUCCESS:{
listener.onSuccess();
}
break;
case TYPE_FAILED:
listener.onFailed();
break;
case TYPE_PAUSED:
listener.onPaused();
break;
case TYPE_CANCELED:
listener.onCanceled();
break;
default:
break;
}
}
public void pauseDownload(){
isPaused=true;
}
public void cancelDownload(){
isCanceled=true;
}
private long getContentLength(String downloadUrl)throws IOException{
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url(downloadUrl).build();
Response response=client.newCall(request).execute();
if(response!=null&&response.isSuccessful()){
long contentLength=response.body().contentLength();
response.body().close();
return contentLength;
}
return 0;
}
}
3 新建下载任务DownloadService,在服务中启动DownloadTask

public class DownloadService extends Service {
private DownloadTask downloadTask;
private String downloadUrl;
private DownloadListener listener=new DownloadListener() {
@Override
public void onProgress(int progress) {
getNotificationManager().notify(1,getNotification("Downloading...",progress));

    }

    @Override
    public void onSuccess() {
        downloadTask=null;
        stopForeground(true);
        getNotificationManager().notify(1,getNotification("Download Success",-1));
        Toast.makeText(DownloadService.this,"Download Success",Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onFailed() {
        downloadTask=null;
        stopForeground(true);
        getNotificationManager().notify(1,getNotification("Download Failed",-1));
        Toast.makeText(DownloadService.this,"Download Failed",Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onPaused() {
        downloadTask=null;
        Toast.makeText(DownloadService.this,"Paused",Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onCanceled() {
        downloadTask=null;
        stopForeground(true);
        Toast.makeText(DownloadService.this,"Canceled",Toast.LENGTH_SHORT).show();
    }
};
public DownloadService() {
}

private DownloadBinder mBinder=new DownloadBinder();
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mBinder;
}
private NotificationManager getNotificationManager(){
return (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
}
private Notification getNotification(String title,int progress){
Intent intent=new Intent(this,MainActivity.class);
PendingIntent pi=PendingIntent.getActivity(this,0,intent,0);
NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentIntent(pi);
builder.setContentTitle(title);
if(progress>0){
builder.setContentText(progress+"%");
builder.setProgress(100,progress,false);

    }
    return builder.build();
}
class DownloadBinder extends Binder{
    public void startDownload(String url){
        if(downloadTask==null){
            downloadUrl=url;
            Log.d("MainActivity","get the downloadurl success");
            downloadTask=new DownloadTask(listener);
            downloadTask.execute(downloadUrl);
            Log.d("MainActivity","downloadtask execute");
            startForeground(1,getNotification("Downloading...",0));
            Toast.makeText(DownloadService.this,"Downloading...",Toast.LENGTH_SHORT).show();
        }

    }

public void pauseDownload(){
    if(downloadTask!=null){
        downloadTask.pauseDownload();
    }
}
public void cancleDownload() {
    //仍然正在下载
    if (downloadTask != null) {
        downloadTask.cancelDownload();
    } else {
        if (downloadUrl != null) {
            String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));

            String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
            File file = new File(directory + fileName);
            if (file.exists()) {
                file.delete();
            }
            getNotificationManager().cancel(1);
            stopForeground(true);
            Toast.makeText(DownloadService.this, "Canceled", Toast.LENGTH_SHORT).show();
        }
    }

}
}

}

从上面这个例子可以看出来,为了让下载服务可以和活动进行通信(例如在活动中去指挥服务去干什么,这恰恰是子进程难以实现的),我们在下载服务中的DownloadBinder类中(继承于粘合剂)获取DownloadTask实例,并通过该实例编写一系列对DownTask进行操作的方法,然后将该服务与活动绑定,从而实现了在活动中对耗时子进程任务的控制。

4 以上就是后端部分的编写,接下来是前端部分的编写,以及在活动中进行绑定服务即可。

个人理解总结:在服务的继承于活页夹的类中获取子进程任务的实例,在内部类中通过该实例编写对子进程的控制方法,再将该服务与活动绑定,就能实现在活动中控制该子进程任务的目的。
————————————————
原文链接:https://blog.csdn.net/Lshow1999/java/article/details/77140427

相关文章

  • Service与Thread的使用和区别

    服务既不是进程也不是线程,它们之间的关系如下:首先要说明的是,进程是系统最小资源分配单位,而线程是则是最小的执行单...

  • 2018-06-07

    1、Android中的四大组件及其作用 2、Service与Thread的区别 Service与Thread两个完...

  • 2018-06-11

    1、Android中的四大组件及其作用 2、Service与Thread的区别 Service与Thread两个完...

  • Service

    1. Service应用场景及 Service和Thread的区别 (1) what is Service(应用场...

  • service和thread区别

    定义 ThreadThread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异...

  • 3 Service相关

    service的应用场景,以及和Thread的区别开启service的两种方式以及区别 1、service是什么?...

  • Service和Thread的区别

    这又一个面试题,笔者被问到后有点懵,毕竟之前压根就没思考过这个问题,在笔者看来,这两者好像除了都可以用来执行任务外...

  • Service和Thread的区别

    1概念 1 Thread:是程序的最小单元,是分配cpu的基本单位,可以执行异步操作 2 Service:andr...

  • Android 拾遗(三) Service

    Service 的应用场景以及和 Thread 的区别service 是什么 Service(服务)是一个可以在...

  • Service

    Service和Thread的区别: Thread是程序执行的最小单元,他是分配CPU的基本单位。Thread生命...

网友评论

      本文标题:Service与Thread的使用和区别

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