整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Android与javaweb数据交互

Android与javaweb数据交互

ndroid向前端发送数据

一般需要交互的数据无非就是文件和字符串(可以替代很多东西),文件又可以变为字符串流进行传输。本文将使用okhttp包从Android端向后端发送数据和接收返回数据。

注意:个人电脑测试若无https协议的域名或ip地址,请在Android的AndroidManifest.xml文件中声明使用明文传输,即不加密而使用http协议。

<application

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:roundIcon="@mipmap/ic_launcher_round"

android:supportsRtl="true" android:usesCleartextTraffic="true"//此处默认选项为false,不启用明文传输,改为true即可

android:theme="@style/AppTheme">

</application>

数据发送,Android端向客户端发送消息如果为get直接在url中添加参数即可,下面主要介绍post,用字符串作为post参数,文件将经过base64编码为字符串传输,字符串类型数据可采用json传输也可以直接用字符串。

注意:okhttp包需额外下载,包含okhttp和okio两个包且版本存在不适配问题,需要对应,这里采用okhttp3.12, okio1.14。如果使用grade(一般Android都是这个),可直接在build.grade中使用`implementation group: 'com.squareup.okio', name: 'okio', version: '1.14.0'`导入,建议下载对应包。

注意:数据发送操作(向网络申请数据)为耗时操作,不可在主线程中运行,另外不建议直接在oncreate等视图创建方法中调用,可以作为按钮点击事件调用。另外收sdk限制同时会限制jdk版本,这里使用的base64编码是Android自带的,与稍后后端解析时的不同。因为jdk版本原因及编码规范,存在不同格式的base64编码,Androidsdk26以上可采用java自带的base64编码工具。

new Thread()

{

      //重写线程run方法
      @Override
      public void run()

      {

          //定义okhttp对象
          OkHttpClient okHttpClient=new OkHttpClient();

          try {

              //如果传输文件
              FileInputStream inputStream=new FileInputStream(new File(getDataDir() + "/x1.png"));

              //文件读取为bytes
              byte[] bytes=new byte[inputStream.available()];

              inputStream.read(bytes);
              //将bytes使用base64编码
              String a1=Base64.encodeToString(bytes, Base64.NO_PADDING);

              //post的方法体,用来添加数据(key-value方式),但只能添加字符串作为数据
              FormBody formBody=new FormBody.Builder().add("w1", a1).add("w2", "wad").build();

              //请求创建
              Request request=new Request.Builder().url("http://192.168.56.1:8080/titan/login").post(formBody).build();

              //执行请求
              Call call=okHttpClient.newCall(request);

              Response response=call.execute();//获得服务端返回内容
              //将返回内容作为字符串输出,也可转换为bytes等
              System.out.println(response.body().string());
          }

          catch (IOException e) {

         		 e.printStackTrace();

      }

	}

}.start();//线程直接启动

服务端接收与返回数据

项目使用tomcat,利用struts的action请求和返回数据。action可返回不限于json、html网页、流格式的内容。项目大致结构如下。

项目结构图

其中images文件夹作为Android端文件存储库和返回信息库,一般不建议将此类文件放入项目内,一个是通过相对路径不方便调取(存在诸多问题,所以放在外边采用绝对路径访问),还有就是对于tomcat下webapps的内容均可以通过url访问,文件直接就泄露了。index.jsp并无什么用,只是默认主页。

struts.xml配置文件,此文件build完成时需在WEB-INF/classes文件夹下,关于在web.xml里配置struts不再给出.

<?xml version="1.0" encoding="UTF-8" ?>
  <!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"

"http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>

//此包用于返回json数据,继承json-default包,也可通过result-types指定,不再介绍

<package name="backJOSN" extends="json-default">

//活动配置,负责返回json数据,可以返回json文件或者自定义json串,这里是有action内部变量组成的json串

<action name="login" class="com.example.titanback.LoginAction">

<result type="json">

</result>

</action>

</package>

//继承默认包,可返回文件流或者html文件文本

<package name="backHTML" extends="struts-default">

//返回图片的活动

<action name="imgBack" class="com.example.titanback.ImgBackAction">

<result type="stream">//返回流

//配置返回流,返回png格式图片,并配置对应变量

<param name="contentType">image/png</param>

<param name="inputStream">inputStream</param>

</result>

</action>

</package>

</struts>

代码,此代码将返回json字符串:

//可继承Action接口或继承ActionSupport类

public class LoginAction extends ActionSupport

{

        //变量和setter、getter方法
        private String username;

        private String password;

        public void setUsername(String username) { this.username=username; }

        public String getPassword() { return password; }

        public String getUsername() { return username; }

        public void setPassword(String password) { this.password=password; }

        @Override

        public String execute() throws Exception

        {

              //获取上下文,getResponse可获取response对象
              HttpServletRequest actionContext=ServletActionContext.getRequest();

              //输出获取参数

              System.out.println(actionContext.getParameter("w1"));

              String a1=actionContext.getParameter("w1");

              //文件写入流,采用绝对路径
              FileOutputStream outputStream=new FileOutputStream("C:\\Users\\1\\Desktop\\Titan\\titanback\\images\\x1.png");

              //将base64解码,注意以为jdk原因,需要去掉换行符,最好采用utf-8编码
              ByteArrayInputStream inputStream=new ByteArrayInputStream(Base64.getMimeDecoder().decode(a1.replace("\r\n", "").getBytes(StandardCharsets.UTF_8)));

              //输出流直接转换
              inputStream.transferTo(outputStream);

              outputStream.close();//关闭

              setUsername("w112");//设置参数

              setPassword("wdaw");

              return SUCCESS;

			}

}

注意:关于base64编码问题,请看:(https://blog.csdn.net/kevin_mails/article/details/87878601)

此代码将返回png格式图片流:

解释一个名词吧 Hybrid, 相信能看到这篇文章的同学对这个词都不会感到陌生, 可能爱恨交叉的感觉会更强烈一些...

回到正题, Hybrid翻译过来叫混合,混合物,在前端世界里有一个词语叫混合开发便是它,大白话点就是将网页内嵌在原生app中,然后产生一系列的交互

常用的交互方式

  • 双方约定协议(schema)
  • 双方约定函数

双方约定协议(schema)

这里以android 为例,android 中可以通过WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url, 然后解析该 url 的协议, 如果检测到是预先约定好的协议,就调用相应方法

协议式的通信适用于单向交互, 客户端想要回传给我们参数比较复杂

代码理解

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <button type="button" id="button1" onclick="callAndroid()">点击调用Android代码</button>
    <script>
        function callAndroid() {
            /*约定的url协议为:js://webview?arg1=111&arg2=222*/
            location.href="js://webview?arg1=111&arg2=222";
        }
    </script>
</body>

</html>

双方约定函数

简单来说,就是客户端为我们做了一层关系映射, 也可以理解原生app端会向webview暴露一个顶层对象,就像js中的window,这个对象包含web需要但不具备因此由原生实现的一些方法

代码理解

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- 点击按钮则调用jsbridge函数 -->
    <button type="button" id="button1" onclick="jsbridge()">Hello</button>

    <script>
        function jsbridge() {
            // 由于对象映射,所以调用test对象等于调用Android映射的对象
            test.hello("js调用了原生app暴漏出来jsbridge中的hello方法");
        }
    </script>
</body>

</html>

总结

  • 约定协议(native拦截http协议进行判读是否是定义好的协议)
  • 约定函数(native向webview注入顶级对象)


lt;!DOCTYPE html>

<html lang="en">


<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="X-UA-Compatible" content="ie=edge">

<title>Document</title>

<style>

#href-box{

text-align: center;

font-size: 40px;

margin:0 atuo;

background: bisque;

}

#btn-box {

display: flex;

border-radius: 99%;

background: burlywood;

}


.menu h1 {

text-align: center;

background: greenyellow;

}


.menu div {

font-size: 24px;

text-align: center;

background: blueviolet;

}


#btn {

width: 100px;

height: 100px;

font-size: 24px;

background: yellowgreen;

display: block;

margin: 0 auto;

background: blue;

border-radius: 50%;

}


#showtext {

display: block;

margin: 0 auto;

font-size: 15px;

background: pink;

border: 1px solid

}


#showarray {

width: 100px;

height: 100px;

font-size: 24px;

background: yellowgreen;

display: block;

margin: 0 auto;

background: red;

border-radius: 50%;

}

#shuaxin{

width: 1500px;

height: 100px;

font-size: 24px;

background: yellowgreen;

display: block;

margin: 0 auto;

}


#showbackmap {

width: 100px;

height: 100px;

font-size: 24px;

background: yellowgreen;

display: block;

margin: 0 auto;

background: gray;

border-radius: 50%;

}


#text {

display: block;

margin: 0 auto;

font-size: 30px;

background: pink;

border: 1px solid

}


#fattext {

display: block;

margin: 0 auto;

font-size: 30px;

background: gray;

}


#showstruct {

width: 100px;

height: 100px;

font-size: 24px;

background: yellowgreen;

display: block;

margin: 0 auto;

background: red;

border-radius: 50%;

}

</style>

</head>


<body>

<div id="href-box">

<a href="https://blog.csdn.net/wangzhen12138/article/details/118068686?spm=1001.2014.3001.5502">CSDN学代码的小臻</a>

</div>

<button id="shuaxin">刷新</button>

<div class="menu">

<h1>基本的操作命令</h1>

<div>1. dir显示目录</div>

<div>2. md创建文件夹</div>

<div>3. mk创建文件</div>

<div>4. del删除文件</div>

<div>5. rd 删除文件夹</div>

<div>6. cd 文件名</div>

<!--向下找-->

<div>7. cd.. 文件名</div>

<div>8. show 输出当前节点</div>

<div>9.showdir</div>

<!--改变当前位置为父级继续找-->

</div>

<div id="btn-box">

<button id="btn">kick me</button>

<button id="showarray">show array</button>

<button id="showbackmap">show backmap</button>

<button id="showstruct">show struct</button>

</div>

<div>

<textarea name="" id="showtext" cols="30" rows="20"></textarea>

<textarea name="" id="text" cols="15" rows="8"></textarea>

</div>

<textarea name="" id="fattext" cols="30" rows="50"></textarea>

<script>

window.onload=function () {

//位示图定义

/*var tArray=new Array(); / / 先声明一维

for (var k=0; k < i; k++) { //一维长度为i,i为变量,可以根据实际情况改变

tArray[k]=new Array(); //声明二维,每一个一维数组里面的一个元素都是一个数组;

for (var j=0; j < p; j++) { //一维数组里面每个元素数组可以包含的数量p,p也是一个变量;

tArray[k][j]=""; //这里将变量初始化,我这边统一初始化为空,后面在用所需的值覆盖里面的值

}

}*/

var shuaxin=document.getElementById("shuaxin");

shuaxin.οnclick=function(){

location.reload();

}

var creatfile=0;

var backmap=new Array();

var bitmap1=new Array();

for (var i=0; i < 64; i++) {

backmap[i]=" ";

}

for (var i=0; i < 64; i++) {

bitmap1[i]=" ";

}

var useblock=new Array();

for (i=0; i < 64; i++) {

useblock[i]=" ";

}

var arr=new Array();

var wi=8, p=8;

for (var k=0; k < wi; k++) {

arr[k]=new Array();

for (var j=0; j < p; j++) {

arr[k][j]="";

}

}


function getrandom() {

for (i=0; i < 8; i++) {

for (j=0; j < 8; j++) {

var num=Math.random();

if (num > 0.5) {

arr[i][j]=1;

}

else {

arr[i][j]=0;

}

}

}


console.log(arr);

}

var showstruct=document.getElementById("showstruct");

showstruct.onclick=function () {

var text=document.getElementById("showtext");

var kin=0;

for (var i=0; i < 10; i++) {

if (docmessage.doc_name[i] !=="") {

kin=kin + 1;

}

console.log(docmessage.doc_name[i]);

}


console.log(kin);

if (kin===0) {

alert("当前的文件目录为空");

} else {

text.value="1.文件名2.文件层级3.文件大小4.文件父类5.文件创建顺序6.文件占据块数量"+"\n";

for (i=0; i < 10; i++) {

text.value=text.value + " " + docmessage.doc_name[i] + " " + docmessage.doc_state[i] + " " + docmessage.doc_memory[i] + " " + docmessage.doc_parents[i] + " " + docmessage.doc_creatfile[i] + " " + docmessage.doc_creatblock[i]+"\n"

}

}


}

var showarray=document.getElementById("showarray");

showarray.onclick=function () {

var text=document.getElementById("showtext");

for (i=0; i < 8; i++) {

for (j=0; j < 8; j++) {

text.value=text.value + " " + arr[i][j]

}

text.value=text.value + "\n";

}

console.log(arr);

}

var showbackmap=document.getElementById("showbackmap");

showbackmap.onclick=function () {//

var text=document.getElementById("showtext");

for (var i=0; i < 64; i++) {

text.value=text.value + " " + backmap[i] + "";

}

var kin=0;

for (var i=0; i < 64; i++) {

if (backmap[i] !=" ") {

kin=kin + 1;

}


}

if (kin===0) {

alert("当前的backmap还未生成");

}

console.log(backmap);

}

getrandom();

function setarr() {

var text=document.getElementById("text");

text.value=arr[0] + "\n" + arr[1] + "\n" + arr[2] + "\n" + arr[3] + "\n" + arr[4] + "\n" + arr[5] + "\n" + arr[6] + "\n" + arr[7];

}

setarr();

function getbitmap() {

var wnum=0

for (var i=0; i < 8; i++) {

for (var j=0; j < 8; j++) {

wnum=wnum + 1;

if (arr[i][j]==0) {

bitmap1[i * 8 + j]=0;

}

else {

bitmap1[i * 8 + j]=1;

}

}

}

}

getbitmap();

function setfat() {

var fat=document.getElementById("fattext");


for (i=0; i < 64; i++) {

fat.value=fat.value + "第" + i + "个位置的内存占用情况为" + bitmap1[i] + "\n";

//console.log(bitmap1[i]);

}

// console.log(fat.value);

}

var fat=document.getElementById("fattext");

//fat.value="第"+i+"个位置的内存占用情况为+"+bitmap1[i]+"\n";

setfat();


console.log(bitmap1);

//自定义构造函数

function nowdocmessage(state, parents, number, name) {

this.name=name;

this.state=state;

this.parents=parents;

this.number=number;

this.memory="";

this.creatfile=0;

}

var docmessage={

doc_name: Array(),

doc_state: Array(),

doc_parents: Array(),

doc_number: Array(),

doc_memory: Array(),

doc_creatfile: Array(),

doc_creatblock: Array(),

}

for (i=0; i < 10; i++) {

docmessage.doc_name[i]="";

docmessage.doc_memory[i]="";

docmessage.doc_number[i]="";

docmessage.doc_parents[i]="";

docmessage.doc_state[i]="";

docmessage.doc_creatfile[i]="";

docmessage.doc_creatblock[i]="";

}

var nowdoc=new nowdocmessage(0, -1, 0, "outside");

// nowdoc.memory=prompt("请输入您想要的文件大小");

//console.log("创建的文件大小为" + nowdoc.memory);

function isexist(state, name) {

// console.log(state,name);

for (i=0; i < 100; i++) {

//console.log(docmessage.doc_state[i],docmessage.doc_name[i]);

if (docmessage.doc_state[i]==state && docmessage.doc_name[i]==name) {

return false;

}

}

}

console.log("nowdoc.state" + nowdoc.state);

var btn=document.getElementById("btn");


// for (p=0; p <=2; p++) {

//btn.onclick=fun(nowdoc);

// }

k=0;

console.log(nowdoc);


btn.onclick=function fun(events) {


console.log("传进来的参数为" + nowdoc);

var keyword=prompt("请输入您想要进行的操作");

console.log(keyword);

if (keyword=="md") {//创建文件夹

var docname=prompt("请输入您想要的文件夹");

console.log("当前的state为" + nowdoc.state);

console.log("当前的number为" + nowdoc.number);

if (isexist(nowdoc.state, docname)==false) {

alert("this document is exist");

}

else {

alert("this document is not exist");

console.log("当前的state" + nowdoc.state);

console.log("当前的parents " + nowdoc.parents);

docmessage.doc_parents[k]=nowdoc.parents;

docmessage.doc_name[k]=docname;

docmessage.doc_memory[k]="";

docmessage.doc_state[k]=nowdoc.state;

docmessage.doc_number[k]=nowdoc.number;

console.log(docmessage);

k=k + 1;

alert("该文件夹创建成功");

nowdoc.number++;

}

}

if (keyword=="rd") {//删除文件夹

var rdname=prompt("请输入当前目录下您想要删除的文件夹名字");

for (var i=0; i < 10; i++) {

console.log("想要删除文件夹名字" + rdname);

console.log("doc父亲名字" + docmessage.doc_name[docmessage.doc_parents[i]]);

if (rdname=docmessage.doc_name[i]) {

console.log(docmessage.doc_parents[i]);

if (docmessage.doc_name[docmessage.doc_parents[i]]==rdname && docmessage.doc_memory !=" ") {

alert("该文件夹下有内容不能删除");

}

else {

docmessage.doc_name=" ";

docmessage.doc_memory=" ";

docmessage.doc_number=" ";

docmessage.doc_parents=" ";

docmessage.doc_state=" ";

}

}


}

}

if (keyword=="del") {

console.log("del");

var delname=prompt("请输入您想要删除的文件");

console.log("delname" + delname);

console.log(docmessage);

for (var i=0; i < 10; i++) {

console.log("docmessage.doc.name memory" + docmessage.doc_name[i], +docmessage.doc_memory[i]);

if (delname==docmessage.doc_name[i] && docmessage.doc_memory[i]==0) {

alert("该目录是文件夹");

}

if (delname==docmessage.doc_name[i] && docmessage.doc_memory[i] !=0) {

alert("进行删除操作");

var nodenumber=i;

var returnblock=docmessage.doc_creatblock[i] - 1;

var returnnumber=docmessage.doc_creatfile[i];

console.log(returnblock, returnnumber);

var sum=0;

for (var i=0; i < 10; i++) {

if (docmessage.doc_creatfile[i] < returnnumber) {

console.log(docmessage.doc_creatfile[i]);

sum=sum + docmessage.doc_creatfile[i] * docmessage.doc_creatblock[i];

}

}

console.log("sum" + sum);

for (var i=sum; i < sum + returnblock + 1; i++) {

var end=sum + returnblock;


console.log(backmap[i]);

console.log("返回数组的值为" + backmap);

var hang=parseInt(backmap[i] / 8);

var lie=backmap[i] - 8 * hang;

console.log(hang);

arr[hang][lie]=0;

bitmap1[backmap[i]]=0;

backmap[i]=" ";

setfat();

}

console.log(arr);

setarr();

console.log("nodenumber" + nodenumber);

docmessage.doc_creatblock[nodenumber]=" ";

docmessage.doc_creatfile[nodenumber]=" ";

docmessage.doc_memory[nodenumber]=" ";

docmessage.doc_name[nodenumber]=" ";

docmessage.doc_number[nodenumber]=" ";

docmessage.doc_parents[nodenumber]=" ";

docmessage.doc_state[nodenumber]=" ";

console.log("i的值为" + i);

console.log(docmessage);

}

}

alert("该文件删除完毕");

console.log("返回数组的值为" + backmap);

}

if (keyword=="mk") {//创建文件

creatfile=creatfile + 1;

var filename=prompt("请输入您想要创建的文件的名字");

var filememory=prompt("请输入您想要创建文件的大小");

docmessage.doc_parents[k]=nowdoc.state;

docmessage.doc_name[k]=filename;

docmessage.doc_memory[k]=filememory;

docmessage.doc_state[k]=nowdoc.state;

docmessage.doc_number[k]=nowdoc.number;//有两行赋值在下面

docmessage.doc_creatfile[k]=creatfile;


var n=filememory / 512;

var a=Math.round(n);

docmessage.doc_creatblock[k]=a;

console.log("需要的块数" + a);

for (var i=0; i < 8; i++) {

for (var j=0; j < 8; j++) {

if (arr[i][j]==0 && a !=0) {

arr[i][j]="1";

a=a - 1;

useblock[i * 8 + j]="1";

}

}

}

console.log(useblock);

console.log(arr);

setarr();

var fattext=document.getElementById("fattext");

/* for (var i=0; i < 8; i++) {

for (var j=0; j < 8; j++) {

if (useblock[i][j]==1) {

console.log(i,j);

var number=i * 8 + j;

c

}

}

}*/

for (var i=0; i < 64; i++) {

if (useblock[i]==1) {

console.log("useblock0" + useblock[0]);

console.log("i的值" + i);

fattext.value=fattext.value + "\n" + i;

for (var j=0; j < 64; j++) {

if (backmap[j]===" ") {

console.log(backmap[0]);

backmap[j]=i;///空默认等于零

break;

}

}

}

}

console.log(backmap)

fattext.value=fattext.value + "\n" + "该文件内存占用完毕" + "\n";

for (var i=0; i < 64; i++) {

useblock[i]=" ";

}

console.log("creatfile" + docmessage.doc_creatfile[k]);

console.log("creatblock" + docmessage.doc_creatblock[k]);

console.log(docmessage);

console.log(backmap);


k=k + 1;

}

if (keyword=="cd") //切换

{

var choosename=prompt("请输入您想要选择的文件夹");

console.log("测试数据");


for (var i=0; i < 10; i++) {

console.log(choosename + " " + docmessage.doc_name[i]);

console.log(docmessage.doc_state[i] + " " + nowdoc.state);

if (docmessage.doc_name[i]==choosename && docmessage.doc_state[i]==nowdoc.state) {

nowdoc.state=docmessage.doc_state[i] + 1;

nowdoc.parents=i;

nowdoc.name=docmessage.doc_name[i];

nowdoc.number=docmessage.doc_number[i]

}

}

}

if (keyword=="cd..") {

alert("已返回上一级文件夹 ");

for (var i=0; i < 10; i++) {

if (nowdoc.parents==i) {

nowdoc.parents=docmessage.doc_parents[i];

nowdoc.name=docmessage.doc_name[i];

nowdoc.number=docmessage.doc_number[i];

nowdoc.state=docmessage.doc_state[i];

}

}

console.log(docmessage);

}

if (keyword=="showdir") {//显示全部文件夹

console.log("文件名 文件阶段 文件大小")

console.log(docmessage.doc_name);

var text=document.getElementById("showtext");

text.value="文件名 文件阶段 文件大小\n";

for (var i=0; i < 10; i++) {

if (docmessage.doc_name[i] !=" ") {

console.log(docmessage.doc_name[i] + " " + docmessage.doc_state[i] + " " + docmessage.doc_memory[i]);

text.value=text.value+" "+docmessage.doc_name[i] + " " + docmessage.doc_state[i] + " " + docmessage.doc_memory[i]+"\n";

}

}

}

if (keyword=="dir") {//显示当前路径的文件

console.log("文件名 文件阶段 文件大小")

var text=document.getElementById("showtext");

text.value="文件名 文件阶段 文件大小\n";

for (var i=0; i < 10; i++) {

if (nowdoc.state==docmessage.doc_state[i]) {

console.log(docmessage.doc_name[i] + " " + docmessage.doc_state[i] + " " + docmessage.doc_memory[i]);

text.value=text.value+" "+docmessage.doc_name[i] + " " + docmessage.doc_state[i] + " " + docmessage.doc_memory[i]+"\n";

}

}

}

if (keyword="show")//显示当前节点

{

console.log("当前节点名字" + nowdoc.name);

console.log("当前节点阶段" + nowdoc.state);

console.log("当前节点数字" + nowdoc.number);

console.log("当前节点父亲" + nowdoc.parents);

}


console.log("btn按钮执行完毕");

}


}

</script>

</body>


</html>