Android 百度翻译API(详细步骤+源码)(1)

<LinearLayout

android:visibility=“gone”

android:id=“@+id/result_lay”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“20dp”

android:orientation=“vertical”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“翻译结果”

android:textColor=“#000”

android:textSize=“14sp” />

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“10dp”

android:background=“#FFF”

android:orientation=“vertical”>

<TextView

android:id=“@+id/tv_result”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:padding=“10dp”

android:textColor=“#000” />

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:gravity=“right”

android:orientation=“horizontal”>

<ImageView

android: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” />

<androidx.cardview.widget.CardView

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“20dp”

android:background=“#FFF”

app:cardCornerRadius=“5dp”>

<TextView

android: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>

这个布局里面,我现在隐藏了两块区域。第一块是翻译后的语言区域,第二块是翻译后的结果区域。运行的效果如下:

在这里插入图片描述

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 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() {

@Override

public void beforeTextChanged(CharSequence s, int start, int count, int after) {

ivClearTx.setVisibility(View.VISIBLE);//显示清除按钮

}

@Override

public void onTextChanged(CharSequence s, int start, int before, int count) {

ivClearTx.setVisibility(View.VISIBLE);//显示清除按钮

}

@Override

public 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() {

@Override

public 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

*/

@Override

public 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/translate

String 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() {

@Override

public void onFailure(Call call, final IOException e) {

//异常返回

goToUIThread(e.toString(), 0);

}

@Override

public 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() {

@Override

public void run() {

tvTranslation.setText(“翻译”);

tvTranslation.setEnabled(true);

if (key == 0) {//异常返回

showMsg(“异常信息:” + object.toString());

Log.e(“MainActivity”,object.toString());

} else {//正常返回

//通过Gson 将 JSON字符串转为实体Bean

final 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 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 getTrans_result() {

return trans_result;

}

public void setTrans_result(List 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"?>

这个配置文件的意思就是允许明文访问网络,也就是http的许可

然后打开AndroidManifest.xml,在application标签中配置

在这里插入图片描述

配置好之后无论,再访问,铁定不报错了。

在这里插入图片描述

当然如果你的代码有报错,不妨试试运行我的源码看看,这也可以作为一个排错的方向。

四、源码地址

===================================================================

写作不易,如果这篇文章对你有帮助的话,不妨点个赞鼓励一下作者,举手之劳而已。

源码地址:

Java版TranslateDemo

Kotlin版TranslateDemo-Kotlin

这是APK下载二维码,如果你下载后运行没有问题,那么你的代码运行不了就是你自己的问题,无可争议。

在这里插入图片描述

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

总结

最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

mFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4NDM2MjE0,size_16,color_FFFFFF,t_70#pic_center)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-Tms4Rix5-1713763017797)]

[外链图片转存中…(img-Bx6oetFc-1713763017798)]

[外链图片转存中…(img-TymfIS0n-1713763017799)]

[外链图片转存中…(img-ATC094jE-1713763017800)]

[外链图片转存中…(img-vHrlFj4M-1713763017801)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

[外链图片转存中…(img-OtM9JbUL-1713763017802)]

总结

最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-XMVKIeuH-1713763017804)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值