(一)Service简介
  服务适合执行那种不需要和用户交互而且还要长期运行的任务。所有的服务代码都是默认运行在主线程中,需要在服务内部手动添加子线程,在子线程中执行耗时任务。
 
(二)线程
1、线程的3种用法:
(1)继承Thread:
 class MyThread extends Thread{
public void run( ){
//执行耗时操作
}
}
new MyThread( ).start( );

(2)实现Runnable接口:

 class MyRunnable implements Runnable{
public void run( ){
//执行耗时操作
}
}
new Thread(new MyRunnable).start( );

(3)使用匿名类:

 new Thread(new Runnable( ){
public void run( ){
//执行耗时操作
}
}).start( );

2、Android不允许在子线程中更新UI,只能在主线程中更新。

(三)异步消息处理
1、不直接在子线程中进行UI操作,而是在子线程中通过Handler将Message传送给主线程,主线程中的Handler接收这个message,然后进行UI操作,这叫异步消息处理。
2、异步消息处理四步曲:
(1)在主线程中创建一个Handler类型的类成员变量对象,并重写handleMessage方法,用于处理相应事件:
 private Handler handler = new Handler( ){
public void handleMessage(Message msg){
switch(msg.what){ //msg的what字段是一个标志字段,整型
case xxx:
//在这里可以进行UI操作
textView.setText("Change text succeed!") //改变textView的字符
break;
default:
break;
}
}
}

(2)在子线程中需要进行UI操作时(如按钮点击事件中),创建一个Message对象,并通过Handler对象的sendMessage方法将该消息发送出去,比如:

 public static final int UPDATE_TEXT = 1;        //修改UI的标志值
......
@Override
public void onClick(View v){
switch(v.getId( )){
case R.id.chage_text_btn:
new Thread(new Runnable( ){
@Override
public void run( ){
Message msg = new Message( );
msg.what = UPDATE_TEXT ;
handler.sendMessage(msg);
}
}).start( );
break; default:
break;
}
}
(3)发出的Message进入MessageQueue队列等待处理。
(4)Looper一直尝试从MessageQueue中取出等待处理的消息,最后分发回handleMessage方法。
注:Message有一个what字段,可以携带标志识别信息(整型),还有arg1和arg2字段,可以携带整型数据,还有一个obj字段可以带一个Object对象。
3、异步消息处理机制示意图:
(四)AsyncTask
1、AsyncTask类是Android对异步消息处理的封装。
2、使用AsyncTask需要自定义一个类去继承它:
 class MyAsyncTask extends AsyncTask<Params, Progress, Result>
三个泛型的含义:
(1)Params:如果在执行AsyncTask时需要传递信息给后台,则传入此参数,如果不需要则为Void。
(2)Progress:如果在后台执行任务过程中,需要在界面上显示进程,则使用这个参数作为进程的单位,一般为Integer。
(3)Result:后台任务执行完后,如果需要对结果进行返回,则使用这个参数作为返回值的类型,如Boolean。
3、继承时需要实现的几个方法:
(1)void onPreExecute( );
该方法运行在UI线程中,可以进行UI的初始化等操作。
(2)boolean doInBackground(Void... params);
该方法的所有代码都在子线程中运行,在该方法中处理耗时任务,需要调用publicProgress(Progress)方法传递进度。
(3)void onProgressUpdate(Integer... values);
当在doInBackground中调用publicProgress方法时,会自动调用此方法,在这里进行UI操作。
(4)void onPostExecute(Boolean result);
执行收尾工作。
4、要启用MyAsyncTask,在主线程中这样用:new MyAsyncTask.execute( );
 

(五)Service

1、定义Service:

 public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
} @Override
public void onCreate() {
super.onCreate();
Log.d("MyService", "onCreate executed");
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService", "onStartCommand executed");
return super.onStartCommand(intent, flags, startId);
} @Override
public void onDestroy() {
super.onDestroy();
Log.d("MyService", "onDestroy executed");
}
}

2、Service类中有一个抽象方法onBind,还有三个常用方法:

(1)onCreate( ):会在Service创建时调用。
(2)onStartCommand( ):会在Service启动时调用。
(3)onDestory( ):在Service销毁时调用。
3、Service需要在AndroidManifest.xml中注册。
 <application
... >
<service android:name=".MyService" >
</service>
...
</application>
4、启动和停止Service:
(1)启动:
 Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);

(2)停止:

 Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);

5、Activity和Service通信:

(1)在Service中安插内线Binder,并在onBind方法中发送这个内线:

 public class MyService extends Service {

     private DownloadBinder mBinder = new DownloadBinder();

     class DownloadBinder extends Binder {    //自定义Binder,模拟下载功能
public void startDownload() {
Log.d("MyService", "startDownload executed");
} public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
} @Override
public IBinder onBind(Intent intent) {
return mBinder;
}
... //其他方法
}

(2)在Activity中创建内线及ServiceConnection,其中的onServiceConnected方法即可接收内线IBinder并通过向下转型获取Binder:

   ...
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
} @Override
public void onServiceDisconnected(ComponentName name) { };
};
...

(3)在合适的时候(如按钮的点击事件等)绑定Activity与Service:

 Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); //BIND_AUTO_CREATE指当绑定后,自动创建Service

(4)解除绑定:

 if(connection != null){
unbindService(connection);
}
6、Service的生命周期:
(1)每个Service都只会存在一个实例。
(2)方法:
 startService( )
onCreate( )
onStartCommand( )
onDestory( )
bindService( )
unbindService( )
stopService( )
stopSelf( ) //在Service中任何地方都可以用这个方法结束服务本身
onBind( )

(3)如果startService( )和bindService( )都调用了,那么必须同时满足unbindService( )和stopService( )都被调用才会执行onDestory( )方法。

7、前台Service:在系统状态栏中一直显示的可见Service,只需在Service的onCreate方法中添加如下代码即可(其实是通知的用法):

   @Override
public void onCreate() {
super.onCreate();
...
Notification notification = new Notification(R.drawable.ic_launcher,
"Notification comes", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "This is title",
"This is content", pendingIntent);
startForeground(1, notification);
}

8、IntentService:

  服务的代码默认都是在主线程中的,如果直接在服务里去处理一些耗时逻辑,就很容易出现ANR(Application Not Responding)的情况。这时就可以方便的使用已经把多线程封装好的IntentService类:

 public class MyIntentService extends IntentService {

     public MyIntentService() {        //需要一个无参的构造方法,调用父类的有参构造方法
super("MyIntentService");
} @Override
protected void onHandleIntent(Intent intent) { //这个方法默认在子线程中运行
// 打印当前线程ID
Log.d("MyIntentService", "Thread id is "
+ Thread.currentThread().getId()); // 在这里已经是在子线程中运行了,可以执行一些耗时操作,但不能执行UI操作
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
} @Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}

  IntentService在任务处理完后,会自动调用onDestory方法,不用再去人工调用unbindService或stopService方法。其他用法和普通Service一样。

(六)Service最佳实践:后台定时任务

1、Android中的定时任务实现方式有两种:Java API的Timer类和Android的Alarm机制。前者会受CPU休眠的影响,后者会唤醒CPU。
2、首先创建一个LongRunningService服务,重写其onStartCommand方法,在这里面执行定时任务:
 import java.util.Date;

 import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log; public class LongRunningService extends Service { @Override
public IBinder onBind(Intent intent) {
return null;
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
//创建子线程打印当前时间,模拟定时任务
new Thread(new Runnable() {
@Override
public void run() {
Log.d("LongRunningService",
"executed at " + new Date().toString());
}
}).start();
//1.创建AlarmManager
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int aMinute = 60 * 1000; // 一分钟的毫秒数
long triggerAtTime = SystemClock.elapsedRealtime() + aMinute;
//2.创建跳到广播接收器的Intent
Intent i = new Intent(this, AlarmReceiver.class);
//3.创建PendingIntent
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
//4.使用AlarmManager的set方法
//第一个参数:指定工作类型,有四种:ELAPSED_REALTIME_WAKEUP表示定时任务触发时间从
//系统开机算起,会唤醒CPU;ELAPSED_REALTIME,同ELAPSED_REALTIME_WAKEUP,但不会唤醒CPU;
//RTC表示从1970-1-1 00:00算起,不会唤醒CPU,RTC_WAKEUP同RTC,但会唤醒CPU。
//注:唤醒CPU和唤醒屏幕是不同的概念。
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi); return super.onStartCommand(intent, flags, startId);
}
}

3、创建AlarmReceiver类:

 import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent; public class AlarmReceiver extends BroadcastReceiver { @Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, LongRunningService.class);
context.startService(i); //反过来再启动服务,交替循环进行下去
}
}

4、在活动中启动服务:

 import android.app.Activity;
import android.content.Intent;
import android.os.Bundle; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Intent i = new Intent(this, LongRunningService.class);
startService(i);
}
}

5、在AndroidManifest.xml中注册服务和广播接收器。

6、分析:刚刚创建的这个定时任务,会每隔一分钟执行一次。

【本章结束】

随机推荐

  1. [开源]C#中开源软件大汇总(外国的)

    一.博客类项目 1.SubText 项目介绍:Subtext 是一个个人博客发布平台,详细的介绍请进SubText 项目分类:博客 项目license:BSD License 项目主页:http:// ...

  2. abp的开发20180425

    指定默认语言. mvc5 在Global中的 protected override void Application_BeginRequest(object sender, EventArgs e) ...

  3. [浪风分享]App必死 Web永生 看Web的前世今生 必会卷土重来

    当我们回顾技术的演变历史时,我们也应该关注技术演变的背后逻辑. 几年前,美国的<连线>杂志发表了“Web已死,Internet永生”的文章,由于作者之一是长尾理论的提出者克里斯.安德森(C ...

  4. Spring MVC控制器类名称处理映射

    以下示例显示如何使用Spring Web MVC框架使用控制器类名称处理程序映射. ControllerClassNameHandlerMapping类是基于约定的处理程序映射类,它将URL请求映射到 ...

  5. Struts2 异常处理

    Struts提供了一个更简单的方式来处理未捕获的异常,并将用户重定向到一个专门的错误页面.您可以轻松地Struts配置到不同的异常有不同的错误页面. Struts的异常处理所使用的“exception ...

  6. Spring入门之通过注解 处理 数据库事务

    用Spring 中的事务写的银行转帐的例子:(环境同上一个贴子) 一.表结构: (create table (id int,username varchar(10),salary int);) 二.文 ...

  7. Unity3D学习笔记——NGUI之UISlider

    UISlider:用于创建简单的滑动块和进度条,并且可以添加一个拇指按钮. 效果图如下: 一:使用步骤 1.从上面的效果看出,这个工具由四部分组成:背景图,进度图,进度lable显示,拇指按钮. 2. ...

  8. android自定义View_2——Making the View Interactive

    前言:绘制出一个view只是自定义view的一个部分,还需要自定义一些view的行为,来反馈用户的使用操作,反馈的 行为要合理性,就像真是的物理世界一样,不要太玄幻哦. 可以将view的行为封装到in ...

  9. SlidingMenu官方实例分析6——ResponsiveUIActivity

    ResponsiveUIActivity 这个类实现的是一个响应适UI设计重点是布局的设计: layout布局如下: layout-large-land布局如下: layout-xlarge布局如下: ...

  10. Android错误——基础篇

    1. Android工程在真机上运行调试: 花了二个小时的时间来把App热部署到小米机上,简直让我寒透了心, 原本是按照网上提供的步骤一步步的做着,没想到小米神机居然出的是什么内测小米助手,两个窗口来 ...