转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)
http://my.oschina.net/ryanhoo/blog/100589
今天我们来学习使用现有的服务构建应用的功能模块——利用有道的翻译API构建一个小的翻译程序。之前曾想用Google的翻译API来实现,后来发现这项服务是收费的,所以用有道的,免费才是王道。
先来看看效果
功能相当简单,主要提供英汉互译(其实参数无需传入语言,有道翻译机器人会自动识别)。
实现步骤如下:
申请有道翻译API KEY
请在这个页面填写必要信息,并记录返回的Key和keyfrom,调用有道的翻译服务将需要使用它。
在申请到Key以后,请花几分钟时间简短的浏览下有道API调用的文档,就在申请页的下面。
请求接口非常简单:
1 | http://fanyi.youdao.com/openapi.do?keyfrom=< keyfrom >&key=< key >&type=data&doctype=< doctype >&version=1.1&q=要翻译的文本 |
唯一在变动的参数是翻译文本,这让我们定义AIDL变得非常容易。
编写AIDL远程服务调用接口
新建ITranslateService.aidl,定义一个简单的接口,只需传入一个参数——待翻译文本。
1 | package com.iedgeco.ryan.translate.service; |
4 | String traslate(in String text); |
实现服务
01 | public class TranslateService extends Service { |
03 | public static final String TAG = "TranslateService" ; |
06 | private final ITranslate.Stub mBinder = new ITranslate.Stub() { |
08 | public String traslate(String text) throws RemoteException { |
11 | return Translator.translate(text); |
12 | } catch (Exception e) { |
13 | Log.e(TAG, "Failed to translate" , e); |
20 | public IBinder onBind(Intent intent) { |
在AIDL所在的包下实现一个Service类
TranslateService
,实现相当的简单。因为是远程调用服务而非本地服务,后期需要使用bindService,因此我们必须返回IBinder实例。这里的IBinder中具体的翻译操作,我交给一个工具类
Translator
的静态方法完成,只需传入待翻译文本即可。
01 | public class Translator { |
03 | private static final String TAG = "Translator" ; |
05 | private static final String ENCODING = "UTF-8" ; |
09 | * 请求标准: http://fanyi.youdao.com/openapi.do? |
16 | * 版本:1.1,请求方式:get,编码方式:utf-8 |
18 | * 中英互译,同时获得有道翻译结果和有道词典结果(可能没有) |
20 | * type - 返回结果的类型,固定为data |
21 | * doctype - 返回结果的数据格式,xml或json或jsonp |
22 | * version - 版本,当前最新版本为1.1 |
23 | * q - 要翻译的文本,不能超过200个字符,需要使用utf-8编码 |
32 | * @throws ClientProtocolException |
34 | public static String translate(String text) throws Exception { |
35 | String url = "http://fanyi.youdao.com/openapi.do?keyfrom=" + StaticDef.KEY_FROM |
36 | + "&key=" + StaticDef.KEY_FOR_TRANSLATE |
42 | HttpClient client = new DefaultHttpClient(); |
43 | HttpGet httpGet = new HttpGet(url); |
44 | HttpResponse response = client.execute(httpGet); |
45 | InputStream is = response.getEntity().getContent(); |
46 | BufferedReader reader = new BufferedReader( new InputStreamReader(is, ENCODING)); |
47 | StringBuffer result = new StringBuffer(); |
49 | if ( null != (string = reader.readLine())) |
50 | result.append(string).append( '\n' ); |
52 | String translation = (String) new JSONObject(result.toString()) |
53 | .getJSONArray( "translation" ).get( 0 ); |
55 | Log.i(TAG, "result: " + result.toString()); |
实现UI并调用翻译服务
UI相对简单,具体的布局请见Github中的代码,后面我会给出地址。
MainActivity中的方法也比较简单,在onCreate中启用服务(doBindService),在onDestory中解除绑定,销毁服务(doUnBindService),可以使用doTranslate进行后台翻译(由于服务是直接运行在Main线程上的,我开启了一个异步线程来完成这个工作,并将结果反馈给Handler,由它来更新UI)。
doBindService:
1 | private void doBindService(){ |
2 | Intent service = new Intent(StaticDef.ACTION_TRANALATE); |
3 | bindService(service, serviceConn, Context.BIND_AUTO_CREATE); |
doUnBindService:
1 | private void doUnBindService(){ |
2 | unbindService(serviceConn); |
doTranslate:
02 | private void doTranslate(){ |
03 | new Thread( new Runnable() { |
08 | String input = etInput.getText().toString(); |
10 | result = mTranslateService.traslate(input); |
12 | Message msg = new Message(); |
15 | msg.what = TRANSLATE_ERROR; |
16 | throw new Exception( "Failed to get a translation..." ); |
18 | msg.what = TRANSLATE_COMPLETED; |
19 | mHandler.sendMessage(msg); |
20 | } catch (Exception e) { |
21 | Log.e(TAG, "Error happened while translating..." , e); |
Handler:
01 | private static final int TRANSLATE_COMPLETED = 0 ; |
02 | private static final int TRANSLATE_ERROR = 1 ; |
05 | private Handler mHandler = new Handler(){ |
07 | public void handleMessage(Message msg) { |
09 | case TRANSLATE_COMPLETED: |
10 | String result = (String) msg.obj; |
11 | etTranslation.setText(result); |
15 | Log.e(TAG, "translation error" ); |
总结
代码不多,逻辑也相对简单,主要是学习如何使用AIDL调用远程服务。
提示:使用之前,请用申请到的KEY替换config包下的key以及keyfrom!
代码
详见我的Github:https://github.com/ryanhoo/TranslateService