美文网首页
android service

android service

作者: MrMagicWang | 来源:发表于2016-07-30 15:35 被阅读61次

    Service 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务并与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

    服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。

    应使用服务还是线程?

    服务是一种即使用户未与应用交互,但它仍可以在后台运行的组件。 因此,应仅在必要时才创建服务。如果您确实要使用服务,则默认情况下,它仍会在应用的主线程中运行,因此,如果服务执行的是密集型或阻止性操作(例如 MP3 播放或联网),则仍应在服务内创建新线程。

    如需在主线程外部执行工作,不过只是在用户正在与应用交互时才有此需要,则应创建新线程而非服务。 例如,如果只是想在 Activity 运行的同时播放一些音乐,则可在 onCreate() 中创建线程,在 onStart() 中启动线程,然后在 onStop() 中停止线程。还可以考虑使用 AsyncTask 或 HandlerThread,而非传统的 Thread 类。

    Service的种类

    • 按运行类型分:
    类别 区别 应用
    前台服务 会在通知栏显示onGoing的 Notification 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。
    后台服务 默认的服务即为后台服务,即不会在通知一栏显示 onGoing的 Notification。 当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。
    • 按使用方式分:
    类别 区别
    startService启动的服务 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService。
    bindService启动的服务 方法启动的服务要进行通信。停止服务使用unbindService。
    同时使用startService、bindService 启动的服务 停止服务应同时使用stopService与unbindService。

    使用service

    • 使用startService启动服务
      1.定义一个类继承service
    public class MyService extends Service {
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
                //TODO do something useful
                return Service.START_NOT_STICKY;
        }
    
        @Override
        public IBinder onBind(Intent intent) {
              //TODO for communication return IBinder implementation
          return null;
        }
    }
    

    onstartCommad方法返回一个int类型用来定义服务在被android系统终止之后的重启方式。最常用的三种常量返回值



    2.在Manifest.xml文件中配置该Service

    <service
            android:name="MyService"
            android:icon="@drawable/icon"
            android:label="@string/service_name"
            >
    </service>
    

    3.使用Context的startService(Intent)方法启动该Service

    Intent intent = new Intent(this, MyService.class);
    startService(intent);
    

    4.不再使用时,调用stopService(Intent)方法停止该服务
    .
    使用这种方式创建启动服务的生命周期如下图:


    注意:
    1.如果服务已经开启,不会重复的执行onCreate(),而是会调用onStartCommand()。
    2.服务停止的时候调用 onDestory()。服务只会被停止一次。
    • 使用bindService方式启动服务
      如果您的服务仅供本地应用使用,不需要跨进程工作,则可以实现自有 Binder 类,让您的客户端通过该类直接访问服务中的公共方法。

    注:此方法只有在客户端和服务位于同一应用和进程内这一最常见的情况下方才有效。 例如,对于需要将 Activity 绑定到在后台播放音乐的自有服务的音乐应用,此方法非常有效。

    具体的创建服务的方法:

    ① 在服务中,创建一个可满足下列任一要求的 Binder 实例:
     - 包含客户端可调用的公共方法
     - 返回当前 Service实例,其中包含客户端可调用的公共方法
     - 返回由服务承载的其他类的实例,其中包含客户端可调用的公共方法

    ② 从 onBind()回调方法返回此 Binder实例。

    ③ 在客户端中,从 [onServiceConnected()](https://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回调方法接收 Binder,并使用提供的方法调用绑定服务。

    例如,以下这个服务可让客户端通过 Binder 实现访问服务中的方法:

    public class LocalService extends Service {
        // Binder given to clients
        private final IBinder mBinder = new LocalBinder();
        // Random number generator
        private final Random mGenerator = new Random();
    
        //Binder中包含返回该实例的方法
        public class LocalBinder extends Binder {
            LocalService getService() {
                // Return this instance of LocalService 
                //so clients can call public methods
                return LocalService.this;
            }
        }
        // onBind()回调方法返回此 Binder实例。
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
        /** method for clients */
        public int getRandomNumber() {
          return mGenerator.nextInt(100);
        }
    }
    

    LocalBinder 为客户端提供 getService() 方法,以检索 LocalService 的当前实例。这样,客户端便可调用服务中的公共方法。 例如,客户端可调用服务中的 getRandomNumber()。

    点击按钮时,以下这个 Activity 会绑定到 LocalService 并调用 getRandomNumber():

    public class BindingActivity extends Activity {
        LocalService mService;
        boolean mBound = false;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            // Bind to LocalService,建议在onstart方法中进行绑定
            Intent intent = new Intent(this, LocalService.class);
            //利用bindService(Intent, ServiceConnection, int)方法启动该Service
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            // Unbind from the service,建议在onstop方法中进行解绑
            if (mBound) {
                unbindService(mConnection);
                mBound = false;
            }
        }
    
        /** Called when a button is clicked (the button in the layout file attaches to
          * this method with the android:onClick attribute) */
        public void onButtonClick(View v) {
            if (mBound) {
                // Call a method from the LocalService.
                // However, if this call were something that might hang, 
                //then this request should occur in a separate thread 
                //to avoid slowing down the activity performance.
                int num = mService.getRandomNumber();
                Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
            }
        }
    
        /** Defines callbacks for service binding, passed to bindService() */
        private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName className,
                    IBinder service) {
                // We've bound to LocalService, cast the IBinder 
                //and get LocalService instance
                LocalBinder binder = (LocalBinder) service;
                mService = binder.getService();
                mBound = true;
            }
    
            @Override
            public void onServiceDisconnected(ComponentName arg0) {
                mBound = false;
            }
        };
    }
    

    特点:bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。绑定者可以调用服务里面的方法。

    使用这种方式创建启动服务的生命周期如下图:


    Service 元素的常见属性

    属性 描述
    android:name 服务类名
    android:label 服务的名字,如果此项不设置,那么默认显示的服务名则为类名
    android:icon 服务的图标
    android:permission 申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务
    android:process 表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字
    android:enabled 如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false
    android:exported 表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

    IntentService

    IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。
    另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
    那么,用IntentService有什么好处呢?首先,我们省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service

    下面来写一个Demo来模拟耗时操作在IntentService中的运行过程


    自定义intentService

    public class MyIntentService extends IntentService {
    
        public static final String REUSLT = "reuslt";
    
        public MyIntentService() {
            super("MyIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            String msg = intent.getStringExtra(MainActivity.COM_KEVINWANGY_TESTINTENTSERVICE_MSG);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            msg = "get result \"" + msg + "_result\" at "
                    + android.text.format.DateFormat.format("dd/MM/yy h:mm:ss aa", System.currentTimeMillis());
            Log.i("onHandleIntent", msg);
    
            Intent resultIntent = new Intent();
            resultIntent.setAction(MainActivity.ResultReceiver.RESULT_ACTION);
            resultIntent.putExtra(REUSLT, msg);
            LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this); //Service本身就是Context
            localBroadcastManager.sendBroadcast(resultIntent);
        }
    }
    

    定义MainActiviy , 其中包含一个BroadCastReceiver

    public class MainActivity extends AppCompatActivity {
    
        public static final String COM_KEVINWANGY_TESTINTENTSERVICE_MSG = "com.kevinwangy.testintentservice.msg";
        private Button mButton;
        private TextView mStart_text;
        private TextView mFinish_text;
        private EditText mEditText;
        private String mStart_msg;
        private ResultReceiver mResultReceiver;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            final StringBuilder stringBuilder = new StringBuilder();
    
            mStart_text = (TextView)findViewById(R.id.start_text);
            mFinish_text = (TextView)findViewById(R.id.finish_text);
    
            mEditText = (EditText)findViewById(R.id.input_edit);
    
            mButton = (Button)findViewById(R.id.input_btn);
            mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mStart_msg = mEditText.getText().toString();
                    stringBuilder.append("send message \"" + mStart_msg + "\" at "
                            + android.text.format.DateFormat.format("dd/MM/yy h:mm:ss aa", System.currentTimeMillis()) + "\n");
                    mStart_text.setText(stringBuilder.toString());
    
                    Intent intent = new Intent(MainActivity.this, MyIntentService.class);
                    intent.putExtra(COM_KEVINWANGY_TESTINTENTSERVICE_MSG, mStart_msg);
                    startService(intent);
                }
            });
        }
    
        @Override
        protected void onStart() {
            super.onStart();
        }
    
        @Override
        protected void onStop() {
            super.onStop();
        }
    
        public class ResultReceiver extends BroadcastReceiver {
        }
    }
    

    ResultReceiver 的定义如下

        public class ResultReceiver extends BroadcastReceiver {
            public static final String RESULT_ACTION = "com.kevinwang.testintentservice.resultReceiver";
    
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent != null && TextUtils.equals(intent.getAction(), RESULT_ACTION)) {
                    String result = intent.getStringExtra(MyIntentService.REUSLT);
                    Log.i("onReceive", result);
                    Log.i("onReceive", "context is " + context.toString());
                    mFinish_text.setText(result);
                }
            }
        }
    

    在onstart中注册BroadCastReceiver

        protected void onStart() {
            super.onStart();
            IntentFilter filter = new IntentFilter(ResultReceiver.RESULT_ACTION);
            mResultReceiver = new ResultReceiver();
            LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
            localBroadcastManager.registerReceiver(mResultReceiver, filter);
        }
    

    在onstop中解除注册

        protected void onStop() {
            super.onStop();
            LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
            localBroadcastManager.unregisterReceiver(mResultReceiver);
        }
    

    在androidManifest中声明

            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
    
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
            </activity>
    
            <service android:name=".MyIntentService"/>
    

    关于service、intentService、thread和AsyncTask的对比

    参考文档及博客服务绑定服务Service那点事儿

    相关文章

      网友评论

          本文标题:android service

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