zoukankan      html  css  js  c++  java
  • Service组件应用实例

    这是通过Service实现的一个计数器服务功能实例。

    直接先上代码:

    ICounterCallback.java

    1 package com.example.counter;
    2 
    3 /**
    4  * 火龙裸
    5  * */
    6 public interface ICounterCallback {
    7     void count(int val);
    8 }

      这个文件定义了一个计数器回调接口ICounterCallback,它只有一个成员函数count,用来将CounterService服务组件的当前“计数结果”,实时地更新到对应的CounterActivity组件上,进行用户界面显示。

    ICounterService.java

    1 package com.example.counter;
    2 
    3 /**
    4  * 火龙裸
    5  * */
    6 public interface ICounterService {
    7     void strtCounter(int initVal, ICounterCallback callback);
    8     void stopCounter();
    9 }

      这个文件定义了一个计数器接口ICounterService,它有两个成员函数startCounter和stopCounter;其中,前者用来启动计数器,后者用来停止计数器。在启动计数器时,可以指定计数器的初始值,以及更新用户界面的回调接口。

    CounterService.java

     1 package com.example.counter;
     2 
     3 import android.app.Service;
     4 import android.content.Intent;
     5 import android.os.AsyncTask;
     6 import android.os.Binder;
     7 import android.os.IBinder;
     8 import android.util.Log;
     9 
    10 import androidx.annotation.Nullable;
    11 
    12 /**
    13  * 火龙裸
    14  * */
    15 public class CounterService extends Service implements ICounterService {
    16     private static final String TAG = "CounterService";
    17 
    18     private boolean stop = false;
    19     private ICounterCallback counterCallback = null;
    20 
    21     private final CounterBinder binder = new CounterBinder();
    22 
    23     public class CounterBinder extends Binder{
    24         public CounterService getService() {
    25             return CounterService.this;
    26         }
    27     }
    28 
    29     @Override
    30     public void onCreate() {
    31         super.onCreate();
    32         Log.e(TAG, "onCreate: =============");
    33     }
    34 
    35     @Nullable
    36     @Override
    37     public IBinder onBind(Intent intent) {
    38         return binder;
    39     }
    40 
    41 
    42 
    43     @Override
    44     public void strtCounter(int initVal, ICounterCallback callback) {
    45         counterCallback = callback;
    46 
    47         AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>() {
    48             @Override
    49             protected Integer doInBackground(Integer... integers) {
    50                 Integer initCounter = integers[0];
    51 
    52                 stop = false;
    53 
    54                 while (!stop) {
    55                     publishProgress(initCounter);
    56 
    57                     try {
    58                         Thread.sleep(1000);
    59                     } catch (InterruptedException e) {
    60                         e.printStackTrace();
    61                     }
    62 
    63                     initCounter++;
    64                 }
    65 
    66                 return initCounter;
    67             }
    68 
    69             @Override
    70             protected void onProgressUpdate(Integer... values) {
    71                 super.onProgressUpdate(values);
    72 
    73                 int val = values[0];
    74                 counterCallback.count(val);
    75             }
    76 
    77             @Override
    78             protected void onPostExecute(Integer val) {
    79                 counterCallback.count(val);
    80             }
    81         };
    82 
    83         task.execute(initVal);
    84         Log.e(TAG, "strtCounter: 启动AsyncTask");
    85     }
    86 
    87     @Override
    88     public void stopCounter() {
    89         stop = true;
    90         Log.e(TAG, "stopCounter: 停止AsyncTask 任务标志位");
    91     }
    92 }

      CounterService是一个Service组件,因此,它必须要从Service类继承下来。CounterService组件同时实现了计数器接口ICounterService,用来提供计数器服务。在CounterService组件启动时,它的成员函数onCreate就会被调用;而在CounterService组件被绑定时,它的成员函数onBind就会被调用。

    注意:CounterService组件有一个成员变量binder,它指向一个类型为CounterBinder的Binder本地对象。当CounterService组件被绑定时,它就会将内部的Binder本地对象binder返回给绑定着,以便绑定者可以通过这个Binder本地对象来获得它的一个计数器访问接口。

    这里之所以要返回一个Binder本地对象给绑定者,是因为绑定着与CounterService组件可能是运行在两个不同的应用程序进程中的。不过本例中,启动CounterService组件的“CounterActivity组件”和“CounterService”组件是运行在同一个应用程序进程中的。

      CounterService组件的成员函数startCounter和stopCounter分别用来启动和停止内部的计数器;其中,成员函数startCounter使用一个异步任务task来启动一个计数器,成员函数stopCounter通过将CounterService组件的成员变量stop设置为true来停止这个计数器。

    当计数器被停止执行时,异步任务task的成员函数onPostExecute就会被调用,它主要是使用CounterService组件内部的一个ICounterCallback接口将计数器的最终技术结果更新到用户界面上显示出来。

    注意:在异步任务task的三个成员函数中,只有成员函数doInBackground是在后台线程中执行的,其余两个成员函数onProgressUpdate和onPostExecute都是在应用程序的主线程中执行的,因此,它们可以被用来更新用户界面。

    CounterActivity.java

     1 package com.example.counter;
     2 
     3 import androidx.appcompat.app.AppCompatActivity;
     4 
     5 import android.content.ComponentName;
     6 import android.content.Intent;
     7 import android.content.ServiceConnection;
     8 import android.os.Bundle;
     9 import android.os.IBinder;
    10 import android.util.Log;
    11 import android.view.View;
    12 import android.widget.Button;
    13 import android.widget.TextView;
    14 
    15 /**
    16  * 火龙裸
    17  * */
    18 public class CounterActivity extends AppCompatActivity implements View.OnClickListener, ICounterCallback {
    19     private static final String TAG = "CounterActivity";
    20 
    21     private Button btn_start;
    22     private Button btn_stop;
    23     private TextView tv_count;
    24 
    25     private ICounterService counterService = null;
    26 
    27     @Override
    28     protected void onCreate(Bundle savedInstanceState) {
    29         super.onCreate(savedInstanceState);
    30         setContentView(R.layout.activity_counter);
    31         btn_start = findViewById(R.id.btn_start);
    32         btn_stop = findViewById(R.id.btn_stop);
    33         tv_count = findViewById(R.id.tv_count);
    34         btn_start.setOnClickListener(this);
    35         btn_stop.setOnClickListener(this);
    36 
    37         Intent serviceIntent = new Intent(CounterActivity.this, CounterService.class);
    38         bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE);
    39     }
    40 
    41     @Override
    42     public void onClick(View view) {
    43         switch (view.getId()){
    44             case R.id.btn_start:
    45                 counterService.strtCounter(0, this);
    46                 break;
    47             case R.id.btn_stop:
    48                 counterService.stopCounter();
    49                 break;
    50         }
    51     }
    52 
    53     /**
    54      * 计数器服务的回调
    55      * */
    56     @Override
    57     public void count(int val) {
    58         tv_count.setText("计算值为:" + val);
    59     }
    60 
    61     @Override
    62     protected void onDestroy() {
    63         super.onDestroy();
    64         unbindService(serviceConnection);
    65     }
    66 
    67     private ServiceConnection serviceConnection = new ServiceConnection() {
    68         @Override
    69         public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    70             counterService = ((CounterService.CounterBinder)iBinder).getService();
    71             Log.e(TAG, "onServiceConnected: ======================>");
    72         }
    73 
    74         @Override
    75         public void onServiceDisconnected(ComponentName componentName) {
    76             counterService = null;
    77             Log.e(TAG, "onServiceDisconnected: >>>>>>>>>>>>>>>");
    78         }
    79     };
    80 }

      CounterActivity是应用程序的根Activity组件,因此,它必须要从类Activity继承下来。CounterActivity同时实现了计数器回调接口ICounterCallback,以便可以实时地回调更新用户界面上的计数值。

      CounterActivity组件被启动时,它的成员函数onCreate就会被调用,这时候它就会调用其父类ContextWrapper的成员函数bindService来启动CounterService组件。当CounterService组件启动起来之后,CounterActivity组件内部的ServiceConnection对象serviceConnection的成员函数onServiceConnected就会被调用,这时候CounterActivity组件就会获得CounterService服务组件中的一个Binder本地对象。由于CounterActivity组件和CounterService服务组件是运行在同一个应用程序进程中的,因此,ServiceConnection对象serviceConnection的成员函数onServiceConnected可以安全地将前面获得的一个Binder本地对象转换为一个类型为CounterBinder的对象,接着再调用它的成员函数getService来获得一个计数器接口。有了这个计数器接口之后,CounterActivity组件就相当于将CounterService服务组件绑定起来了。

      由于CounterActivity组件在启动时绑定了CounterService组件,因此当它销毁时,即它的成员函数onDestrory被调用时,它就必须要调用父类ContextWrapper的成员函数unbindService来解绑CounterService服务组件。解绑成功后,CounterActivity组件内部的ServiceConnection对象serviceConnection的成员函数onServiceDisconnected就会被调用,用来执行清理工作。

    activity_counter.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     xmlns:app="http://schemas.android.com/apk/res-auto"
     4     xmlns:tools="http://schemas.android.com/tools"
     5     android:layout_width="match_parent"
     6     android:layout_height="match_parent"
     7     tools:context=".CounterActivity">
     8 
     9     <Button
    10         android:id="@+id/btn_start"
    11         android:layout_width="wrap_content"
    12         android:layout_height="wrap_content"
    13         android:text="开始"
    14         app:layout_constraintBottom_toBottomOf="parent"
    15         app:layout_constraintHorizontal_bias="0.498"
    16         app:layout_constraintLeft_toLeftOf="parent"
    17         app:layout_constraintRight_toRightOf="parent"
    18         app:layout_constraintTop_toTopOf="parent"
    19         app:layout_constraintVertical_bias="0.196" />
    20 
    21     <TextView
    22         android:id="@+id/tv_count"
    23         android:layout_width="wrap_content"
    24         android:layout_height="wrap_content"
    25         android:text="计算值为:"
    26         android:textSize="20sp"
    27         app:layout_constraintBottom_toBottomOf="parent"
    28         app:layout_constraintHorizontal_bias="0.498"
    29         app:layout_constraintLeft_toLeftOf="parent"
    30         app:layout_constraintRight_toRightOf="parent"
    31         app:layout_constraintTop_toTopOf="parent"
    32         app:layout_constraintVertical_bias="0.311" />
    33 
    34     <Button
    35         android:id="@+id/btn_stop"
    36         android:layout_width="wrap_content"
    37         android:layout_height="wrap_content"
    38         android:text="停止"
    39         app:layout_constraintBottom_toBottomOf="parent"
    40         app:layout_constraintHorizontal_bias="0.498"
    41         app:layout_constraintLeft_toLeftOf="parent"
    42         app:layout_constraintRight_toRightOf="parent"
    43         app:layout_constraintTop_toTopOf="parent"
    44         app:layout_constraintVertical_bias="0.409" />
    45 
    46 </androidx.constraintlayout.widget.ConstraintLayout>

    AndroidManifest.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.example.counter">
     4 
     5     <application
     6         android:allowBackup="true"
     7         android:icon="@mipmap/ic_launcher"
     8         android:label="@string/app_name"
     9         android:roundIcon="@mipmap/ic_launcher_round"
    10         android:supportsRtl="true"
    11         android:theme="@style/Theme.Counter">
    12         <activity
    13             android:name=".CounterActivity"
    14             android:exported="true">
    15             <intent-filter>
    16                 <action android:name="android.intent.action.MAIN" />
    17 
    18                 <category android:name="android.intent.category.LAUNCHER" />
    19             </intent-filter>
    20         </activity>
    21         <service
    22             android:name=".CounterService"
    23             android:enabled="true" />
    24     </application>
    25 
    26 </manifest>
  • 相关阅读:
    centos7无法上网问题
    git 笔记记录
    高级 JsRender 模板功能
    Xamarin 示例Standard Controls报错:xamarin Failed to compile interface file. See Build Output for details
    Xamarin学习资源收集
    Bootstrap学习笔记1
    动态样式语言Less学习笔记
    html5的发展历程和由此引起的政治斗争
    网页引用本地电脑的字体 css设置浏览器会不显示的解决办法
    css引入方式优先级以及不同选择器的优先级区别
  • 原文地址:https://www.cnblogs.com/huolongluo/p/15772304.html
Copyright © 2011-2022 走看看