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中,然后產生一系列的交互
常用的交互方式
這里以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>
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>
*請認真填寫需求信息,我們會在24小時內與您取得聯系。