Android四大组件——服务以及实例

Posted Mask_D

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android四大组件——服务以及实例相关的知识,希望对你有一定的参考价值。

一 服务的基本用法

1.定义服务

在包中新建一个service,命名为MyService。发现MyService类继承自Service。

要在服务中处理一些逻辑,所以重写Service中的一些方法如下:

 1 public class MyService extends Service {
 2     
 3     /*在服务创建时被调用*/
 4     @Override
 5     public void onCreate() {
 6         super.onCreate();
 7     }
 8 
 9     /*在服务每次启动时候调用*/
10     @Override
11     public int onStartCommand(Intent intent, int flags, int startId) {
12         return super.onStartCommand(intent, flags, startId);
13     }
14 
15     /*在服务被销毁时候调用*/
16     @Override
17     public void onDestroy() {
18         super.onDestroy();
19     }
20 
21     public MyService() {
22     }
23 
24     @Override
25     public IBinder onBind(Intent intent) {
26         // TODO: Return the communication channel to the service.
27         throw new UnsupportedOperationException("Not yet implemented");
28     }
29 }

注:服务是四大组件之一,自然也需要被注册,当然我们新建时候已经被自动在androidManifest.xml中注册了。

 

2.启动和停止服务

布局文件如下:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="vertical">
 5 
 6     <Button
 7         android:id="@+id/start_service"
 8         android:layout_width="match_parent"
 9         android:layout_height="wrap_content"
10         android:text="start service" />
11 
12     <Button
13         android:id="@+id/stop_service"
14         android:layout_width="match_parent"
15         android:layout_height="wrap_content"
16         android:text="stop service" />
17 </LinearLayout>

MyService类同上一部分一样,然后MainActivity类如下:

 1 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 2 
 3     private Button startService;
 4     private Button stopService;
 5 
 6     @Override
 7     protected void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.activity_main);
10 
11         startService = (Button)findViewById(R.id.start_service);
12         stopService = (Button)findViewById(R.id.stop_service);
13         startService.setOnClickListener(this);
14         stopService.setOnClickListener(this);
15     }
16 
17     @Override
18     public void onClick(View view) {
19         switch (view.getId()){
20             case R.id.start_service:
21                 Intent startIntent = new Intent(this,MyService.class);
22                 startService(startIntent); //启动服务
23                 break;
24             case R.id.stop_service:
25                 Intent stopIntent = new Intent(this,MyService.class);
26                 stopService(stopIntent);  //停止服务
27                 break;
28             default:
29                 break;
30         }
31     }
32 }

可以看到,在点击事件中,我们构建了显性的Intent,目的将其跳转到服务。然后调用startService()和stopService()方法来开始和停止活动。这里如果没有点击停止运行的按键的话,服务会一直执行下去,而如果再MyService中调用stopSelf()方法的话就会停止服务自身。

其中,onCreate()和onStartCommand()方法在 点击startService时都会使用,不同的是,onCreate只在第一次创建的时候使用,再点击的的时候onCreate就不会再执行了。

 

3.活动和服务进行通信

如果我们想实现一个活动来控制一个下载服务,可以在活动中决定何时开始下载和查看下载进度。

这里要用到之前新建服务时候自带的onBind()方法。更新MyService如下:

 1 public class MyService extends Service {
 2 
 3     private DownloadBinder mBinder = new DownloadBinder();
 4 
 5     class DownloadBinder extends Binder {
 6         public void startDownload(){
 7             Log.d("MyService","startDownload executed");
 8         }
 9         public int getProgress(){
10             Log.d("MyService","getProgress executed");
11             return 0;
12         }
13     }
14 
15     ······
16     @Override
17     public IBinder onBind(Intent intent) {
18         // TODO: Return the communication channel to the service.
19         return mBinder;
20     }
21 }

可见,先新建了一个Binder(绑定器)对象来对下载功能进行管理。而在DownloadBinder类中里写了对服务进行控制的功能,即开始下载的逻辑和查看下载进度的逻辑。

然后在onBind()方法里返回了这个实例,即Binder的对象。

然后在布局中添加两个按键:绑定服务和解除绑定。

在MainActivity中修改如下:

 1 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 2 
 3     private Button startService;
 4     private Button stopService;
 5     private Button bindService;
 6     private Button unbindService;
 7     private MyService.DownloadBinder downloadBinder;
 8     private ServiceConnection connection = new ServiceConnection() {
 9         @Override
10         public void onServiceConnected(ComponentName componentName, IBinder service) {
11             /*在活动成功绑定时候执行*/
12             downloadBinder = (MyService.DownloadBinder) service;
13             downloadBinder.startDownload();
14             downloadBinder.getProgress();
15         }
16 
17         @Override
18         public void onServiceDisconnected(ComponentName componentName) {
19             /*在活动和服务没有成功绑定时候执行*/
20         }
21     };
22 
23     protected void onCreate(Bundle savedInstanceState) {
24         super.onCreate(savedInstanceState);
25         setContentView(R.layout.activity_main);
26 
27         startService = (Button)findViewById(R.id.start_service);
28         stopService = (Button)findViewById(R.id.stop_service);
29         bindService = (Button)findViewById(R.id.bind_service);
30         unbindService = (Button)findViewById(R.id.unbind_service);
31         startService.setOnClickListener(this);
32         stopService.setOnClickListener(this);
33         bindService.setOnClickListener(this);
34         unbindService.setOnClickListener(this);
35     }
36 
37     @Override
38     public void onClick(View view) {
39         switch (view.getId()){
40             case R.id.start_service:
41                 Intent startIntent = new Intent(this,MyService.class);
42                 startService(startIntent); //启动服务
43                 break;
44             case R.id.stop_service:
45                 Intent stopIntent = new Intent(this,MyService.class);
46                 stopService(stopIntent);  //停止服务
47                 break;
48             case R.id.bind_service:
49                 Intent bindIntent = new Intent(this,MyService.class);
50                 bindService(bindIntent,connection,BIND_AUTO_CREATE);//绑定服务
51                 break;
52             case R.id.unbind_service:
53                 unbindService(connection);  //解绑服务
54                 break;
55             default:
56                 break;
57         }
58     }
59 }

如上可见,我们先创建一个ServiceConnection的匿名类,然后在里面重写了onServiceConnected()方法和onServiceDisconnected()方法用来在服务绑定成功 和 服务断开时候调用。在onServiceConnected()中,通过向下转型得到DownloadBinder的实例。现在就可以执行所有DownloadBinder中所有的方法了。即实现了指挥服务干什么功能。

然而目前活动和服务还是没有绑定,绑定是在绑定按键的点击事件中。绑定中先构建一个Intent对象,调用bindService方法进行绑定,传入三个参数,分别是刚构建的intent对象、ServiceConnection实例、和标示位(BIND_AUTO_CREATE表示绑定后自动创建)。(自动创建后会执行onCreate方法,但不会执行onStartCommand方法)

而解除绑定只需要调用unbindService()方法即可,传入参数ServiceConnection实例。

 

4.服务的生命周期

当项目调用了context的startService()方法后,相应的服务就会启动,并回调开启服务onStartCommand()方法,如果服务还没被创建,就先执行创建的onCreate()方法。然后服务就会一直处于运行状态,直到调用了stopService()方法或者是stopSelf()方法。因为服务只有一个实例,无论开启多少次,只要调用一次停止方法,服务就会停止了。

同时可以调用bindService()方法来绑定服务,并会回调onBind()方法,如果服务还没被创建,就先执行创建的onCreate()方法。之后调用方可以获取到onBind中返回的所有IBinder实例,就可以自由通信了。当调用解除绑定方法后,服务也会被销毁。

当对一个服务即调用了startService()后,又调用了bindService()方法。必须不满足以上两种条件,服务才会销毁。也就是说要调用stopService()和unBindService()两个方法才会使服务onDestroy()。

 

5.服务使用技巧

(1)使用前台服务

前台服务相比普通服务,会有一个正在运行的图标在系统的状态栏显示,效果类似于通知。而且不会被系统回收。

 1 public class MyService extends Service {
 2     ···
 3     /*在服务创建时被调用*/
 4     @Override
 5     public void onCreate() {
 6         super.onCreate();
 7         Log.d("MyService", "服务已创建");
 8         Intent intent = new Intent(this,MainActivity.class);
 9         PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
10         Notification notification = new NotificationCompat.Builder(this)
11                 .setContentTitle("this is content title")
12                 .setContentText("this is content text")
13                 .setWhen(System.currentTimeMillis())
14                 .setSmallIcon(R.mipmap.ic_launcher)
15                 .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
16                 .setContentIntent(pi)
17                 .build();
18         startForeground(1,notification);
19     }
20     ···
21 }

可以看出来和通知创建的方法很像,基本相同。只是最后调用startForeground()方法将其显示出来。第一个参数是通知id,第二个参数是notification对象。

 

(2)使用IntentService

因为在服务中多执行子线程,同时在子线程中多使用stopSelf()来使其工作结束后结束服务。使用IntentService类可以很好的完成以上的两个要求。

首先创建一个类MyIntentService继承自IntentService。如下:

 1 public class MyIntentService extends IntentService {
 2 
 3     public MyIntentService() {
 4         super("MyIntentService"); //调用父类的有参构造函数
 5     }
 6 
 7     @Override
 8     protected void onHandleIntent(@Nullable Intent intent) {
 9         //打印当前线程的id 来证明处理逻辑部分在子线程中
10         Log.d("MyIntentService","Thread id is "+Thread.currentThread().getId());
11     }
12 
13     @Override
14     public void onDestroy(){
15         super.onDestroy();
16         Log.d("MyIntentService","onDestroy executed");
17     }
18 }

类中首先提供了一个无参的构造函数,并在内部调用父类的有参构造函数。在子类中实现onHandleIntent()这个抽象方法,在这个方法中处理具体的逻辑,这个方法就是在子线程中了。因为运行完是自动停止的,我们重写onDestroy()方法来打印一条状态来证明一下。

布局中添加一个开始IntentService的按钮,在MainActivity中修改按钮的点击事件如下:

1             case R.id.start_intent_service:
2                 //打印主线程的id
3                 Log.d("MainActivity","Thread id is "+Thread.currentThread().getId());
4                 Intent intentService = new Intent(this,MyIntentService.class);
5                 startService(intentService);
6                 break;

可以看到。启动intentService和启动普通服务一样,都是新建一个intent对象,然后使用startService()进行跳转。

 

二 实例

一 添加依赖

配置build.gradle:

compilecom.squareup.okhttp3:okhttp:3.11.0

 

二 下载监听接口

 1 public interface DownloadListener {
 2     /*回调接口,用来对下载过程状态进行监听和回调*/
 3     void onProgress(int progress); //通知当前下载进度
 4 
 5     void onSuccess();  //通知下载成功事件
 6 
 7     void onFailed();  //通知下载失败事件
 8 
 9     void onPaused();  //通知下载暂停事件
10 
11     void onCanceled();  //通知下载取消事件
12 }

 

三 下载功能DownloadTask类(使用AsyncTask) 

新建一个DownloadTask类继承自AsyncTask类如下:

  1 public class DownloadTask extends AsyncTask<String, Integer, Integer> {
  2     /*传入三个参数 第一个是传一个字符串给后台任务,
  3     * 第二个是表示用整数显示进度,第三个是用整数来反馈结果*/
  4 
  5     /*定义了四种下载状态*/
  6     public static final int TYPE_SUCCESS = 0;
  7     public static final int TYPE_FAILED = 1;
  8     public static final int TYPE_PAUSED = 2;
  9     public static final int TYPE_CANCELED = 3;
 10 
 11     private DownloadListener listener;
 12     private boolean isCanceled = false;
 13     private boolean isPaused = false;
 14     private int lastProgress;
 15 
 16     //在DownloadTask的构造函数中传入刚刚定义的DownloadListener参数。
 17     public DownloadTask(DownloadListener listener) {
 18         this.listener = listener;
 19     }
 20 
 21     @Override
 22     /*在后台执行的下载逻辑*/
 23     protected Integer doInBackground(String... params) {
 24         InputStream is = null;
 25         RandomAccessFile savedFile = null;
 26         File file = null;
 27         try {
 28             long downloadedLength = 0;//记录已下载文件的长度
 29             String downloadUrl = params[0];  //参数中获得下载的URL地址
 30             String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/")); //根据url解析出下载的文件名
 31             String directory = Environment.getExternalStoragePublicDirectory
 32                     (Environment.DIRECTORY_DOWNLOADS).getPath(); //指定将文件下载到Download目录下
 33 
 34             /*判断Download中是否有要下载的文件,如果有读取已经下载的字节数
 35             * 可以在后面启动断点续传功能*/
 36             file = new File(directory + fileName);
 37             if (file.exists()) {
 38                 downloadedLength = file.length();
 39             }
 40             /*获取待下载文件的长度,如果为0则文件有误 下载失败,如果等于已下载文件长度则说明下载完成*/
 41             long contentLength = getContentLength(downloadUrl);  //待下载文件的总长度
 42             if (contentLength == 0) {
 43                 return TYPE_FAILED;
 44             } else if (contentLength == downloadedLength) {
 45                 return TYPE_SUCCESS;
 46             }
 47 
 48             /*发送一条网络请求*/
 49             OkHttpClient client = new OkHttpClient();
 50             //断点下载,指定从那个字节开始下载
 51             Request request = new Request.Builder()
 52                     .addHeader("RANGE", "bytes=" + downloadedLength + "-")  //断点下载
 53                     .url(downloadUrl)
 54                     .build();
 55 
 56             Response response = client.newCall(request).execute();
 57             if (response != null) {
 58                 is = response.body().byteStream();
 59                 savedFile = new RandomAccessFile(file, "rw");
 60                 savedFile.seek(downloadedLength);//跳过已经下载的字节
 61                 byte[] b = new byte[1024];
 62                 int total = 0; //本次已下载的总长度
 63                 int len;  //要下载的长度
 64                 /*当还有下载任务时就一直执行,在下载过程中不停判断是否有触发取消和暂停操作*/
 65                 while ((len = is.read(b)) != -1) {
 66                     if (isCanceled) {
 67                         return TYPE_CANCELED; //如果下载过程中取消
 68                     } else if (isPaused) {
 69                         return TYPE_PAUSED;  //如果下载过程中暂停
 70                     } else {
 71                         total += len;
 72                         savedFile.write(b, 0, len);
 73                         //计算已经下载的百分比
 74                         int progress = (int) ((total + downloadedLength) * 100 / contentLength);
 75                         publishProgress(progress);  //传入下载百分比
 76                     }
 77                 }
 78             }
 79         } catch (Exception e) {
 80             e.printStackTrace();
 81         } finally {
 82             /*清空下载过程中产生的数据和文件*/
 83             try {
 84                 if (is != null) {
 85                     is.close();
 86                 }
 87                 if (savedFile != null) {
 88                     savedFile.close();
 89                 }
 90                 if (isCanceled && file != null) {
 91                     file.delete();
 92                 }
 93             } catch (Exception e) {
 94                 e.printStackTrace();
 95             }
 96         }
 97         return TYPE_FAILED;  //如果在之前没有返回下载完成和其他情况,就是下载失败了。
 98     }
 99 
100     @Override
101     /*在界面上更新下载进度*/
102     protected void onProgressUpdate(Integer... values) {
103         int progress = values[0];
104         if (progress > lastProgress) {
105             listener.onProgress(progress);
106             lastProgress = progress;
107         }
108     }
109 
110     @Override
111     /*通知最终的下载结果*/
112     protected void onPostExecute(Integer status) {
113         switch (status) {
114             case TYPE_SUCCESS:
115                 listener.onSuccess();
116                 break;
117             case TYPE_FAILED:
118                 listener.onFailed();
119                 break;
120             case TYPE_PAUSED:
121                 listener.onPaused();
122                 break;
123             case TYPE_CANCELED:
124                 listener.onCanceled();
125                 break;
126             default:
127                 break;
128         }
129     }
130 
131     public void pauseDownload() {
132         isPaused = true;
133     }
134 
135     public void cancelDownload() {
136         isCanceled = true;
137     }
138 
139     /*得到下载任务总长度方法*/
140     private long getContentLength(String downloadUrl) throws IOException {
141         OkHttpClient client = new OkHttpClient();
142         Request request = new Request.Builder()
143                 .url(downloadUrl)
144                 .build();
145         Response response = client.newCall(request).execute();
146         if (response != null && response.isSuccessful()) {
147             long contentLength = response.body().contentLength();
148             response.body().close();
149             return contentLength;
150         }
151         return 0;
152     }
153 }

 

四 下载服务DownloadService

  1 public class DownloadService extends Service {
  2 
  3     private DownloadTask downloadTask;
  4     private String downloadUrl;
  5 
  6     /*创造一个DownloadListener匿名类实例,在匿名类中实现具体的五个方法*/
  7     private DownloadListener listener = new DownloadListener() {
  8         @Override
  9         public void onProgress(int progress) {
 10             /*使用getNotification构造一个显示下载进度的通知
 11             * 使用NotificationManager的notify方法去触发这个通知*/
 12             getNotificationManager().notify(1, getNotification("Downloading...", progress));
 13         }
 14 
 15         @Override
 16         public void onSuccess() {
 17             downloadTask = null;
 18             //下载成功时将前台服务通知关闭,并创建一个下载成功的通知
 19             stopForeground(true); //关闭前台服务
 20             getNotificationManager().notify(1, getNotification("Download success", -1));
 21             Toast.makeText(DownloadService.this, "Download Success", Toast.LENGTH_LONG).show();
 22         }
 23 
 24         @Override
 25         public void onFailed() {
 26             downloadTask = null;
 27             //下载失败将前台通知关闭,并创建一个下载失败的通知
 28             stopForeground(true);
 29             getNotificationManager().notify(1, getNotification("Download failed", -1));
 30             Toast.makeText(DownloadService.this, "Download Failed", Toast.LENGTH_LONG).show();
 31         }
 32 
 33         @Override
 34         public void onPaused() {
 35             downloadTask = null;
 36             Toast.makeText(DownloadService.this, "Download Paused", Toast.LENGTH_LONG).show();
 37         }
 38 
 39         @Override
 40         public void onCanceled() {
 41             downloadTask = null;
 42             stopForeground(true);
 43             Toast.makeText(DownloadService.this, "Canceled", Toast.LENGTH_LONG).show();
 44         }
 45     };
 46 
 47     /*为了服务和活动可以通信,创建一个DownloadBinder*/
 48     private DownloadBinder mBinder = new DownloadBinder();
 49 
 50     @Override
 51     public IBinder onBind(Intent intent) {
 52         // TODO: Return the communication channel to the service.
 53         return mBinder;
 54     }
 55     /*DownloadBinder中提供了开始,暂停 取消三种方法*/
 56     class DownloadBinder extends Binder {
 57         public void startDownload(String url) {
 58             if (downloadTask == null) {
 59                 downloadUrl = url;
 60                 downloadTask = new DownloadTask(listener);
 61                 downloadTask.execute(downloadUrl);
 62                 /*设置为前台服务*/
 63                 startForeground(1, getNotification("Downloading...", 0));
 64                 Toast.makeText(DownloadService.this,
 65                         "Downloading,,,", Toast.LENGTH_LONG).show();
 66             }
 67         }
 68 
 69         public void pauseDownload() {
 70             if (downloadTask != null) {
 71                 downloadTask.pauseDownload();
 72             }
 73         }
 74 
 75         public void cancelDownload() {
 76             if (downloadTask != null) {
 77                 downloadTask.cancelDownload();
 78             }
 79             if (downloadUrl != null) {
 80                 //取消下载要删除文件,关闭通知
 81                 String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));//下载文件名
 82                 String directory = Environment.getExternalStoragePublicDirectory
 83                         (Environment.DIRECTORY_DOWNLOADS).getPath();  //下载地址
 84                 File file = new File(directory + fileName);//下载文件的目录
 85                 if(file.exists()){
 86                     file.delete();
 87                 }
 88                 getNotificationManager().cancel(1);  //关闭通知
 89                 stopForeground(true);  //取消前台通知
 90                 Toast.makeText(DownloadService.this,"Canceled",
 91                         Toast.LENGTH_LONG).show();
 92             }
 93         }
 94     }
 95 
 96     /*返回通知管理器的方法*/
 97     private NotificationManager getNotificationManager() {
 98         return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
 99     }
100 
101     /*构造一个显示下载进度的通知*/
102     private Notification getNotification(String title, int progress) {
103         /*点击跳转intent*/
104         Intent intent = new Intent(this, MainActivity.class);
105         PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
106         NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
107         builder.setSmallIcon(R.mipmap.ic_launcher);
108         builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
109         builder.setContentIntent(pi);
110         builder.setContentTitle(title);
111         if (progress >= 0) {
112             //当progress大于或等于0才显示下载进度
113             builder.setContentText(progress + "%");
114             builder.setProgress(100, progress, false);
115         }
116         return builder.build();
117     }
118 }

服务类主要可以分成三部分,

  1. DownloadListener匿名类实例,在匿名类中实现具体的五个方法。
  2. 为了服务和活动绑定,创建的DownloadBinder和其实力,类中包含三种具体操作方法。
  3. 通知管理器和创建通知的getNotification()部分

 

五 布局文件

布局中包含三个按键,开始、暂停和取消。

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="vertical">
 5 
 6     <Button
 7         android:id="@+id/start_download"
 8         android:layout_width="match_parent"
 9         android:layout_height="wrap_content"
10         android:text="start_download" />
11 
12     <Button
13         android:id="@+id/pause_download"
14         android:layout_width="match_parent"
15         android:layout_height="wrap_content"
16         android:text="pause download" />
17 
18     <Button
19         android:id="@+id/cancel_download"
20         android:layout_width="match_parent"
21         android:layout_height="wrap_content"
22         android:text="cancel download" />
23 
24 </LinearLayout>

 

六 MainActivity代码

 1 public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 2 
 3     private DownloadService.DownloadBinder downloadBinder;
 4 
 5     private ServiceConnection connection = new ServiceConnection() {
 6         @Override
 7         public void onServiceConnected(ComponentName componentName, IBinder service) {
 8             //服务被绑定时的操作 获取了DownloadBinder的实例,有了实例就可以在活动中调用服务提供的方法。
 9             downloadBinder = (DownloadService.DownloadBinder) service;
10         }
11 
12         @Override
13         public void onServiceDisconnected(ComponentName componentName) {
14             //服务解除绑定时的操作
15         }
16     };
17 
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         setContentView(R.layout.activity_main);
21         Button startDownload = (Button) findViewById(R.id.start_download);
22         Button pauseDownload = (Button) findViewById(R.id.pause_download);
23         Button cancelDowmload = (Button) findViewById(R.id.cancel_download);
24         startDownload.setOnClickListener(this);
25         pauseDownload.setOnClickListener(this);
26         cancelDowmload.setOnClickListener(this);
27 
28         /*启动服务并绑定服务
29         * 启动服务可以保证DownloadService一直在后台运行*/
30         Intent intent = new Intent(this, DownloadService.class);
31         startService(intent);
32         bindService(intent, connection, BIND_AUTO_CREATE);
33         /*sd卡读写权限申请判断*/
34         if(ContextCompat.checkSelfPermission(MainActivity.this,
35                 Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
36             ActivityCompat.requestPermissions(MainActivity.this,
37                     new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
38         }
39     }
40 
41     @Override
42     public void onClick(View view) {
43         if(downloadBinder==null){
44             return;
45         }
46         switch (view.getId()) {
47             case R.id.start_download:
48                 String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=" +
49                         "1535868543461&di=9d49c6cd4d161e0f4d09795fe6b5ac37&imgtype=0&src=" +
50                         "http%3A%2F%2Fphotocdn.sohu.com%" +
51                         "2F20151013%2Fmp35444706_1444730447601_1_th.jpeg";
52                 downloadBinder.startDownload(url);
53                 break;
54             case R.id.pause_download:
55                 downloadBinder.pauseDownload();
56                 break;
57             case R.id.cancel_download:
58                 downloadBinder.cancelDownload();
59                 break;
60             default:
61                 break;
62         }
63     }
64 
65     //requestPermissions的回调函数,用来判断权限
66     @Override
67     public void onRequestPermissionsResult(int requesCode,String[] permissions,int[] grantResults){
68         switch (requesCode){
69             case 1:
70                 if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
71                     Toast.makeText(this,"拒绝授权无法使用程序",Toast.LENGTH_LONG)
72                             .show();
73                     finish();
74                 }
75                 break;
76             default:
77                 break;
78         }
79     }
80 
81     /*活动销毁的时候要解除服务的绑定*/
82     @Override
83     protected void onDestroy(){
84         super.onDestroy();
85         unbindService(connection);
86     }
87 }

 

七 权限声明

程序中使用到了网络和SD卡存储读取的权限,所以声明相关权限。

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

 

以上是关于Android四大组件——服务以及实例的主要内容,如果未能解决你的问题,请参考以下文章

四大组件:Activity生命周期-Android12

四大组件:Activity生命周期-Android12

Android第一行代码--Service(四大组件之一)

Android 四大组件学习之ContentProvider四

Android第一行代码--Service(四大组件之一)

Android第一行代码--Service(四大组件之一)