android 自定义服务 (GpsService)

   通过本例子说明如何搭建自定义的应用层服务。

   本例子建立了一个模拟的Gps应用服务,通过监听串口设备获取GPS数据(非阻塞),获取到有效的数据后通过handler通知UI线程刷新,以下给出源码

  GpsDevice.java

package com.example.gpsservice;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.location.Location;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class GpsDevice {

	/*****************************************************************************************************************/
	private final String TAG = "GpsDevice";
	private final int GPS_Device_SERIAL_GPS_READABLE = 0x1000;
	
	private int 						fd = -1;
	private FileDescriptor   			mFd = null;
	private FileInputStream  			mFileInputStream  = null;
	private FileOutputStream 			mFileOutputStream = null;
	
	private GpsLocationChangedListener 	mGpsListener;
	private Location 					mLastLocation;
	private Location 					mLocation;
	
	private GpsDeviceListenerHandler 	mHandler;
	private GpsDeviceMonitorThread   	mMonitorThread;
	/*****************************************************************************************************************/
	static {
		System.loadLibrary("GpsDevice");
	}
	/*****************************************************************************************************************/
	public GpsDevice() throws IOException
	{
		// 打开模拟GPS设备,串口
		fd = openSerialPort("/dev/ttyUSB2"); 
		if( fd == -1 ) 
		{	
			throw new IOException();
		}

		// 设置串口属性为115200 8 N 1
		if( setSerialPort(fd, 115200, 8, 0 , 1, 0 ) < 0 )
			throw new IOException();
		
		// 转换fd为输入输出流
		FileDescriptor mFd = convertFileDescriptor(fd);
		mFileInputStream   = new FileInputStream(mFd);
		mFileOutputStream  = new FileOutputStream(mFd);
		
		// 启动handler 用于处理listener, 确保listener工作在UI主线程,否则刷新UI会报错
		mHandler           = new GpsDeviceListenerHandler();
		
		// 开启监听端口线程
		mMonitorThread     = new GpsDeviceMonitorThread();
		
		mLastLocation      = new Location("");
		mLocation          = new Location("");
		
		// 将fd加入可读监听队列
		Selector.clearAllSets();
		Selector.addReadSet(fd);
	}
	
	protected void finalize()
	{
		mMonitorThread.stop();
		closeSerialPort(fd);
	}
	
	public void setGpsLocationChangedListener(GpsLocationChangedListener listener)
	{
		mGpsListener = listener;
	}
	
	public void run()
	{
		mMonitorThread.start();
	}
	
	public void checkLocationChanged()
	{
		if( mLocation.getLatitude() != mLastLocation.getLatitude() || mLocation.getLongitude() != mLastLocation.getLongitude())
		{
			if( mGpsListener != null ) mGpsListener.onGpsLocationChanged(mLocation);
			
			mLastLocation.setLatitude(mLocation.getLatitude());
			mLastLocation.setLongitude(mLocation.getLongitude());
		}
	}
	
	public void getLocation()
	{
		byte[] buffer = new byte[512];
		int size = 0;
		
		try {
			size = mFileInputStream.read(buffer);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// 解析串口协议数据,本例中为自定义数据,可以根据自己的协议修改
		int a = buffer[0] & 0xFF;
		int b = buffer[1] & 0xFF;
		if( a == 0x5A && b == 0xBB && size == 17 )
		{
			int n1, n2, n3, n4;
			n1 = buffer[9] & 0xFF;
			n2 = buffer[8] & 0xFF;
			n3 = buffer[7] & 0xFF;
			n4 = buffer[6] & 0xFF;
			double latitude   = n1 << 24  | n2 << 16 | n3 << 8 | n4;
			
			n1 = buffer[13] & 0xFF;
			n2 = buffer[12] & 0xFF;
			n3 = buffer[11] & 0xFF;
			n4 = buffer[10] & 0xFF;
			double longitude  = n1 << 24  | n2 << 16 | n3 << 8 | n4;
			
			mLocation.setLatitude(latitude/1000000);
			mLocation.setLongitude(longitude/1000000);
			
			Log.d(TAG, "latitude : " + mLocation.getLatitude() + ",longitude = " + mLocation.getLongitude());
		}
	}
	/*****************************************************************************************************************/
	// CLASS
	private class GpsDeviceMonitorThread extends Thread{
		public void run()
		{	
			while (!isInterrupted())
			{
				if( Selector.runSelector(100) > 0 )
				{
					Message message = new Message();   
					
					if( Selector.isReadable(fd))
					{
						getLocation();
						message.what = GPS_Device_SERIAL_GPS_READABLE;
						mHandler.sendMessage(message);
					}
				}
				else
				{
					Log.d(TAG, "select time out");
				}
			}
		}
	}

	private class GpsDeviceListenerHandler extends Handler
	{
		public void handleMessage(Message msg) 
		{   
            switch (msg.what) 
            {   
            case GPS_Device_SERIAL_GPS_READABLE:
            	checkLocationChanged();
            	break;
            default:
            	break;
            }   
            super.handleMessage(msg);   
		}   
	}
	
	/*****************************************************************************************************************/
	// INTERFACE
	public interface GpsLocationChangedListener
	{
		public void onGpsLocationChanged(Location location);
	}
	/*****************************************************************************************************************/
	//JNI
	private native int openSerialPort(String device);
	private native FileDescriptor convertFileDescriptor(int fd);

	//@param[in] baudrate  2400, 4800, 9600, 9600, 19200, 38400, 57600, 115200
	//@param[in] databit   5, 6, 7, 8
	//@param[in] fctl      flow control, 0: none, 1: hardware, 2: software
	//@param[in] stopbit   1, 2
	//@param[in] parity    0: none, 1: odd, 2: even
	private native int setSerialPort(int fd, int baudrate, int databit, int fctl, int stopbit, int parity);

	private native int closeSerialPort(int fd);

	
}


为了实现非阻塞的读取设备,本例采用了select轮训方式查看设备是否可读,便于扩展成多设备,多服务

Selector.java

package com.example.gpsservice;

// Linux Select 函数的简单封装
public class Selector {
	static {
		System.loadLibrary("Selector");
	}
	
	public static void clearAllSets()
	{
		ClearAllSets();
	}
	
	public static void clearReadSets()
	{
		ClearReadSets();
	}
	
	public static void clearWriteSets()
	{
		ClearWriteSets();
	}
	
	public static void addReadSet(int fd)
	{
		AddReadSet(fd);
	}
	
	public static void addWriteSet(int fd)
	{
		AddWriteSet(fd);
	}
	
	public static void removeReadSet(int fd)
	{
		RemoveReadSet(fd);
	}
	
	public static void removeWriteSet(int fd)
	{
		RemoveWriteSet(fd);
	}
	
	public static boolean isReadable(int fd)
	{
		return IsReadSet(fd) > 0;
	}
	
	public static boolean isWritable(int fd)
	{
		return IsWriteSet(fd) > 0;
	}
	
	// -1 : error  0 : timeout  1 : readable or writable
	public static int runSelector(int timeout)
	{
		return DoSelect(timeout);
	}
	
	// JNI
	private static native void ClearAllSets();
	private static native void ClearReadSets();
	private static native void ClearWriteSets();
	private static native void AddReadSet(int fd);
	private static native void AddWriteSet(int fd);
	private static native void RemoveReadSet(int fd);
	private static native void RemoveWriteSet(int fd);
	private static native int  IsReadSet(int fd);
	private static native int  IsWriteSet(int fd);
	private static native int  DoSelect(int timeout);
}



最后通过UI简单测试,拿到有效的GPS数据后,通过TextView显示出来

GpsService.java

package com.example.gpsservice;

import java.io.IOException;

import android.app.Activity;
import android.location.Location;
import android.os.Bundle;
import android.view.Menu;
import android.widget.TextView;

import com.example.gpsservice.GpsDevice.GpsLocationChangedListener;

public class GpsService extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gps_service);
        
        try {
			GpsDevice gpsDevice = new GpsDevice();
			gpsDevice.setGpsLocationChangedListener(new GpsLocationChangedListener(){
				@Override
				public void onGpsLocationChanged(Location location) {
					// TODO Auto-generated method stub
					updateGpsLocation(location);
				}});
			gpsDevice.run();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_gps_service, menu);
        return true;
    }
    
    public void updateGpsLocation(Location locaction)
    {
    	if( locaction == null ) return;
    	
    	((TextView)findViewById(R.id.TextView_GpsInfo)).setText("N:" + locaction.getLatitude() + ",E:" + locaction.getLongitude());
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值