深入四大组件之Service
之前学习android的时候,说实话自己并没有特别认真学习Service。以至于等自己用到的时候一头雾水,“书到用时方恨少”这话一点也不假呀。为了多读书,所以就下定决心,好好的把Service深入的了解一下。我划分了几个学习步骤,由简单认识到深入了解。我们给出官方API Service官方API 一:Service的概念特性 (1)概念 :Service是后
之前学习android的时候,说实话自己并没有特别认真学习Service。以至于等自己用到的时候一头雾水,“书到用时方恨少”这话一点也不假呀。为了多读书,所以就下定决心,好好的把Service深入的了解一下。
我划分了几个学习步骤,由简单认识到深入了解。我们给出官方API Service官方API
一:Service的概念特性
(1)概念 :Service是后台运行的没有界面的优先级高于Activity的一个组件。
(2)Service与Thread的区别:
Service和Thread之间没有任何关系!
之所以有不少人会把它们联系起来,主要就是因为Service的后台概念。Thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。而Service我们最初理解的时候,总会觉得它是用来处理一些后台任务的,一些比较耗时的操作也可以放在这里运行,这就会让人产生混淆了。但是,如果我告诉你Service其实是运行在主线程里的,你还会觉得它和Thread有什么关系吗?
其实,后台和子线程是两个完全不同的概念:
Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。你可能又会问,Service既然是运行在主线程里,在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。
既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例;而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
(3)注意项
(4)服务的类型
二:Service的生命周期以及两种启动方式
1、使用start方式启动服务
package com.example.servicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyStartService extends Service {
@Override
public void onCreate() {
// TODO Auto-generated method stub
Log.i("info", "Service--onCreate()");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.i("info", "Service--onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
Log.i("info", "Service--onDestroy()");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.i("info", "Service--onBind()");
return null;
}
}
(2)在我们的MainActivity中修改布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start:" />
<Button
android:id="@+id/start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="StartService" />
<Button
android:id="@+id/stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="StopService" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bind:" />
<Button
android:id="@+id/bind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="BindService" />
<Button
android:id="@+id/play"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="播放" />
<Button
android:id="@+id/pause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="暂停" />
<Button
android:id="@+id/next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="下一首" />
<Button
android:id="@+id/pervious"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="上一首" />
<Button
android:id="@+id/unbind"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="doClick"
android:text="UnBindService" />
</LinearLayout>
效果图为:
intent1 = new Intent(MainActivity.this, MyStartService.class);
startService(intent1);
上面的为启动的方式,当我们停止的时候直接一句话就可以了。点击stopService按钮
stopService(intent1);
运行结果是什么呢?
2、使用bind方式启动服务
package com.example.servicedemo;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyBindService extends Service{
@Override
public void onCreate() {
// TODO Auto-generated method stub
Log.i("info", "BindService--onCreate()");
super.onCreate();
}
public class MyBinder extends Binder{
public MyBindService getService(){
return MyBindService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.i("info", "BindService--onBind()");
return new MyBinder();
}
@Override
public void unbindService(ServiceConnection conn) {
// TODO Auto-generated method stub
Log.i("info", "BindService--unbindService()");
super.unbindService(conn);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
Log.i("info", "BindService--onDestroy()");
super.onDestroy();
}
public void Play(){
Log.i("info", "播放");
}
public void Pause(){
Log.i("info", "暂停");
}
public void Pervious(){
Log.i("info", "上一首");
}
public void next(){
Log.i("info", "下一首");
}
}
(2)MyBindService类中的方法说明。
(3)在MainActivity启动我们服务,点击BindService按钮
intent2 = new Intent(MainActivity.this, MyBindService.class);
bindService(intent2, conn, Service.BIND_AUTO_CREATE);
我们看与start方式启动有一些稍微的区别,就是bindService(intent2,conn,Service.BIND_AUTO_CREATE);
ServiceConnection conn = new ServiceConnection() {
@Override//当服务跟启动源断开的时候 会自动回调
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
@Override//当服务跟启动源连接的时候 会自动回调
public void onServiceConnected(ComponentName name, IBinder binder) {
// TODO Auto-generated method stub
service = ((MyBinder)binder).getService();
}
};
看注释应该就应该能明白。
package com.example.servicedemo;
import com.example.servicedemo.MyBindService.MyBinder;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
Intent intent1;
Intent intent2;
MyBindService service;
ServiceConnection conn = new ServiceConnection() {
@Override//当服务跟启动源断开的时候 会自动回调
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
@Override//当服务跟启动源连接的时候 会自动回调
public void onServiceConnected(ComponentName name, IBinder binder) {
// TODO Auto-generated method stub
service = ((MyBinder)binder).getService();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void doClick(View v){
switch (v.getId()) {
case R.id.start:
intent1 = new Intent(MainActivity.this, MyStartService.class);
startService(intent1);
break;
case R.id.stop:
stopService(intent1);
break;
case R.id.play:
service.Play();
break;
case R.id.pause:
service.Pause();
break;
case R.id.pervious:
service.Pervious();
break;
case R.id.next:
service.next();
break;
case R.id.bind:
intent2 = new Intent(MainActivity.this, MyBindService.class);
startService(intent2);
bindService(intent2, conn, Service.BIND_AUTO_CREATE);
break;
case R.id.unbind:
unbindService(conn);
break;
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
stopService(intent2);
unbindService(conn);
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
真开心呀,写了一个小时终于写完一部分了。到此为止我们的Service基本用法算是完了。接下来就是更高级的了。我们写这篇博客的目的,也主要是为了学习下面的高级进阶。上面的主要是铺垫而已。
三、系统服务
常用系统服务: 后台Service在系统启动时被SystemServer开启: 1.MountService:监听是否有SD卡安装及移除 2.ClipboardService:提供剪切板功能 3.PackageManagerService:提供软件包的安装移除及查看 4.电量,网络连接状态等等 使用的时候通过getSystemService()的方法来实现: 这是一个Activity的一个方法,通过传入name->object>服务对象 WINDOW_SERVICE -- WindowManager -- 管理打开的窗口程序 LAYOUT_INFLATER_SERVICE -- LayoutInflater -- 取得XML里定义的View ACTIVITY_SERVICE -- ActivityManager -- 管理应用程序的系统状态 POWER_SERVICE -- PowerManger -- 电源服务 ALARM_SERVICE -- AlarmManager -- 闹钟服务 NOTIFICATION_SERVICE -- NotificationManager -- 状态栏服务 KEYGUARD_SERVICE -- KeyguardManager -- 键盘锁服务 LOCATION_SERVICE -- LocationManager -- 位置服务,如GPS SEARCH_SERVICE -- SearchManager -- 搜索服务 VEBRATOR_SERVICE -- Vebrator -- 手机震动服务 CONNECTIVITY_SERVICE -- Connectivity -- 网络连接服务 WIFI_SERVICE -- WifiManager -- Wi-Fi服务 TELEPHONY_SERVICE -- TelephonyManager -- 电话服务下面我们用代码演示一下如何使用这些服务。
LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.activity_main, null);
setContentView(view);
这个方法在平时我们的开发当中是非常有必要的。因为我们可以通过LayoutInflater动态的加载我们布局。
2、判断网络的连接状态
判断网络是否连接
public boolean isNetworkConnected(Context context) { // 判断网络的方法
if (context != null) {
ConnectivityManager mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();// 获取网络连接状态信息
if (mNetworkInfo != null) {// 如果不为空
return mNetworkInfo.isAvailable();// 返回网络状态属于活动状态
}
}
return false;
}
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
<uses-permission android:name="android.permission.READ_SMS"></uses-permission>
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
String phone = phoneEt.getText().toString();
String context = contextEt.getText().toString();
SmsManager manager = SmsManager.getDefault();
ArrayList<String> list = manager.divideMessage(context); //因为一条短信有字数限制,因此要将长短信拆分
for(String text:list){
manager.sendTextMessage(phone, null, text, null, null);
}
Toast.makeText(getApplicationContext(), "发送完毕", Toast.LENGTH_SHORT).show();
/**
* 调起系统发短信功能
* @param phoneNumber
* @param message
*/
public void doSendSMSTo(String phoneNumber,String message){
if(PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber)){
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:"+phoneNumber));
intent.putExtra("sms_body", message);
startActivity(intent);
}
}
还有其他好多种短信发送的。我们给出一个链接。自己可以看看写的非常详细
几种常见的发送短信方式
四、在Service里的耗时操作
package com.example.servicetest;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
public static final String TAG = "MyService";
//服务执行的操作
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
public void run() {
//处理具体的逻辑
stopSelf(); //服务执行完毕后自动停止
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
我在onStartCommand里面定义了一个子线程。当然在子线程处理完服务之后stopSelf自动停止服务。这是我们自然而然想到的办法,但是这种办法也有不妥,因为有时候我们老是忘记启动线程或者是停止服务。怎么办呢?谷歌给我们提供了一种方法,那就是
IntentService类 。它可以为我们异步的创建服务,还可以自动的停止服务。是不是很高大上。好,接下来好好地认识一下他,如何去用。
IntentService的工作机制
package com.example.servicetest;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
public class MyIntentService extends IntentService{
public MyIntentService() {
super("MyIntentService");//调用父类有参构造函数。这里我们手动给服务起个名字为:MyIntentService
// TODO Auto-generated constructor stub
}
//该方法在会在一个单独的线程中执行,来完成工作任务。任务结束后,该Service自动停止
@Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
for(int i = 0;i<3;i++) {
//打印当前线程的id
Log.d("MyIntentService","IntentService线程的id是:"+Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d("MyIntentService","onDestroy");
}
}
上面这段我们可以看到,我们需要继承IntentService,以前我们都是直接继承Service。然后在onHandlerIntent重写方法当中执行耗时操作。在我们这个例子里面我们只是每过一秒就在后台打印当前的线程ID。我们还是一样在我们的MainActivity中启动Service。我们使用Start方式启动就行。代码和上面的一样,就不给出了。
更多推荐
所有评论(0)