服务 android多线程编程 服务的基本用法 服务的生命周期 服务技巧

服务(Service): 在Android中实现程序后台运行的解决方案,本身的运行并不依赖于用户可视的UI界面。 适用:

  • 并不依赖于用户可视的UI界面(不一定,前台Service就是与Notification界面结合使用的)
  • 不需要和用户交互而且要求长时间运行 服务依赖于创建服务的所在的应用程序进程。(进程被杀死,依赖该进程的服务停止) 服务并不会自动开启线程,因此需要在Service内部创建子线程。

服务基本用法:

Service分类:

  • Started Service:被一个组件调用startService()开启的Service。
  • 扩展Service: 这是所有服务的基类。扩展这个类的时候,特别重要的一点是,需要创建一个新的线程来做服务任务,因为service默认是运行在你的主线程(UI线程)中的,它会使你的主线程运行缓慢。
  • 扩展IntentService: service的子类,在一个工作线程(子线程)中处理所有的启动请求。需要是实现onHandlerIntent()方法,通过这个函数处理接受的每一个启动请求。 (Android提供的便于创建异步,能自动停止的service)

service的onStartCommand()方法被调,根据传递intent开启Service,拥有一个独立于开始它的组件(不是进程)的生命周期。 默认service运行在声明它的应用的同一个进程里面,而且在应用的主线程里面。 - Bound Service: 与Activity相绑定的service。

定义一个服务:

  • AndroidManifest.xml 注册:Service属于四大组件之一,无论是Started Service和Bound Service,都有Service基类继承而来,都需要在AndroidManifest.xml中声明.
<service android:enabled=["true" | "false"]    
    android:exported=["true" | "false"]        //是否能被其他程序组件调用或交互
    android:icon="drawable resource"
    android:isolatedProcess=["true" | "false"]
    android:label="string resource"
    android:name="string"                      //Service类名
    android:permission="string"                //权限声明
    android:process="string" >                 //设置具体的进程名称
    . . .
</service>
  • 完成Service类的继承,自定义MyService类,重写相应办法:
public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {        //绑定方法,唯一抽象方法
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService" , "in onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "in onStartCommand");
        return super.onStartCommand(intent,flags,startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyService", "in onDestroy");
    }
}

onCreate(…),onStartCommand(…),onDestroy()为Service相应生命周期阶段的回调函数. onBind(…)函数是Service基类中的唯一抽象方法,子类都必须重写实现,对于Bound Service,其返回值才具有意义。

启动和停止服务: 通过startservice() stopservice(),传递intent,开启,停止相应服务。 在service内部任一位置,通过调用stopSelf()方法停止服务。

case R.id.start_service:
     Intent startIntent  = new Intent(this,MyService.class);
     startService(startIntent);
break;
case R.id.stop_service:
     Intent stopIntent = new Intent(this,MyService.class);
     stopService(stopIntent);
break;

活动与服务进行通信(Bound Service): 通过扩展Binder类创建Bound Service的步骤如下:

  • 在Service类中,创建一个Binder实例,包含客户端能调用的公共方法,返回当前服务对象,在onBind()方法中返回Binder实例
private DownloadBinder mBinder = new DownloadBinder();

    class DownloadBinder extends 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;
   }
}
  • 自定义的ServiceConnection中实现onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例,通过获取的Binder实例进行Service端其他公共方法的调用
private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName namee) {
        }

        @Override
        public void onServiceConnected(ComponentName name,IBinder service) {
            downloadBinder = (MyService.DownloadBinder) service;   //获取实例
            downloadBinder.startDownload();                     //完成对于公共方法的调用
            downloadBinder.getProgress();
        }
    };
  • 通过bindService(intent,connection,flag)方法,实现Activity与Service的通信。 intent : 连接相应的ActivityyuService connection:已完成重写onServiceConnected()方法的ServiceConnection内部类对象。 flag:关联模式,采用BIND_AUTO_CREATE即可。
Intent bindIntent = new Intent(this,MyService.class);
       bindService(bindIntent,connection,BIND_ABOVE_CLIENT);
       break;
  • 通过调用unbindService()方法,解除绑定:
unbindService(connection);

服务的生命周期: 生命周期回调方法:

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

java多线程中注入mapper操作数据库 多线程注入service_ide

注:

  • onCreate()方法在service没有被创建的情况下,启动服务,才会被调用。
  • onStartCommand()方法在每一次调用startService()方法时,都会被执行一次,但是并不会创建新的实例。
  • 通过bindService()方法获取了持久连接,则必须调用unbindService()方法,解除绑定,才可以调用stopService()方法,结束服务。

前台服务: 由于Service的系统优先级比较低,在内存不足的情况下,可能被系统回收。为了避免被系统回收正在运行的Service,使Service可以一直保持运行状态——前台服务 前台服务将会在状态栏有一个正在运行的图标,类似于Notification效果。

实现:

  • 构建Notification对象,对其显示方式进行设置
  • PendingIntent的设置,实现对于点击意图的设置
  • 通过startForeground(Id, notification); ID为通知的Id,notification为构建的Notification对象,将Service转变为前台服务。
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);

Android多线程基础:基本与java多线程编程使用相同的语法。

  • 创建子线程:
class MyThread extends Thread{
      @Override
      public void run(){
      //耗时逻辑
      }
}
---------------------------------------------------
//使用实现Runnable接口定义线程    (耦合性高?)
class MyThread implements Runnable(){
      @Override
      public void run(){
      //耗时逻辑
      }
}
-----------------------------------------------------
//匿名类方式
new Thread (new Runnable(){
    @Override
    public void run(){
    //耗时逻辑
    }
}).start();
  • 启动线程:
new Thread().start();
----------------------------------------------------------
MyThread myThread = new MyThread();
new Thread(myThread).start;

Android的UI操作属于线程不安全,即必须在主线程中进行对于UI的操作。 使用异步消息机制,在子线程中执行耗时操作,根据任务结果更新UI。 方法一:异步消息处理:Message,Handle,MessageQueue,Looper构成,详细解释。 基础练习 方法二:AsyncTask: Android提供的轻量级的异步类,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程. 同样基于异步消息处理机制,Android进行了较好的封装。 优点:

  • 简单,快捷
  • 过程可控

缺点:

  • 在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。 AsyncTask定义了三种泛型类型 Params,Progress和Result。

  • Params: 启动任务执行的输入参数,比如HTTP请求的URL。
  • Progress: 后台任务执行的百分比。
  • Result: 后台执行任务最终返回的结果,比如String。

最少写以下这两个方法:

  • doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
  • onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。

补充方法:

  • nProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
  • onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
  • onCancelled() 用户调用取消时,要做的操作

使用AsyncTask类,以下是几条必须遵守的准则:

  • Task的实例必须在UI thread中创建;
  • execute方法必须在UI thread中调用;
  • 不可以手动调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法;
  • 该task只能被执行一次,否则多次调用时将会出现异常; AsyncTask基础练习

IntentService: 由于Serice默认运行与主线程,在处理耗时逻辑情况下,可能出现ANR情况。 可以通过多线程编程,在Service的具体方法内开启线程,在子线程中处理耗时逻辑,通过stopSelf停止。

public itn onStartCommand(Intent intent,int flags,int startId){
new Thread(new Runnable() {           //开启子线程
                @Override
                public void run() {
                    //耗时逻辑
                    stopSelf();
                }
            }).start();
        return super.onStartCommand(intent,flags,startId);
        }
}

InentService: 已由Android封装,自动开启线程,自动调用stopSelf()方法的InentService类。 IntentService通过worker thread处理每个Intent对象,执行完所有工作后自动停止Service。 实现:通过复写onHandleIntent()方法,构造。

  • 创建一个与应用程序主线程分开worker thread用来处理所有通过传递过来的Intent请求
  • 创建一个work queue,一次只传递一个intent到onHandleIntent()方法中,从而不用担心多线程带来的问题
  • 当处理完所有请求后自动停止服务,而不需要我们自己调用stopSelf()方法
  • 默认实现了onBind()方法,返回值为null
  • 默认实现了onStartCommand()方法,这个方法将会把我们的intent放到work queue中,然后在onHandleIntent()中执行
public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
    }              //耗时操作 在子线程中运行

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService", "onDestroy executed");
    }
}

使用上与一般Service没有很大差别。

服务的最佳实践: 后台执行的定时任务 (通过定时任务,实现循环)