Android 百度翻译API(详细步骤+源码)
百度翻译API
- 一、创建平台应用
- 二、创建及配置项目
- 三、编码
- 1. 修改外观与布局
- 2. 初始化控件
- 3. 输入框监听
- 4. 语言选择监听
- 5. 页面点击事件
- 6. 翻译
- 四、源码地址
一、创建平台应用
运行效果图
百度翻译开放平台也是属于百度智能云的一部分,所以你如果注册过百度的账号都是可以直接登录,当然最好做一下开发者认证,这样一些API的开放力度会大一些,再来说一下写这篇文章的初衷吧,首先我是弄过百度的翻译的,我之前并没有写过这方面的博客,而有读者看过我之前写的关于百度语音识别和百度文字识别的博客,于是问我百度翻译的相关问题,其实他突然这么问我,我也是很懵逼的(´⊙ω⊙`)。因为你光凭一个现象并不足以解决这个问题。一般情况下,按着官方文档来做基本上没问题,剩下的就是细节上的处理了,所以借着这个机会,索性写一篇这样的文章,就当是做个记录吧。
熟悉我写百度类似文章思路的朋友肯定知道,第一步是创建平台应用,点击百度翻译开放平台进入,至于登录和注册以及实名认证和开发者认证就没有讲述的必要了,如果你自己连这几步都无法独立完成的话,我也没有什么好说的了。如下图所示,我已经登录好了。
点击管理控制台,会让你先完成个人认证,如果你是第一次进入的话,认证完之后会出现
往下滑,你只要填写姓名和身份证号码即可,一个身份证只能认证一个账号,所以如果你已经认证过了,但是又想用另一个账号来做这个测试,你可以点击暂不认证,
这个消息是告诉你,你已经成功注册成为百度翻译的开发者,然后点击开通服务。
选择好之后点击下一步,点击开通标准版,你就不需要申请认证了,直接可以填写申请表格
开始填表
填写完资料之后,点击提交申请
点击前往管理控制台。然后找到你的APP ID,这个很重要,要在项目中使用的。
官方我的文档我就不去介绍了,用自己的理解来写。现在已经有了这个APP ID了,服务也开通好了,下面创建测试项目。
二、创建及配置项目
开大打开Android Studio,新建一个名为TranslateDemo的项目,如下图所示:
点击Finish完成创建。在这篇文章里,需要去自己去访问网络,所以需要添加一些依赖库
先在工程的build.gradle中添加
maven { url "https://jitpack.io" }
然后在app模块下的build.gradle中添加网络访问依赖库和其他的依赖
//网络访问implementation 'com.squareup.okhttp3:okhttp:3.10.0'//下拉框implementation 'com.github.arcadefire:nice-spinner:1.4.3'//卡片视图implementation 'androidx.cardview:cardview:1.0.0'//GSON解析implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
而其中okhttp是一个你做Android开发必须要知道的一个库,很多公司在面试的时候都会问这个库的底层原理,有想法可以详细的去官网了解,这是github上的地址:okhttp,有兴趣就可以去了解。文章中只是简单的使用而已,这里先说明,然后Sync。
然后在AndroidManifest.xml中添加网络访问权限
<!--网络访问权限--><uses-permission android:name="android.permission.INTERNET"/>
下面可以进入到正式的编码环节了。激动的心,颤抖的手,我相信你已经迫不及待了吧,当然我会尽我所能的讲清楚每一个环节,哪怕你觉得我啰嗦也好。
三、编码
1. 修改外观与布局
既然是编码,首先我要改变主题的外观,作为颜值控,我不运行这个丑的软件在我的手机上运行,这个项目你现在运行看到的页面是很丑的,来看看有多丑。
要想软件过得去,页面总得带点绿,这就是Google的直男审美。下面我都要改成白色,并且去掉它默认的顶部ActionBar。找到styles.xml文件并打开,修改代码如下:
<resources><!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"><!-- Customize your theme here. --><item name="colorPrimary">#FFF</item><item name="colorPrimaryDark">#FFF</item><item name="colorAccent">@color/colorAccent</item></style></resources>
这里我将主题样式的颜色从原谅绿改成了白色,并且NoActionBar去掉动作栏。然后你再运行一下
emmm…怎么说呢,感觉怪怪的,不行,还得再改改。打开MainActivity,在onCreate中增加如下代码:
//设置亮色状态栏模式 systemUiVisibility在Android11中弃用了,可以尝试一下。getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
其实使用这段代码的时候应该先判断Android的版本,这个在Android6.0以上生效,不过这只是做测试,所以我就不做判断了,因为我的手机是10.0,但是在实际的开发中还是要做的,这就涉及到Android版本适配了,比较多复杂,网络上的文章比较多,自行搜索。好了,下面运行一下:
看到状态栏了,不过好像还少了点什么,打开activity_main.xml,修改后代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.andr oid.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"android:orientation="vertical"tools:context=".MainActivity"><!--标题--><androidx.appcompat.widget.Toolbarandroid:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="#FFF"android:elevation="3dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="在线翻译"android:textColor="#000"android:textSize="18sp" /></androidx.appcompat.widget.Toolbar></LinearLayout>
再运行一下:
嗯,效果喜人,看上去就是辣么滴顺眼。然后我贴上完整的布局代码,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.andr oid.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"android:orientation="vertical"tools:context=".MainActivity"><!--标题--><androidx.appcompat.widget.Toolbarandroid:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="#FFF"android:elevation="3dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="在线翻译"android:textColor="#000"android:textSize="18sp" /></androidx.appcompat.widget.Toolbar><!--滚动视图 当内容高度超出屏幕高度时可以上下滚动--><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:overScrollMode="never"><!--主要操作区域--><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="20dp"><!--翻译前显示的布局--><LinearLayoutandroid:id="@+id/before_lay"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#FFF"android:foreground="@drawable/stroke_gray"><!--下拉框 控制转换的语言--><org.angmarch.views.NiceSpinnerandroid:id="@+id/sp_language"android:layout_width="match_parent"android:layout_height="48dp"app:arrowTint="#000"app:textTint="#000" /></LinearLayout><!--翻译后显示的布局--><LinearLayoutandroid:id="@+id/after_lay"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:orientation="horizontal"android:visibility="gone"><androidx.cardview.widget.CardViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="#FFF"app:cardCornerRadius="5dp"><!--翻译源语言--><TextViewandroid:id="@+id/tv_from"android:layout_width="match_parent"android:layout_height="40dp"android:background="@drawable/stroke_black_radus"android:gravity="center"android:textColor="#000"android:textSize="14sp" /></androidx.cardview.widget.CardView><ImageViewandroid:layout_width="30dp"android:layout_height="30dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:src="@mipmap/icon_change" /><androidx.cardview.widget.CardViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="#FFF"app:cardCornerRadius="5dp"><!--翻译目标语言--><TextViewandroid:id="@+id/tv_to"android:layout_width="match_parent"android:layout_height="40dp"android:background="@drawable/stroke_black_radus"android:gravity="center"android:textColor="#000"android:textSize="14sp" /></androidx.cardview.widget.CardView></LinearLayout><!--内容输入区域--><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="150dp"android:layout_marginTop="20dp"android:background="#FFF"><!--输入框--><EditTextandroid:id="@+id/ed_content"android:layout_width="match_parent"android:layout_height="150dp"android:background="@drawable/stroke_gray"android:gravity="top"android:hint="请输入要翻译的文字内容"android:maxLength="6000"android:paddingLeft="10dp"android:paddingTop="10dp"android:paddingRight="30dp"android:paddingBottom="10dp"android:textColor="#000"android:textColorLink="#ABABAB"android:textCursorDrawable="@drawable/cursor_style" /><!--清空输入内容--><ImageViewandroid:id="@+id/iv_clear_tx"android:layout_width="20dp"android:layout_height="20dp"android:layout_alignParentRight="true"android:layout_alignParentBottom="true"android:layout_marginRight="8dp"android:layout_marginBottom="8dp"android:src="@mipmap/icon_delete"android:visibility="gone" /></RelativeLayout><!--翻译后的结果显示--><LinearLayoutandroid:visibility="gone"android:id="@+id/result_lay"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="翻译结果"android:textColor="#000"android:textSize="14sp" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:background="#FFF"android:orientation="vertical"><!--显示翻译的结果--><TextViewandroid:id="@+id/tv_result"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="10dp"android:textColor="#000" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="right"android:orientation="horizontal"><!--复制翻译出来的结果--><ImageViewandroid:id="@+id/iv_copy_tx"android:layout_width="24dp"android:layout_height="24dp"android:layout_marginRight="4dp"android:layout_marginBottom="4dp"android:padding="4dp"android:src="@mipmap/icon_copy" /></LinearLayout></LinearLayout></LinearLayout><androidx.cardview.widget.CardViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:background="#FFF"app:cardCornerRadius="5dp"><TextViewandroid:id="@+id/tv_translation"android:layout_width="match_parent"android:layout_height="48dp"android:background="@drawable/stroke_black_radus"android:foreground="?android:attr/selectableItemBackground"android:gravity="center"android:padding="10dp"android:text="翻译"android:textColor="#000"android:textColorLink="#ABABAB"android:textSize="16sp" /></androidx.cardview.widget.CardView></LinearLayout></ScrollView></LinearLayout>
这个布局里面,我现在隐藏了两块区域。第一块是翻译后的语言区域,第二块是翻译后的结果区域。运行的效果如下:
2. 初始化控件
在MainActivity中,声明变量
private LinearLayout beforeLay;//翻译之前的布局private NiceSpinner spLanguage;//语言选择下拉框private LinearLayout afterLay;//翻译之后的布局private TextView tvFrom;//翻译源语言private TextView tvTo;//翻译目标语言private EditText edContent;//输入框(要翻译的内容)private ImageView ivClearTx;//清空输入框按钮private TextView tvTranslation;//翻译private LinearLayout resultLay;//翻译结果布局private TextView tvResult;//翻译的结果private ImageView ivCopyTx;//复制翻译的结果private String fromLanguage = "auto";//目标语言private String toLanguage = "auto";//翻译语言private ClipboardManager myClipboard;//复制文本private ClipData myClip; //剪辑数据private String appId = "20201125000625305";//APP ID 来源于百度翻译平台 请使用自己的private String key = "6vjmDnNxypmebgbzKxul";//秘钥 来源于百度翻译平台 请使用自己的//配置初始数据private List<String> data = new LinkedList<>(Arrays.asList("自动检测语言", "中文 → 英文", "英文 → 中文","中文 → 繁体中文", "中文 → 粤语", "中文 → 日语","中文 → 韩语", "中文 → 法语", "中文 → 俄语","中文 → 阿拉伯语", "中文 → 西班牙语 ", "中文 → 意大利语"));
然后新写一个initView的方法。在这里对控件进行初始化并给予点击事件,并且数据赋值,
/*** 初始化控件视图*/private void initView() {//设置亮色状态栏模式 systemUiVisibility在Android11中弃用了,可以尝试一下。getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//控件初始化beforeLay = findViewById(R.id.before_lay);spLanguage = findViewById(R.id.sp_language);afterLay = findViewById(R.id.after_lay);tvFrom = findViewById(R.id.tv_from);tvTo = findViewById(R.id.tv_to);edContent = findViewById(R.id.ed_content);ivClearTx = findViewById(R.id.iv_clear_tx);tvTranslation = findViewById(R.id.tv_translation);resultLay = findViewById(R.id.result_lay);tvResult = findViewById(R.id.tv_result);ivCopyTx = findViewById(R.id.iv_copy_tx);//点击时间ivClearTx.setOnClickListener(this);ivCopyTx.setOnClickListener(this);tvTranslation.setOnClickListener(this);//设置下拉数据spLanguage.attachDataSource(data);editTextListener();//输入框监听spinnerListener();//下拉框选择监听//获取系统粘贴板服务myClipboard = (ClipboardManager) this.getSystemService(CLIPBOARD_SERVICE);}
3. 输入框监听
editTextListener方法代码:
/*** 输入监听*/private void editTextListener() {edContent.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {ivClearTx.setVisibility(View.VISIBLE);//显示清除按钮}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {ivClearTx.setVisibility(View.VISIBLE);//显示清除按钮}@Overridepublic void afterTextChanged(Editable s) {ivClearTx.setVisibility(View.VISIBLE);//显示清除按钮String content = edContent.getText().toString().trim();if (content.isEmpty()) {//为空resultLay.setVisibility(View.GONE);tvTranslation.setVisibility(View.VISIBLE);beforeLay.setVisibility(View.VISIBLE);afterLay.setVisibility(View.GONE);ivClearTx.setVisibility(View.GONE);}}});}
4. 语言选择监听
spinnerListener方法代码如下:
/*** 语言类型选择*/private void spinnerListener() {spLanguage.setOnSpinnerItemSelectedListener(new OnSpinnerItemSelectedListener() {@Overridepublic void onItemSelected(NiceSpinner parent, View view, int position, long id) {switch (position) {case 0://自动检测fromLanguage = "auto";toLanguage = fromLanguage;break;case 1://中文 → 英文fromLanguage = "zh";toLanguage = "en";break;case 2://英文 → 中文fromLanguage = "en";toLanguage = "zh";break;case 3://中文 → 繁体中文fromLanguage = "zh";toLanguage = "cht";break;case 4://中文 → 粤语fromLanguage = "zh";toLanguage = "yue";break;case 5://中文 → 日语fromLanguage = "zh";toLanguage = "jp";break;case 6://中文 → 韩语fromLanguage = "zh";toLanguage = "kor";break;case 7://中文 → 法语fromLanguage = "zh";toLanguage = "fra";break;case 8://中文 → 俄语fromLanguage = "zh";toLanguage = "ru";break;case 9://中文 → 阿拉伯语fromLanguage = "zh";toLanguage = "ara";break;case 10://中文 → 西班牙语fromLanguage = "zh";toLanguage = "spa";break;case 11://中文 → 意大利语fromLanguage = "zh";toLanguage = "it";break;default:break;}}});}
5. 页面点击事件
同时要实现点击事件的监听,
鼠标点击这一行代码,然后使用快捷键,Alt + 回车
选择第一项,然后回车
点击OK,之后会重写onClick方法。这里不止一个控件,所以要根据view的id来判断才行。
/*** 页面点击事件* @param v*/@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.iv_clear_tx://清空输入框edContent.setText("");//清除文本ivClearTx.setVisibility(View.GONE);//清除数据之后隐藏按钮break;case R.id.iv_copy_tx://复制翻译后的结果String inviteCode = tvResult.getText().toString();myClip = ClipData.newPlainText("text", inviteCode);myClipboard.setPrimaryClip(myClip);showMsg("已复制");break;case R.id.tv_translation://翻译translation();//翻译break;default:break;}}/*** Toast提示* @param msg*/private void showMsg(String msg) {Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();}
下面重点来看看这个翻译的方法,这里面的东西还挺多的。
6. 翻译
既然是翻译首先获取到输入的文字,如下所示:
/*** 翻译*/private void translation() {//获取输入的内容String inputTx = edContent.getText().toString().trim();//判断输入内容是否为空if (!inputTx.isEmpty() || !"".equals(inputTx)) {//不为空tvTranslation.setText("翻译中...");tvTranslation.setEnabled(false);//不可更改,同样就无法点击String salt = num(1);//随机数//拼接一个字符串然后加密String spliceStr = appId + inputTx + salt + key;//根据百度要求 拼接String sign = stringToMD5(spliceStr);//将拼接好的字符串进行MD5加密 作为一个标识//异步Get请求访问网络asyncGet(inputTx, fromLanguage, toLanguage, salt, sign);} else {//为空showMsg("请输入要翻译的内容!");}}
这里先判断了输入框的值是否为null或者“”,不是则改变翻译按钮的文字显示,并且不可点击,给用户一种正在翻译的假象。之后就是生成一个随机数,这个是按照百度的要求来的,方法很简单,就不过多解释了。
/*** 随机数 (根据百度的要求需要一个随机数)*/public static String num(int a) {Random r = new Random(a);int ran1 = 0;for (int i = 0; i < 5; i++) {ran1 = r.nextInt(100);System.out.println(ran1);}return String.valueOf(ran1);}
然后拼接一个字符串spliceStr,然后通过md5进行小写加密,加密后的值也是作为访问百度翻译API的一个参数。加密方法如下:
/*** 将字符串转成MD5值** @param string 需要加密的内容* @return 加密后的字符串*/public static String stringToMD5(String string) {byte[] hash;try {hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));} catch (NoSuchAlgorithmException e) {e.printStackTrace();return null;} catch (UnsupportedEncodingException e) {e.printStackTrace();return null;}StringBuilder hex = new StringBuilder(hash.length * 2);for (byte b : hash) {if ((b & 0xFF) < 0x10) {hex.append("0");}hex.append(Integer.toHexString(b & 0xFF));}return hex.toString();}
网络请求作为耗时操作,所以通常不会在主线程中进行,所以写一个异步Get请求访问网络的方法,传入刚才写进去的一些参数。
/*** 异步Get请求** @param content 要翻译的内容* @param fromType 翻译源语言* @param toType 翻译后语言* @param salt 随机数* @param sign 标识*/private void asyncGet(String content, String fromType, String toType, String salt, String sign) {//通用翻译API HTTP地址://http://api.fanyi.baidu.com/api/trans/vip/translate//通用翻译API HTTPS地址://https://fanyi-api.baidu.com/api/trans/vip/translateString httpStr = "http://api.fanyi.baidu.com/api/trans/vip/translate";String httpsStr = "https://fanyi-api.baidu.com/api/trans/vip/translate";//拼接请求的地址String url = httpsStr +"?appid=" + appId + "&q=" + content + "&from=" + fromType + "&to=" +toType + "&salt=" + salt + "&sign=" + sign;OkHttpClient okHttpClient = new OkHttpClient();final Request request = new Request.Builder().url(url).get()//默认就是GET请求,可以不写.build();Call call = okHttpClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, final IOException e) {//异常返回goToUIThread(e.toString(), 0);}@Overridepublic void onResponse(Call call, Response response) throws IOException {//正常返回goToUIThread(response.body().string(), 1);}});}
这里就是OkHttp的简单使用了,而这里我写了两个访问地址,区别就是一个是https一个是http,不知道这两个区别的自行百度,没有解释的必要。你可能会问这个和Android有什么关系,别着急,会让你看到的。GET请求常规的操作就是把参数拼接到URL后面,我这里也是这么找的,
//拼接请求的地址String url = httpsStr +"?appid=" + appId + "&q=" + content + "&from=" + fromType + "&to=" +toType + "&salt=" + salt + "&sign=" + sign;
URL的第一个参数要用?开头,后续参数使用&,其他的就是字符串的拼接了,一目了然。然后将地址放入到Request,里面完成请求体的构建,然后通过Call构建一个新的请求回调。在请求队列里监听请求的结果,结果只有两种,成功和失败。之前我是通过异步请求网络的,那么它的回调自然也不会是在主线程中,但是我又要在回调里面控制页面的UI。那么就需要切换到主线程或者UI线程中进行。于是你看到我在成功和失败的返回中都调用了goToUIThread,里面第一个参数作为一个Object对象,失败时传入错误信息,成功时传入返回数据。方法如下:
/*** 接收到返回值后,回到UI线程操作页面变化** @param object 接收一个返回对象* @param key 表示正常还是异常*/private void goToUIThread(final Object object, final int key) {//切换到主线程处理数据MainActivity.this.runOnUiThread(new Runnable() {@Overridepublic void run() {tvTranslation.setText("翻译");tvTranslation.setEnabled(true);if (key == 0) {//异常返回showMsg("异常信息:" + object.toString());Log.e("MainActivity",object.toString());} else {//正常返回//通过Gson 将 JSON字符串转为实体Beanfinal TranslateResult result = new Gson().fromJson(object.toString(), TranslateResult.class);tvTranslation.setVisibility(View.GONE);//显示翻译的结果tvResult.setText(result.getTrans_result().get(0).getDst());resultLay.setVisibility(View.VISIBLE);beforeLay.setVisibility(View.GONE);afterLay.setVisibility(View.VISIBLE);//翻译成功后的语言判断显示initAfter(result.getFrom(), result.getTo());}}});}
这种写代码的方式虽然像是套娃一样,一层一层的,看起来好像很复杂的样子,但是其实是有一个思路串联起来的,由上到下,思路清晰就很好理解,我个人觉得比把所有代码写在一个方法里要好。而在上面的代码中,通过传进来的key来区别是成功还是失败。失败里面就是提示失败信息通过打印失败信息。成功里面,通过Gson将返回的JSON字符串转换成实体Bean。TranslateResult代码如下:
package com.llw.translate;import java.util.List;/*** 翻译结果* @author llw */
public class TranslateResult {/*** from : zh* to : en* trans_result : [{"src":"早上","dst":"morning"}]*/private String from;private String to;private List<TransResultBean> trans_result;public String getFrom() {return from;}public void setFrom(String from) {this.from = from;}public String getTo() {return to;}public void setTo(String to) {this.to = to;}public List<TransResultBean> getTrans_result() {return trans_result;}public void setTrans_result(List<TransResultBean> trans_result) {this.trans_result = trans_result;}public static class TransResultBean {/*** src : 早上* dst : morning*/private String src;private String dst;public String getSrc() {return src;}public void setSrc(String src) {this.src = src;}public String getDst() {return dst;}public void setDst(String dst) {this.dst = dst;}}
}
后面就是一些控件的隐藏和显示了,请结合GIF示例图来看,会让你有一个清晰的认识。然后还有最后initAfter一个方法要讲一下:
/*** 翻译成功后的语言判断显示*/private void initAfter(String from, String to) {if (("zh").equals(from)) {tvFrom.setText("中文");} else if (("en").equals(from)) {tvFrom.setText("英文");} else if (("yue").equals(from)) {tvFrom.setText("粤语");} else if (("cht").equals(from)) {tvFrom.setText("繁体中文");} else if (("jp").equals(from)) {tvFrom.setText("日语");} else if (("kor").equals(from)) {tvFrom.setText("韩语");} else if (("fra").equals(from)) {tvFrom.setText("法语");} else if (("ru").equals(from)) {tvFrom.setText("俄语");} else if (("ara").equals(from)) {tvFrom.setText("阿拉伯语");} else if (("spa").equals(from)) {tvFrom.setText("西班牙语");} else if (("it").equals(from)) {tvFrom.setText("意大利语");}if (("zh").equals(to)) {tvTo.setText("中文");} else if (("en").equals(to)) {tvTo.setText("英文");} else if (("yue").equals(to)) {tvTo.setText("粤语");} else if (("cht").equals(to)) {tvTo.setText("繁体中文");} else if (("jp").equals(to)) {tvTo.setText("日语");} else if (("kor").equals(to)) {tvTo.setText("韩语");} else if (("fra").equals(to)) {tvTo.setText("法语");} else if (("ru").equals(to)) {tvTo.setText("俄语");} else if (("ara").equals(to)) {tvTo.setText("阿拉伯语");} else if (("spa").equals(to)) {tvTo.setText("西班牙语");} else if (("it").equals(to)) {tvTo.setText("意大利语");}}
这个方法很简单,就是根据返回的值得检测到的语言类型,去控制UI的显示而已。
好了,写了这么久,还没有运行过呢?下面运行一下吧。
OK,已经搞定了。还记得之前百度有两个访问地址吗?我之前用的是https的,那么现在用http的,再运行访问一下
你会发现只是用http地址访问怎么就不行了呢?,难道是这个地址有问题,首先这个地址没有问题,而是Android的版本从中作祟,Google规定在Android9.0以后默认是https访问网络,所以刚才使用了http不行。那么如果要用http访问呢?也比较简单,配置一个网络访问许可就行了。
在res下新建一个xml文件夹,文件夹下新建一个network_security_config.xml,里面的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config cleartextTrafficPermitted="true" ><trust-anchors><certificates src="system" /></trust-anchors></base-config>
</network-security-config>
这个配置文件的意思就是允许明文访问网络,也就是http的许可
然后打开AndroidManifest.xml,在application标签中配置
配置好之后无论,再访问,铁定不报错了。
当然如果你的代码有报错,不妨试试运行我的源码看看,这也可以作为一个排错的方向。
四、源码地址
写作不易,如果这篇文章对你有帮助的话,不妨点个赞鼓励一下作者,举手之劳而已。
源码地址:
Java版:TranslateDemo
Kotlin版:TranslateDemo-Kotlin
这是APK下载二维码,如果你下载后运行没有问题,那么你的代码运行不了就是你自己的问题,无可争议。
疑难杂症: 有部分读者运行了我的源码,然后发现点击翻译之后会闪退,报错如下
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object referenceat com.llw.translate.MainActivity$4.run(MainActivity.java:329)
这是报错的原因是翻译是成功的,但是没有获取到翻译后的数据,也可以说是数据为空,然后用这个数据去赋值显示出来,就报错了,那么为什么会为空呢?我也是百思不得其解,因为我的代码我运行在手机或者是模拟器上都是正常的,从来不会闪退。所以我怀疑是百度搞的鬼。问题可能是:① 百度翻译服务可能限制了访问的ip。② 开发者账号需要做个人开发者认证,认证后的appid和密码才能供其他开发者使用。
不过这两个问题没有依据。反正就是一个现象,我运行没有问题,其他人运行就闪退,我能怎么办?只能慢慢跟踪,回头问问百度的开发人员看是怎么回事。
Android 百度翻译API(详细步骤+源码)相关推荐
- 实战 | 用Python和MediaPipe搭建一个嗜睡检测系统 (详细步骤 + 源码)
导读 本文将使用Python和MediaPipe搭建一个嗜睡检测系统 (包含详细步骤 + 源码). 背景介绍 疲劳驾驶的危害不堪设想,据了解,21%的交通事故都因此而生,尤其是高速路上,大多数车辆都是 ...
- 实战 | 基于OpenCV的停车场空余车位实时监测系统(详细步骤 + 源码)
导 读 本文主要介绍如何使用Python和OpenCV实现一个停车场空余车位实时监测系统,并包含详细步骤和源码. 背景介绍 介绍实现步骤之前,先来看看测试视频(小型停车场实时监控画面): ,时长00 ...
- Android 百度语音合成 (含离线、在线、API合成方式,详细步骤+源码)
百度语音合成 声明 前言 正文 一.创建项目 二.离线语音合成 1. 配置AndroidManifest.xml 2. 配置SDK 3. 离线SDK初始化 4. 导包 5. 运行 三.在线语音合成 - ...
- Android 高德地图API(详细步骤+源码)
高德地图API使用详解 前言 正文 一.创建应用 ① 获取PackageName ② 获取调试版安全码SHA1 ③ 获取发布版安全码SHA1 二.配置Android Studio工程 ① 导入SDK ...
- Android 百度语音识别(详细步骤+源码)
前言 因为项目中用到了语音识别的技术,但是项目源码我不能公开,所以,重新写一个简单的集成教程,不喜可不看,不做键盘侠,文明你我他. 效果图 识别结果 最终效果 源码在文章最后,不需要下载积分什么的,哪 ...
- Android 百度文字识别(详细步骤+源码)
运行效果图 识别到的内容: {"words_result":[{"words":"突然间有想看书的冲动"},{"words&quo ...
- Android 腾讯位置服务使用(详细步骤+源码)
腾讯位置服务使用 前言 正文 一.注册腾讯位置服务账号 二.创建平台应用Appkey 三.创建并配置AS工程 四.定位 ① 连续定位 ② 单次定位 ③ 后台定位 ④ 地理围栏 五.地图 ① 基础地图 ...
- 使用Keras和OpenCV实时预测年龄、性别和情绪 (详细步骤+源码)
来源 | https://towardsdatascience.com/real-time-age-gender-and-emotion-prediction-from-webcam-with-ker ...
- python在线编程翻译器-【分享】python 翻译器,爬取百度翻译,并附上源码
[Python] 纯文本查看 复制代码#!/usr/bin/python # -*- coding: cp936 -*- ####################################### ...
- python代码翻译器-【分享】python 翻译器,爬取百度翻译,并附上源码
[Python] 纯文本查看 复制代码#!/usr/bin/python # -*- coding: cp936 -*- ####################################### ...
最新文章
- (Incomplete) UVa 719 Glass Beads
- NotePad++学习总结
- Excel多因素可重复方差分析
- 【GitHub】如何合并分支?
- 部署及配置Lync Server 2013 监控功能
- 纯靠技术,很难进入大厂了。。。
- MacBook Pro 如何删除多余专注模式?
- 计算机应用基础第十一版答案,计算机应用基础试题十一.xls
- 硬件工程师如何零基础入门?
- ICO 图标快速制作
- gazebo设置_GAZEBO学习笔记(3)
- 关于谷歌浏览器全线崩溃的原因及几种解决办法(疑难杂症篇)
- 破解不加微信看朋友圈
- Android删除系统的WIFI功能
- 洛阳等地启动电子劳动合同试点,多家名企选择法大大
- 题解 CF133A 【HQ9+】
- 手撕鸭腌料批发场 新奥尔良烤肉腌料批发 奥尔良鸡叉骨腌料批发
- Caffe中卷基层和全连接层训练参数个数如何确定
- ng 无法加载文件 C:\Users\hl\AppData\Roaming\npm\ng.ps1 解决方法
- dtoj#4224. 小L的占卜
热门文章
- 嵌入式 职位描述 职位要求
- 蓝色学校网站模板_中小学网站源码_学校网站管理系统
- 互联网盈利模式,网络策划运营模式
- 继美国后新加坡电信运营商遭DDoS攻击 部分用户断网
- python如何绘制曲线图_Python matplotlib 如何绘制双Y轴曲线图?
- 执行maven install命令报java不支持diamond语法
- python常用快捷键mac_Mac PHPStorm 常用快捷键,常用设置
- win10系统的怎么搭建web服务器,win10系统利用iis搭建web服务器的操作方法
- 静止卫星遥感图像太阳及卫星天顶、方位角(SOZ/SOA/SAZ/SAA)计算方法
- 智能电视大战背后的秘密