后台的幽灵 - Service
本节内容涉及到
一 什么是Service
二
如何使用Service
三
Service的生命周期
一 什么是Service
Service,看名字就知道跟正常理解的“服务”差不多,后台运行,可交互这样的一个东西。它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用,
Context.startService() 和
Context.bindService()。
两种启动Service的方式有所不同。这里要说明一下的是如果你在Service的onCreate或者onStart做一些很耗时间的事情,最好在Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。
什么时候需要Service呢?比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。
二
如何使用Service
那接下来用代码来说明一下怎么使用Service,这里我们要讲的是Local Service也就是你自己的一个Service, 你也可以操作别的应用程序的service如果它允许你那么去做的话,这就设计到一个比较麻烦的东西interprocess communication (IPC),在不同的进程中通信的机制,这个我自己也还没有用过,等用了以后再跟大伙说说,通常情况下Local的就够用啦。
跟Activity一样首先你要写一个类继承自android.app.Service,在这里我叫他TestService
代码如下:
package com.haric.tutorial;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class TestService extends Service {
private static final String TAG = "TestService";
private NotificationManager _nm;
@Override
public IBinder onBind(Intent i) {
Log.e(TAG, "============> TestService.onBind");
return null;
}
public class LocalBinder extends Binder {
TestService getService() {
return TestService.this;
}
}
@Override
public boolean onUnbind(Intent i) {
Log.e(TAG, "============> TestService.onUnbind");
return false;
}
@Override
public void onRebind(Intent i) {
Log.e(TAG, "============> TestService.onRebind");
}
@Override
public void onCreate() {
Log.e(TAG, "============> TestService.onCreate");
_nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
showNotification();
}
@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "============> TestService.onStart");
}
@Override
public void onDestroy() {
_nm.cancel(R.string.service_started);
Log.e(TAG, "============> TestService.onDestroy");
}
private void showNotification() {
Notification notification = new Notification(R.drawable.face_1,
"Service started", System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, TestServiceHolder.class), 0);
// must set this for content view, or will throw a exception
notification.setLatestEventInfo(this, "Test Service",
"Service started", contentIntent);
_nm.notify(R.string.service_started, notification);
}
}
其中用到Notification是为了明显地表明Service存活的状态,跟demo的code学过来的,这样看上去直观一点,更多关于Notification的内容以后UI部分来写吧,现在就知道怎么使用就好了。
@Override
public void onCreate() {
Log.e(TAG, "============> TestService.onCreate");
_nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
showNotification();
}
像这样,我在Service的几个生命周期函数中加了打印log的语句,方便测试。
public class LocalBinder extends Binder {
TestService getService() {
return TestService.this;
}
}
这个方法是为了让调用者得到这个Service并操作它。
Service本身就这样简单了,你需要做什么就在onCreate和onStart里做好了,起个线程什么的。
再看一下它的调用者,TestServiceHolder
package com.haric.tutorial;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class TestServiceHolder extends Activity {
private boolean _isBound;
private TestService _boundService;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_service_holder);
setTitle("Service Test");
initButtons();
}
private ServiceConnection _connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
_boundService = ((TestService.LocalBinder)service).getService();
Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// unexpectedly disconnected,we should never see this happen.
_boundService = null;
Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}
};
private void initButtons() {
Button buttonStart = (Button) findViewById(R.id.start_service);
buttonStart.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
startService();
}
});
Button buttonStop = (Button) findViewById(R.id.stop_service);
buttonStop.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
stopService();
}
});
Button buttonBind = (Button) findViewById(R.id.bind_service);
buttonBind.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
bindService();
}
});
Button buttonUnbind = (Button) findViewById(R.id.unbind_service);
buttonUnbind.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
unbindService();
}
});
}
private void startService() {
Intent i = new Intent(this, TestService.class);
this.startService(i);
}
private void stopService() {
Intent i = new Intent(this, TestService.class);
this.stopService(i);
}
private void bindService() {
Intent i = new Intent(this, TestService.class);
bindService(i, _connection, Context.BIND_AUTO_CREATE);
_isBound = true;
}
private void unbindService() {
if (_isBound) {
unbindService(_connection);
_isBound = false;
}
}
}
这里可以看到两种启动方法,start和bind,当然也是通过intent调用的,在intent中指明指定要启动的Service的名字,stop也一样
:
private void startService() {
Intent i = new Intent(this, TestService.class);
this.startService(i);
}
private void stopService() {
Intent i = new Intent(this, TestService.class);
this.stopService(i);
}
对于bind的话,需要一个ServiceConnection对象
private ServiceConnection _connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
_boundService = ((TestService.LocalBinder)service).getService();
Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// unexpectedly disconnected,we should never see this happen.
_boundService = null;
Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}
};
用来把Activity和特定的Service连接在一起,共同存亡,具体的生命周期细节下一段来讲。
三
Service的生命周期
Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy
我们有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。
1 通过startService
Service会经历 onCreate -> onStart
stopService的时候直接onDestroy
如果是调用者(TestServiceHolder)自己直接退出而没有调用stopService的
话,Service会一直在后台运行。
下次TestServiceHolder再起来可以stopService。
2 通过bindService
Service只会运行onCreate, 这个时候
TestServiceHolder
和TestService绑定在一起
TestServiceHolder 退出了,Srevice就会调用onUnbind->onDestroyed
所谓绑定在一起就共存亡了。
那有同学问了,要是这几个方法交织在一起的话,会出现什么情况呢?
一个原则是Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又bindService,Service只被创建一次。如果先是bind了,那么start的时候就直接运行Service的onStart方法,如果先是start,那么bind的时候就直接运行onBind方法。如果你先bind上了,就stop不掉了,对啊,就是stopService不好使了,只能先UnbindService, 再StopService,所以是先start还是先bind行为是有区别的。
看起来情况很多,不过我会把这次的代码包括上回Activity生命周期的研究代码都贴上了,希望你喜欢!大家有兴趣可以回去点点按钮看看log,多看几遍就知道了。
分享到:
相关推荐
为了开始使用Android SDK 2.2,开发者需要安装Java Development Kit(JDK),然后配置好Android SDK Manager来下载必要的平台和工具。在Eclipse中安装ADT插件后,可以创建新的Android项目,选择目标API级别为2.2,并...
本主题将深入探讨Android 2.2(Froyo)版本的通讯录源码,这对于理解Android系统的底层机制,尤其是对于那些希望进行定制化开发或者优化通讯录功能的开发者来说,具有很高的价值。 首先,我们要明白Android 2.2的...
Android Launcher2.2使用SQLite数据库来存储用户的布局信息,如快捷方式的位置、文件夹内容等。`com.android.launcher2.Workspace`类管理着桌面布局,而`com.android.launcher2.shortcuts.DeepShortcutManager`则...
打开Eclipse(当时常用的IDE,现在更多人可能使用Android Studio),创建一个新的Android项目。在向导中,选择“New Project”,输入项目名,选择最小SDK版本为API 8,然后点击“Next”。 ### 6. 编写代码 在生成...
描述中提到“关联eclipse使用超爽”,这表明此压缩包可能包含了用于在Eclipse集成开发环境中(IDE)编译和调试Android 2.2源代码的必要文件和配置。Eclipse是当时非常流行的Android开发工具,它拥有ADT(Android ...
总的来说,“lockscreen for android 2.2”是Android生态系统中的一个创新实践,它结合了Android 2.2的特性和用户需求,通过定制化的锁屏界面,为用户提供更便捷、个性化的手机使用体验。这背后涉及的不仅是软件开发...
以下是一些关于在Android 2.2中使用C++实现截屏的关键知识点: 1. **JNI(Java Native Interface)**:由于Android系统主要基于Java,因此要在C++中进行操作,我们需要使用JNI作为桥梁,将Java层与C/C++层进行通信...
这份文档集合包含了Android 2.2(API级别8)及部分2.3(API级别9)的详细中文翻译,旨在帮助开发者理解和使用Android平台的各种功能和接口。 首先,Android API文档是开发者进行程序设计的重要参考资料,它详细地...
这个特定版本可能与传智播客的Android开发基础视频教程有关,它可能是教程中推荐或使用的环境,经过了对版本号和信息的比对和推测才被找到。 【标签】"android-2.2 r02 windows zip" 进一步强调了这个SDK的版本、...
《Android 2.2 SDK 源码解析与深度探讨》 Android 2.2,代号Froyo(冻酸奶),是Google于2010年推出的一个重要的Android操作系统版本。这个版本在前作的基础上进行了诸多性能优化和功能升级,为开发者提供了更丰富...
解压Android 2.2源码到Android SDK的platforms/android-8文件夹内,是为了在Eclipse等开发环境中使用源码浏览功能。这样,开发者可以在编写代码时直接查看系统类的源码,有助于理解和解决问题。重启Eclipse后,源码...
Android 2.2(Froyo)源码学习是Android开发者深入理解系统工作原理和优化应用性能的关键步骤。源码提供了对操作系统内核、库、框架以及用户界面等所有层次的详细视图,使得开发者能够从底层到高层全面了解Android...
最后,"J动不已x"可能指的是一个特定的教程或示例项目,它可能涵盖了Java编程基础以及与Android 2.2相关的实践应用。这部分内容可以帮助读者将理论知识与实际操作结合起来,进一步巩固学习成果。 总的来说,...
3. **Dalvik与ART虚拟机**:在Android 2.2中,仍然使用的是Dalvik虚拟机,它是Android运行应用程序的基础。了解Dalvik的工作机制,如字节码执行、垃圾回收等,对于优化应用性能很有帮助。 4. **Framework层**:这是...
为了调试和测试,学习如何使用DDMS(Dalvik Debug Monitor Service)工具,它提供了进程管理、内存分析、线程和堆信息等功能。此外,理解AndroidManifest.xml文件的作用也非常重要,它是每个Android应用的核心配置...
**Android2.2 API 中文文档系列(3)—— AccessibilityService** 在Android系统中,`AccessibilityService` 是一个关键的框架组件,它允许应用程序监听并响应用户与系统的交互,特别是帮助残障用户或者实现自动化...
《ac100升级至Android 2.2的详尽教程》 对于拥有ac100设备的用户来说,升级操作系统至Android 2.2是一个提升设备性能和体验的重要步骤。本文将指导您逐步完成这一过程,确保您的ac100顺利运行最新的Android版本。 ...
Android 2.2(Froyo)是Google发布的Android系统的一个版本,它在2010年推出,支持许多新特性和性能优化。在这个版本上进行彩信发送的编程,开发者需要对Android的MMS(Multimedia Messaging Service)服务有深入...
8. **HttpClient/HttpURLConnection**:在Android 2.2中,开发者可能会使用HttpClient库进行网络请求,但在较新版本中,推荐使用HttpURLConnection,因为HttpClient已被弃用。 9. **JSON解析**:微博API通常返回...
这个“android2.2中文API”是针对开发者设计的一份详尽的中文参考文档,帮助他们理解和使用Android 2.2平台上的各种API接口和功能。 1. **Android SDK**: Android Software Development Kit (SDK) 是开发Android...