Android中控件Service简介
安卓中服务的类型以及区别对比
1.本地服务和远端服务
2.常见的程序设计的服务类型以及代码实现
a.本地服务(以文件拷贝为例)
一.主界面Activity
package com.example.testhandler;
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;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
public TextView textview;
public Button handlerThreadBTN;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textview = (TextView) findViewById(R.id.textView1);
handlerThreadBTN = (Button) findViewById(R.id.handlerThreadBtn);
handlerThreadBTN.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//创建启动service的Intent,注意这个intent必须startService(intent)一样
Intent intent=new Intent();
//为intent设置action属性,值和AndroidManifest.xml一致,极易出现错误的intent值问题
intent.setAction("com.example.service.FIRST_SERVICE");
//启动服务
startService(intent);
}
}
二.服务
package com.example.service;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
//程序弊端:对于只读文件没办法进行复制移动,以后引用务必注意
public class FilecoyeService extends Service{
// 源文件夹
static String url1 = "/mnt/sdcard/baidu";
// 目标文件夹
static String url2 = "/mnt/sdcard2/hh";
@Override
public IBinder onBind(Intent arg0) {
return null;
}
//service创建时回调的方法
public void onCreate(){
super.onCreate();
System.out.println("service is created!");
}
//service被启动startService()时回调该方法,如果文件拷贝是耗时操作,可以在下面的方法中启动一个线程,不然会报ANR
public int onStartCommand(Intent intent,int flags,int startId){
//服务的方法体,在主线程中服务
System.out.println("onCreate CurrentThread = " + Thread.currentThread().getName());
//如果手机插入了sd卡,且应用程序具有访问sd的权限
if(Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)){
//获取SD卡的目录
File sdCardDir = Environment.getExternalStorageDirectory();
System.out.println("service is started!"+sdCardDir);
// 创建目标文件夹
(new File(url2)).mkdirs();
// 获取源文件夹当前下的文件或目录
File[] file = (new File(url1)).listFiles();
for (int i = 0; i < file.length; i++) {
if (file[i].isFile()) {
// 复制文件
try {
copyFile(file[i],new File(url2+file[i].getName()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (file[i].isDirectory()) {
// 复制目录
String sourceDir=url1+File.separator+file[i].getName();
String targetDir=url2+File.separator+file[i].getName();
try {
copyDirectiory(sourceDir, targetDir);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
System.out.println("service is completed!");
return 0;
}
// 复制文件
public static void copyFile(File sourceFile,File targetFile)
throws IOException{
// 新建文件输入流并对它进行缓冲
FileInputStream input = new FileInputStream(sourceFile);
BufferedInputStream inBuff=new BufferedInputStream(input);
// 新建文件输出流并对它进行缓冲
FileOutputStream output = new FileOutputStream(targetFile);
BufferedOutputStream outBuff=new BufferedOutputStream(output);
// 缓冲数组
byte[] b = new byte[1024 * 5];
int len;
while ((len =inBuff.read(b)) != -1) {
outBuff.write(b, 0, len);
}
// 刷新此缓冲的输出流
outBuff.flush();
//关闭流
inBuff.close();
outBuff.close();
output.close();
input.close();
}
// 复制文件夹
public static void copyDirectiory(String sourceDir, String targetDir)
throws IOException {
// 新建目标目录
(new File(targetDir)).mkdirs();
// 获取源文件夹当前下的文件或目录
File[] file = (new File(sourceDir)).listFiles();
for (int i = 0; i < file.length; i++) {
if (file[i].isFile()) {
// 源文件
File sourceFile=file[i];
// 目标文件
File targetFile=new
File(new File(targetDir).getAbsolutePath()
+File.separator+file[i].getName());
copyFile(sourceFile,targetFile);
}
if (file[i].isDirectory()) {
// 准备复制的源文件夹
String dir1=sourceDir + "/" + file[i].getName();
// 准备复制的目标文件夹
String dir2=targetDir + "/"+ file[i].getName();
copyDirectiory(dir1, dir2);
}
}
}
public void onDestroy(){
super.onDestroy();
System.out.println("service is destroyed!");
}
}
三.布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.testhanlerthread.MainActivity$PlaceholderFragment" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/handlerThreadBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:layout_marginTop="99dp"
android:text="@string/startHandlerThread" />
</RelativeLayout>
四.配置文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testhandler"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<!-- 在SD卡中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SD卡写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service android:name="com.example.service.FilecoyeService"
android:exported="false">
<intent-filter>
<action android:name="com.example.service.FIRST_SERVICE"/>
</intent-filter>
</service>
<activity
android:name="com.example.testhandler.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
b.绑定本地服务并与之通信
c.AIDL 服务
AIDL的demo链接http://blog.csdn.net/saintswordsman/article/details/5130947,比较详细的介绍了AIDL的具体实现情况。
3.服务与线程的区别
Service本身存在两个问题
1.Service不会专门启动一个单独的进程,Service与它所在的应用位于同一个进程中
2.Service也不是专门一条新的线程,两者没有任何关系, 因此不可以在Service中直接处理耗时操作,要处理耗时操作可以在其中启动一个Thread
对比服务与线程
1.服务不是单一的进程。服务没有自己的进程,应用程序可以不同,服务运行在相同的进程中。
2.服务不是线程。可以在线程中工作。
一.在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务。
同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,需需要长时间运行的情况下使用线程。
二.如果任务占用CPU时间多,资源大的情况下,要使用线程。
servie是系统的组件,它由系统进程托管(servicemanager);它们之间的通信类似于client和server,是一种轻量级的ipc通信,这种通信的载体是binder,它是在linux层交换信息的一种ipc。而thread是由本应用程序托管。
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。