小猪的Android入门之路 Day 9 part 1

小猪的Android入门之路 Day 9 part 1

Android四大组件之——Service浅析

——转账请注明出处:coder-pig

本节引言:

在前面的学习中我们已经把安卓四个基本组件中的两个:

Actvity(活动)和BroadCastReceiver过了一遍,而在Day 9中我们会对第三个组件Service进行

解析,两种类型的Service,Service的生命周期,如何去使用Service,声明Service,调用,停止Service;

跨进程调用AIDL,以及常用的系统服务的使用!好了,引言就说到这里,接着开始本节的内容!

本节学习路线图:

正文:

Service简介与生命周期图解析:

代码验证生命周期图:

1.验证StartService启动Service的调用顺序:

首先我们自定义一个Service,重写相关的方法,用户在logcat上打印验证:

TestService1.java

package com.jay.example.servicetestdemo1;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class TestService1 extends Service {

	private final String TAG = "TestService1";
	//必须要实现的方法
	@Override
	public IBinder onBind(Intent intent) {
		Log.i(TAG, "onBind方法被调用!");
		return null;
	}

	//Service被创建时调用
	@Override
	public void onCreate() {
		Log.i(TAG, "onCreate方法被调用!");
		super.onCreate();
	}

	//Service被启动时调用
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i(TAG, "onStartCommand方法被调用!");
		return super.onStartCommand(intent, flags, startId);
	}

	//Service被关闭之前回调
	@Override
	public void onDestroy() {
		Log.i(TAG, "onDestory方法被调用!");
		super.onDestroy();
	}
}

接着在AndroidManifest.xml完成Service组件的注册:

<!-- 配置Service组件,同时配置一个action -->
        <service android:name=".TestService1">
            <intent-filter>
                <action android:name="com.jay.example.service.TEST_SERVICE1"/>
            </intent-filter>
</service>

再接着是简单的布局文件,两个按钮,再最后是MainActivity的编写,在按钮的点击事件中分别

调用startService( )和stopService( )!

package com.jay.example.servicetestdemo1;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	private Button start;
	private Button stop;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		start = (Button) findViewById(R.id.btnstart);
		stop = (Button) findViewById(R.id.btnstop);

		//创建启动Service的Intent,以及Intent属性
		final Intent intent = new Intent();
		intent.setAction("com.jay.example.service.TEST_SERVICE1");
		//为两个按钮设置点击事件,分别是启动与停止service
		start.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				startService(intent);
			}
		});

		stop.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				stopService(intent);

			}
		});

	}
}

运行截图:

点击开始服务:

吃饱饭没事做,点多几下:

最后点击停止服务:

从上面的运行结果我们可以验证我们生命周期图中解释的内容:

我们发现onBind()方法并没有被调用,另外多次点击启动Service,只会重复地调用

onStartCommand方法!无论我们启动多少次Service,一个stopService就会停止

Service!

2.验证BindService启动Service的顺序:

在开始讲写代码之前,我们先要来了解一些东西先:

首先是第一个大图下面给出的Context的bindService方法

①ServiceConnection对象:监听访问者与Service间的连接情况,如果成功连接,回调

onServiceConnected(),如果异常终止或者其他原因终止导致Service与访问者断开

连接则回调onServiceDisconnected方法,调用unBindService()不会调用该方法!

②onServiceConnected方法中有一个IBinder对象,该对象即可实现与被绑定Service

之间的通信!我们再开发Service类时,默认需要实现IBinder onBind()方法,该方法返回的

IBinder对象会传到ServiceConnection对象中的onServiceConnected的参数,我们就可以

在这里通过这个IBinder与Service进行通信!

总结:

step 1:在自定义的Service中继承Binder,实现自己的IBinder对象

step 2:通过onBind( )方法返回自己的IBinder对象

step 3:在绑定该Service的类中定义一个ServiceConnection对象,重写两个方法,

onServiceConnected和onDisconnected!然后直接读取IBinder传递过来的参数即可!

那么好了,接下来就是写代码验证了,这里的话我们定义一个用来计时的Service,

然后来演示BindService的用法以及方法调用流程!代码比较简单,不解释了!

TestService2.java:

package com.jay.example.servicetestdemo2;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class TestService2 extends Service {

	private final String TAG = "TestService2";
	private int count;
	private boolean quit;

	//定义onBinder方法所返回的对象
	private MyBinder binder = new MyBinder();
	public class MyBinder extends Binder
	{
		public int getCount()
		{
			return count;
		}
	}

	//必须实现的方法,绑定改Service时回调该方法
	@Override
	public IBinder onBind(Intent intent) {
		Log.i(TAG, "onBind方法被调用!");
		return binder;
	}

	//Service被创建时回调
	@Override
	public void onCreate() {
		super.onCreate();
		Log.i(TAG, "onCreate方法被调用!");
		//创建一个线程动态地修改count的值
		new Thread()
		{
			public void run()
			{
				while(!quit)
				{
					try
					{
						Thread.sleep(1000);
					}catch(InterruptedException e){e.printStackTrace();}
					count++;
				}
			};
		}.start();

	}

	//Service断开连接时回调
	@Override
	public boolean onUnbind(Intent intent) {
		Log.i(TAG, "onUnbind方法被调用!");
		return true;
	}

	//Service被关闭前回调
	@Override
	public void onDestroy() {
		super.onDestroy();
		this.quit = true;
		Log.i(TAG, "onDestroyed方法被调用!");
	}

	@Override
	public void onRebind(Intent intent) {
		Log.i(TAG, "onRebind方法被调用!");
		super.onRebind(intent);
	}

}

需要在AndroidManifest.xml中对Service组件进行注册:

<service android:name=".TestService2" android:exported="false">
            <intent-filter>
                <action android:name="com.jay.example.service.TEST_SERVICE2"/>
            </intent-filter>
 </service>

MainActivity.java

package com.jay.example.servicetestdemo2;

import com.jay.example.servicetestdemo2.TestService2.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.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

	private Button btnbind;
	private Button btncancel;
	private Button btnstatus;

	//保持所启动的Service的IBinder对象,同时定义一个ServiceConnection对象
	TestService2.MyBinder binder;
	private ServiceConnection conn = new ServiceConnection() {

		//Activity与Service断开连接时回调该方法
		@Override
		public void onServiceDisconnected(ComponentName name) {
			System.out.println("------Service DisConnected-------");
		}

		//Activity与Service连接成功时回调该方法
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			System.out.println("------Service Connected-------");
			binder = (TestService2.MyBinder) service;
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btnbind = (Button) findViewById(R.id.btnbind);
		btncancel = (Button) findViewById(R.id.btncancel);
		btnstatus  = (Button) findViewById(R.id.btnstatus);

		final Intent intent = new Intent();
		intent.setAction("com.jay.example.service.TEST_SERVICE2");

		btnbind.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				//绑定service
				bindService(intent, conn, Service.BIND_AUTO_CREATE);
			}
		});

		btncancel.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				//解除service绑定
				unbindService(conn);
			}
		});

		btnstatus.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(getApplicationContext(), "Service的count的值为:"
						+ binder.getCount(), Toast.LENGTH_SHORT).show();

			}
		});
	}
}

运行截图:

点击锁定Service:

继续点击锁定:没任何变化

获取当前Service的状态:

解除绑定:

如果我们再绑定后直接关掉Activity的话会报错,

然后会自动调用onUnbind和onDestory方法!

。。。

从上面的运行结果验证了生命周期图中的:

使用BindService绑定Service,依次调用onCreate(),onBind()方法,我们可以在onBind()方法中

返回自定义的IBinder对象;再接着调用的是ServiceConnectiononServiceConnected()方法

该方法中可以获得IBinder对象,从而进行相关操作;当Service解除绑定后会自动调用onUnbind

onDestroyed方法,当然绑定多客户端情况需要解除所有的绑定才会调用onDestoryed方法进行销毁哦!

IntentService的使用:

上面已经学习了Service的用法,现在我们已经知道如何去定义和启动自己的Service了!

但是从上面的bindService的例子中,发现了一个问题,就是我们直接把耗时线程放在了

Service中的onStart( )方法中,网上很多都是直接这样做!但是这样容易引发ANR异常

(Application Not Responding),而Android的官方是这样介绍Service的:

1.A Service is not a separate process. The Service object itself does not imply it is running

 in its own process; unless otherwise specified, it runs in the same process as the application it is part of.

2.A Service is not a thread. It is not a means itself to do work off of the main thread

 (to avoid Application Not Responding errors).

直接翻译就是:

1.Service不是一个单独的进程,它和它的应用程序在同一个进程中

2.Service不是一个线程,这样就意味着我们应该避免在Service中进行耗时操作

于是乎肯定是有替代Service的东西啦,那就是我们要讲的IntentService

IntentService是继承与Service并处理异步请求的一个类,在IntentService中有

一个工作线程来处理耗时操作,请求的Intent记录会加入队列

工作流程:

客户端通过startService(Intent)来启动IntentService;

我们并不需要手动地区控制IntentService,当任务执行完后,IntentService会自动停止;

可以启动IntentService多次,每个耗时操作会以工作队列的方式在IntentService的

onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完一,再到二这样!

总结使用IntentService的原因:

1)无需在Service中手动地去开辟线程

2)无需手动停止Service,当操作完成时,Service会自动停止

3)简单的使用方式

再接着是代码演示,网上大部分的代码都是比较Service与IntentService的,定义足够长的

休眠时间,演示Service的ANR异常,然后引出IntentService有多好!

这里就不演示Service了,网上的都是自定义Service,然后在onStart()方法中Thread.sleep(20000)

然后引发ANR异常,有兴趣的可以自己写代码试试,这里的话只演示下IntentService的用法

首先自定义一个Service,继承IntentService,重写核心方法onHandleIntent,在这里完成耗时操作

接着重写其他方法,添加log.i用于查看方法的调用顺序!

TestService3.java

package com.com.example.testservice3;

import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class TestService3 extends IntentService {

	private final String TAG = "hehe";

	//必须实现父类的构造方法
	public TestService3()
	{
		super("TestService3");
	}

	//必须重写的核心方法
	@Override
	protected void onHandleIntent(Intent intent) {
		//Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务
		String action = intent.getExtras().getString("param");
		if(action.equals("s1"))Log.i(TAG,"启动service1");
		else if(action.equals("s2"))Log.i(TAG,"启动service2");
		else if(action.equals("s3"))Log.i(TAG,"启动service3");

		//让服务休眠2秒
		try{
			Thread.sleep(2000);
		}catch(InterruptedException e){e.printStackTrace();}
	}

	//重写其他方法,用于查看方法的调用顺序
	@Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"onBind");
        return super.onBind(intent);
    }

    @Override
    public void onCreate() {
        Log.i(TAG,"onCreate");
        super.onCreate();
    }

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

    @Override
    public void setIntentRedelivery(boolean enabled) {
        super.setIntentRedelivery(enabled);
        Log.i(TAG,"setIntentRedelivery");
    }

    @Override
    public void onDestroy() {
        Log.i(TAG,"onDestroy");
        super.onDestroy();
    }

}

接着记得到AndroidManifest中注册小Service组件哦,不然Service是没响应的哦!

        <service android:name=".TestService3" android:exported="false">
            <intent-filter >
                <action android:name="com.test.intentservice"/>
            </intent-filter>
        </service>

最后在MainActivity中启动三次服务

package com.com.example.testservice3;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Intent it1 = new Intent("com.test.intentservice");
		Bundle b1 = new Bundle();
		b1.putString("param", "s1");
		it1.putExtras(b1);

		Intent it2 = new Intent("com.test.intentservice");
		Bundle b2 = new Bundle();
		b2.putString("param", "s2");
		it2.putExtras(b2);

		Intent it3 = new Intent("com.test.intentservice");
		Bundle b3 = new Bundle();
		b3.putString("param", "s3");
		it3.putExtras(b3);

		//接着启动多次IntentService,每次启动,都会新建一个工作线程
		//但始终只有一个IntentService实例
		startService(it1);
		startService(it2);
		startService(it3);

	}
}

然后看下运行的截图:

好了,最后总结下,当一个后台的任务,需要分成几个子任务,然后按先后顺序执行,子任务

(简单的说就是异步操作),此时如果我们还是定义一个普通Service然后在onStart方法中

开辟线程,然后又要去控制线程,这样显得非常的繁琐;

此时应该自定义一个IntentService然后再onHandleIntent()方法中完成相关任务!

本节参考代码下载:

1)验证StartService生命周期:点击下载

2)验证BindService生命周期:点击下载

3)IntentService的简单使用:点击下载

时间: 2024-10-09 12:03:19

小猪的Android入门之路 Day 9 part 1的相关文章

小猪的Android入门之路 Day 8 part 2

小猪的Android入门之路 Day 8 part 2 Android网络编程浅析--Android访问网络资源 --转载请注明出处:coder-pig 本节引言: 在part 1中我们学习了网络交互中用得较多的xml文件的相关概念,以及在Android中常用的 解析XML三种不同形式,分别SAX,DOM,Pull三种不同的解析方式;而在part 2中我们将会 讲解我们的应用如何去获取网络上的资源,分别是图片,HTML代码,XML代码和JSON数据; 好了,废话就这么多,开始本节的课程吧!从这p

小猪的Android入门之路 Day 8 part 4

小猪的Android入门之路 Day 8 part 4 Android网络编程浅析--Android网络数据的上传 --转载请注明出处:coder-pig 本节引言: 在part 3中我们已经学习了Android网络数据的下载,难点是多线程断点续传下载; 有下载,当然也有上传啦,本节就来研究下Android中的网络数据的上传! 1.使用GET或者Post方式上传数据给服务器 2.使用开源框架HttpClient上传数据到服务区 3.发送xml数据给服务器 4.通过Http协议上传文件 5.Web

小猪的Android入门之路 Day 4 - part 4

小猪的Android入门之路 Day 4 - part 4 Android事件处理机制之--事件处理机制拾遗 ------------转载请注明出处--coder-pig 本节引言: 在前面三个部分中,对于android的事件处理机制的学习已经学得七七八八了, 基于监听与回调的时间处理机制,以及使用Handler传递信息的机制都已经学了; 在最后这个部分中会对一些小的知识点进行补充,比如触摸事件的两种形式, Configuration类以及异步任务AsyncTask进行讲解,好了,开始本节的课程

小猪的Android入门之路 Day 3 - part 1

小猪的Android入门之路 Day 2 各种UI组件的学习 Part 1 本节引言: 在上一节中,我们初次体验了Android开发的一个流程,开发了一个简单的电话拨号器; 然后又学习了android的六大布局,界面无非是由布局 + 控件构成;布局都学了,剩下的 当然是控件啦,不过Android 所提供的UI组件还是比较丰富的;我们不求掌握他们的全部 用法,只需要了解一些基本的用法,等需要时再查资料就可以了!当然,内容是以android UI 组件实例大全为依托的,因为内容较多,所以需要分成几个

小猪的Android入门之路 Day 7 part 4

小猪的Android入门之路 Day 7 part 4 Android的数据存储与访问之--ContentProvider(内容提供者)                                   ---转载请注明出处:coder-pig 本节引言: 在前面的学习中,我们已经学习了一些存储数据的方式,而这些都是可以共享的,比如文件,我们可以把操作 模式设置为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE,其他应用 就可以

小猪的Android入门之路 Day 5 - part 1

小猪的Android入门之路 Day 5 - part 1 基本程序单元:Activity(活动) ------------转载请注明出处--coder-pig 本节引言: 经过前面的学习,我们已经可以开发出一个自定义简单UI界面以及具有简单逻辑业务的App了, 不过都是在一个界面上完成的,而现在大部分的app都是拥有多个界面的,所以我们有必要继续深入地 学习,而这些所谓的界面,窗口,在Android我们把他们叫做Activity(活动),他也是Android四大组件的其中 一个,是基本的程序单

小猪的Android入门之路 Day 4 - part 3

小猪的Android入门之路 Day 4 - part 3 Android事件处理机制之--Handler消息传递机制 ------------转载请注明出处--coder-pig 本节引言: 在前面两个部分中,我们对于android的两种事件处理机制:监听与回调进行了深入的学习; 貌似就学完android的事件处理机制了,其实这两个仅仅是发生了触摸啊之类做出的事件响应; 而今天这一Part要讲的是修改Activity中的UI组件时发生一些信息传递;相信大家都知道,我们只能够 主线程中去修改Ac

小猪的Android入门之路 Day 4 - part 1

小猪的Android入门之路 Day 4 - part 1 Android事件处理机制之--基于监听的事件处理机制 本节引言: 在开始本个章节前,我们先回顾下,现在我们已经知道了android的一些相关背景,一些常用的UI组件, 六大布局,现在的我们已经可以做出一个简单的app界面了,下一步就是逻辑与业务的实现了;在前面 的例子中我们曾经看到过setXXXListener这些东东,这个就是android 的事件处理,而这个方法是基于监听的 Android为我们提供了两套功能强大的事件处理机制:

小猪的Android入门之路 Day 6

小猪的Android入门之路 Day 6 Android应用核心:Intent(意图) -----转载请注明出处:coder-pig 本节引言: 通过前面的学习中,我们都知道可以调用startActivity(intent)或者startActivityForResult(intent) 来启动一个新的Activity了,他们的参数都是Intent类型的实例,那么这个Intent是什么东西呢? 有什么用?还有一个问题,相信细心的朋友都发现AndroidManifest.xml的activity标

小猪的Android入门之路 day 1

小猪的Android入门之路 Day 1 Android相关背景与开发环境的搭建 ------转载请注明出处:coder-pig 本节引言: 随着社会经济的发展,移动互联网的越来越热,手机APP开发显得格外火爆, 作为一名快要毕业的IT屌丝,自然要趟一趟这一浑水啦,当前主流的手机系统 IOS(苹果),Android(安卓),WinPhone(windows);WindPhone貌似没什么崛起的势头; 所以主流的就是前面的两个;作为一名屌丝学生狗,买不起Mac,仅仅有一台双核的破电脑; 仅仅能去搞