Android之Service复习深入

       一个服务是一个应用程序组合,在后台运行,可以执行一个长时间的操作,但是并不提供用户界面。

      应用程序终止,Service也不会终止。。。。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。。 Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
 service的两种模式(startService()/bindService()不是完全分离的):
本地服务 Local Service 用于应用程序内部。

      它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服。用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
      远程服务 Remote Service 用于android系统内部的应用程序之间。
      它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
两种Service方式启动服务的主要区别
1、startService()方式启动。
     使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
      如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法(在2.0之后已经改变onStartCommond()方法)。
      如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。或者自己停止。
      2、bindService()方式启动;(异步)
调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用
     采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法

Service生命周期:(如图,不做介绍)


拥有service的进程具有较高的优先级
      官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级
      1、如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
      2、如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
      3、如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
      4、如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
分析onStartCommand方法参数的作用和返回值的作用:
      1、根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,(当进行被杀死的时候,是否重新启动。如果是参数:START_REDELIVER_INTENT表示当服务所在进程被杀死后,重新启动,并且重新传递Intent内容,其它两个参数不会重新传递intent,都为null)
      2、返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
      3、是当前服务的标记
      4、第三个参数startId表示当前启动的Service的次数。

下面看一下测试源码:

HelloSerivce.java

public class HelloService extends Service {
	Handler handler = new Handler();
	private final IBinder mBinder = new HelloBinder();
	@Override
	public void onCreate() {
		Log.v("verbose", "onCreate");
		super.onCreate();
	}

	/**
	 * 用这种方式 ,从Activity启动服务之后,在后台运行的,之后就没有与Activity联系了 如果有bind方法
	 * ,在整个过程中与Activity进行通信
	 * 
	 * 根据这个方法的返回值不同可以有两种启动模式START_NOT_STICKY,START_STICKY,
	 * START_REDELIVER_INTENT服务被系统杀死后是否自动重启,和是否重新传递intent。
	 * 如果被杀死之后重新启动服务,会重新调用onCreate,和onStartCommand方法
	 * ,但是重新调用onStartCommand的时候,不会再次传递参数。。
	 * 返回START_REDELIVER_INTENT的时候,如果不论启动多少次,当重新启动的时候,也会启动多少次。
	 */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.v("verbose", "onStartComand");
		handler.post(new Runnable() {// 用通常用Handler线程跟UI线程打交到
					@Override
					public void run() {
						Toast.makeText(getApplicationContext(), "启动服务",
								Toast.LENGTH_LONG).show();

					}
				});
		// return super.onStartCommand(intent, flags, startId);
		return START_REDELIVER_INTENT;
	}

	@Override
	public void onDestroy() {
		Log.v("verbose", "onDestory");
		handler.post(new Runnable() {// 用通常用Handler线程跟UI线程打交到
					@Override
					public void run() {
						Toast.makeText(getApplicationContext(), "停止服务",
								Toast.LENGTH_LONG).show();
					}
				});
		super.onDestroy();
	}

	
	/**
	 * 这个方法是必须执行的,当用bind方法启动Service的时候,是有用的。
	 */
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return mBinder;
	}

	/**
	 * Class used for the client Binder. Because we know this service always
	 * runs in the same process as its clients, we don't need to deal with IPC.
	 */
	public class HelloBinder extends Binder {
		HelloService getService() {
			return HelloService.this;
		}
	}
	
	public void showNumber(){
		new Thread(new Runnable() {
			int i=1;
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(i++);
				}
			}
		}).start();
	}
}

HelloServiceActivity.java

package hb.android.service;

import hb.android.service.HelloService.HelloBinder;
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.TextView;

public class HelloServiceActivity extends Activity {
	Intent intent;
	boolean flag = true;
	HelloService mService;;
	boolean mBound = false;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		intent = new Intent();
		initMyWidget();
		setMyWidgetListener();
	}

	public void setMyWidgetListener() {
		MyWidget.btn_bind.setOnClickListener(new WidgetOnClickListener());
		MyWidget.btn_start.setOnClickListener(new WidgetOnClickListener());
		MyWidget.btn_stop.setOnClickListener(new WidgetOnClickListener());
		MyWidget.btn_unbind.setOnClickListener(new WidgetOnClickListener());
		MyWidget.btn_kill.setOnClickListener(new WidgetOnClickListener());
	}

	class WidgetOnClickListener implements OnClickListener {

		@Override
		public void onClick(View v) {
			switch (v.getId()) {
			case R.id.btn_start:
				intent.setClass(getApplicationContext(), HelloService.class);
				intent.putExtra("test", "start");
				startService(intent);
				flag = true;
				MyWidget.btn_stop.setEnabled(flag);
				break;
			case R.id.btn_stop:
				intent.putExtra("test", "stop");
				stopService(intent);
				flag = false;
				MyWidget.btn_stop.setEnabled(flag);
				break;
			case R.id.btn_kill:
				android.os.Process.killProcess(android.os.Process.myPid());
				break;
			case R.id.btn_bind:
				Intent intent = new Intent(getApplicationContext(), HelloService.class);
		        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);//自动调用Service里的onCreate方法
		        System.out.println("bind:"+mService);
		        opeService();
				break;
			case R.id.btn_unbind:
				if (mBound) {
		            unbindService(mConnection);//自动调用Service的onDestory方法
		            mBound = false;
		        }
				break;
			default:
				break;
			}
		}

		public void opeService() {
			System.out.println("opeService:"+mService);
//			mService.showNumber();
		}
	}

	public void initMyWidget() {
		MyWidget.btn_bind = (Button) findViewById(R.id.btn_bind);
		MyWidget.btn_start = (Button) findViewById(R.id.btn_start);
		MyWidget.btn_stop = (Button) findViewById(R.id.btn_stop);
		MyWidget.btn_unbind = (Button) findViewById(R.id.btn_unbind);
		MyWidget.tv_test = (TextView) findViewById(R.id.tv_test);
		MyWidget.btn_kill = (Button) findViewById(R.id.btn_kill);
	}

	private static class MyWidget {
		static Button btn_start;
		static Button btn_stop;
		static Button btn_bind;
		static Button btn_unbind;
		static Button btn_kill;
		@SuppressWarnings("unused")
		static TextView tv_test;
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		stopService(intent);
	}
	
	 /** Defines callbacks for service binding, passed to bindService() */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            HelloBinder binder = (HelloBinder) service;
            mService = binder.getService();
            System.out.println("ServiceConnection:"+mService);
            mBound = true;
            mService.showNumber();
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
    @Override
    protected void onStop() {
    	super.onStop();
    	if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    };
}


注意:当服务创建之后由,onServiceConnected 这个方法负责建立与Servicer的连接

意思当Activit用BindService启动服务之后,由:

 public ServiceConnection mConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			System.out.println("onServiceConnected");
			mBound = false;
		}
		/**
		 * 服务创建之后收些方法建立Serivce与Activity的连接
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			System.out.println("onServiceDisconnected");
			mBound = true;
			LocalBinder myBinder = (LocalBinder) service;
			myService = myBinder.getService(); //在下面就可以对service进行操作了。
			myService.showNumber();
		}
	};

对所绑定的Service进行控制(连接与销毁)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT人.阿标

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值