【Service】使用有道翻译API构建翻译服务

原创
2013/01/07 15:44
阅读数 1.1K

声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) 

http://my.oschina.net/ryanhoo/blog/100589

        今天我们来学习使用现有的服务构建应用的功能模块——利用有道的翻译API构建一个小的翻译程序。之前曾想用Google的翻译API来实现,后来发现这项服务是收费的,所以用有道的,免费才是王道。

        先来看看效果

    功能相当简单,主要提供英汉互译(其实参数无需传入语言,有道翻译机器人会自动识别)。

    实现步骤如下:

  • 申请有道翻译API的key并阅读文档
  • 新建Android项目,编写远程调用服务AIDL
  • 实现服务并供程序调用
  • 实现UI

    申请有道翻译API KEY

    请在这个页面填写必要信息,并记录返回的Key和keyfrom,调用有道的翻译服务将需要使用它。

    在申请到Key以后,请花几分钟时间简短的浏览下有道API调用的文档,就在申请页的下面。

    请求接口非常简单:

http://fanyi.youdao.com/openapi.do?keyfrom=<keyfrom>&key=<key>&type=data&doctype=<doctype>&version=1.1&q=要翻译的文本

    唯一在变动的参数是翻译文本,这让我们定义AIDL变得非常容易。

    编写AIDL远程服务调用接口

    新建ITranslateService.aidl,定义一个简单的接口,只需传入一个参数——待翻译文本。

package com.iedgeco.ryan.translate.service;

interface ITranslate{
	String traslate(in String text);
}
    实现服务

public class TranslateService extends Service {

	public static final String TAG = "TranslateService";
	
	//binder
	private final ITranslate.Stub mBinder = new ITranslate.Stub() {
		@Override
		public String traslate(String text) throws RemoteException {
			
			try {
				return Translator.translate(text);
			} catch (Exception e) {
				Log.e(TAG, "Failed to translate", e);
				return null;
			}
		}
	};
	
	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

}
    在AIDL所在的包下实现一个Service类 TranslateService ,实现相当的简单。因为是远程调用服务而非本地服务,后期需要使用bindService,因此我们必须返回IBinder实例。这里的IBinder中具体的翻译操作,我交给一个工具类 Translator 的静态方法完成,只需传入待翻译文本即可。
public class Translator {

	private static final String TAG = "Translator";

	private static final String ENCODING = "UTF-8";

	/**
	 * <pre>
	 * 请求标准: http://fanyi.youdao.com/openapi.do?
	 * 		keyfrom=<keyfrom>&
	 * 		key=<key>&
	 * 		type=data&
	 * 		doctype=<doctype>&
	 * 		version=1.1&
	 * 		q=要翻译的文本
	 * 版本:1.1,请求方式:get,编码方式:utf-8
	 * 主要功能:
	 * 		中英互译,同时获得有道翻译结果和有道词典结果(可能没有)
	 * 参数说明:
	 * 		type - 返回结果的类型,固定为data 
	 * 		doctype - 返回结果的数据格式,xml或json或jsonp
	 * 		version - 版本,当前最新版本为1.1 
	 * 		q - 要翻译的文本,不能超过200个字符,需要使用utf-8编码
	 * 	errorCode:  
	 * 		0 - 正常  
	 * 		20 - 要翻译的文本过长  
	 * 		30 - 无法进行有效的翻译  
	 * 		40 - 不支持的语言类型  
	 * 		50 - 无效的key
	 * </pre>
	 * @throws IOException 
	 * @throws ClientProtocolException 
	 * */
	public static String translate(String text) throws Exception {
		String url = "http://fanyi.youdao.com/openapi.do?keyfrom=" + StaticDef.KEY_FROM
				+ "&key=" + StaticDef.KEY_FOR_TRANSLATE
				+ "&type=data"
				+ "&doctype=json"
				+ "&version=1.1"
				+ "&q=" + text;
		try{
			HttpClient client = new DefaultHttpClient();
			HttpGet httpGet = new HttpGet(url);
			HttpResponse response = client.execute(httpGet);
			InputStream is = response.getEntity().getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(is, ENCODING));
			StringBuffer result = new StringBuffer();
			String string = null;
			if(null != (string = reader.readLine()))
				result.append(string).append('\n');
			//TODO parse the response json string
			String translation = (String) new JSONObject(result.toString())
				.getJSONArray("translation").get(0);
			
			Log.i(TAG, "result: " + result.toString());
			return translation;
		}finally{
			//close stream here
		}
	}
}

    实现UI并调用翻译服务

    UI相对简单,具体的布局请见Github中的代码,后面我会给出地址。

    MainActivity中的方法也比较简单,在onCreate中启用服务(doBindService),在onDestory中解除绑定,销毁服务(doUnBindService),可以使用doTranslate进行后台翻译(由于服务是直接运行在Main线程上的,我开启了一个异步线程来完成这个工作,并将结果反馈给Handler,由它来更新UI)。

    doBindService

private void doBindService(){
	Intent service = new Intent(StaticDef.ACTION_TRANALATE);
	bindService(service, serviceConn, Context.BIND_AUTO_CREATE);
}

    doUnBindService

private void doUnBindService(){
	unbindService(serviceConn);
}

    doTranslate

//launch a thread for translation
private void doTranslate(){
	new Thread(new Runnable() {
		@Override
		public void run() {
			String result = null;
			try {
				String input = etInput.getText().toString();
				//use the translate service
				result = mTranslateService.traslate(input);
				//send message callback
				Message msg = new Message();
				msg.obj = result;
				if(result == null){
					msg.what = TRANSLATE_ERROR;
					throw new Exception("Failed to get a translation...");
				}
				msg.what = TRANSLATE_COMPLETED;
				mHandler.sendMessage(msg);
			} catch (Exception e) {
				Log.e(TAG, "Error happened while translating...", e);
			}
		}
	}).start();
}

    Handler

private static final int TRANSLATE_COMPLETED = 0;
private static final int TRANSLATE_ERROR = 1;

//controller
private Handler mHandler = new Handler(){
	@Override
	public void handleMessage(Message msg) {
		switch (msg.what) {
		case TRANSLATE_COMPLETED:
			String result = (String) msg.obj;
			etTranslation.setText(result);
			etInput.selectAll();
			break;
		case TRANSLATE_ERROR:
			Log.e(TAG, "translation error");
			break;
		default:
			break;
		}
	}
	
};

    总结

    代码不多,逻辑也相对简单,主要是学习如何使用AIDL调用远程服务。

    提示:使用之前,请用申请到的KEY替换config包下的key以及keyfrom!

    代码

    详见我的Github:https://github.com/ryanhoo/TranslateService

展开阅读全文
打赏
0
4 收藏
分享
加载中
更多评论
打赏
0 评论
4 收藏
0
分享
返回顶部
顶部