Android中WebView的互動細節天氣視覺化Demo實戰

2020-09-28 09:10:24

Android使用WebView互動

Android使用webView細節



前言

android中使用WebView細節繁多,特此記錄一個天氣視覺化折線圖,android端使用WebView載入前端H5頁面,視覺化工具使用Echarts ,api使用聚合天氣


一、android端與WebView互動

1.android呼叫前端方法

編寫佈局 ProgressBar為進度條,可省略

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ProgressBar
        android:layout_width="match_parent"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:id="@+id/chart_bar"
        android:layout_height="10dp"/>
<WebView
    android:layout_width="match_parent"
    android:id="@+id/fragment_webview"
    android:layout_height="match_parent"/>

</LinearLayout>

H5中編寫一個測試方法供android端呼叫

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
</body>
<script>

      /* 無參呼叫 */
    function notParamFun() {
        alert("網頁方法被呼叫");
    }
    
    /* 有參呼叫 */
    function haveParamtestFun(data) {
        alert("接收到android端的資料:" + data);
    }
</script>
</html>

注意:編寫好的HTML網頁需要放入android 專案中的assets中,assets需要手動新建。
在這裡插入圖片描述


android 中java程式碼,注意loadUrl中是asset,且傳送資料必須等待網頁載入完(newProgress =100)才能進行互動並且只能傳輸字串形式。
且需要加入單引號

 	private ProgressBar chartBar;
    private WebView fragmentWebview;
    
   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
         chartBar = (ProgressBar) view.findViewById(R.id.chart_bar);
        fragmentWebview = (WebView) view.findViewById(R.id.fragment_webview);


        /*前端介面*/
        fragmentWebview.addJavascriptInterface(this, "myWebView");
        fragmentWebview.loadUrl("file:///android_asset/myWebView.html");
        fragmentWebview.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
//                 當進度達到100時呼叫H5介面
                if (newProgress == 100) {
                       fragmentWebview.loadUrl("javascript:notParamFun()");
                    fragmentWebview.loadUrl("javascript:haveParamtestFun('"+ "傳送String資料" +"')");
                    chartBar.setVisibility(View.GONE);

                } else {
                    chartBar.setVisibility(View.VISIBLE);
                    chartBar.setProgress(newProgress);
                }
            }

        });
    }
        /*前端呼叫的介面方法*/
    @JavascriptInterface
    public void getData(String title) {
        new AlertDialog.Builder(getContext())
                .setTitle(title)
                .setMessage("前端呼叫")
                .setPositiveButton("OK", null)
                .create()
                .show();

    }

在這裡插入圖片描述
在這裡插入圖片描述

2. 前端H5呼叫android方法

在android已經寫好網頁端呼叫介面物件myWebView,且有一個共前端呼叫的方法為getData

        /*前端介面物件*/
fragmentWebview.addJavascriptInterface(this, "myWebView");

    /*前端呼叫的介面方法*/
    @JavascriptInterface
    public void getData(String title) {
        new AlertDialog.Builder(getContext())
                .setTitle(title)
                .setMessage("前端呼叫")
                .setPositiveButton("OK", null)
                .create()
                .show();

    }

只需在前端加入一行呼叫程式碼

<script>
//呼叫android方法,無參也需要寫上()
javascript: myWebView.getData("我是前端的title");
  /* 無參呼叫 */
    function notParamFun() {
        alert("網頁方法被呼叫");
    }

    /* 有參呼叫 */
    function haveParamtestFun(data) {
        alert("接收到android端的資料:" + data);
    }
    
</script>

儲存重新啟動模擬器
在這裡插入圖片描述

二、編寫寫天氣視覺化Demo

1、前端引入Echarts,編寫前端佈局

注意:stack加上會有堆疊顯示問題,最後去掉stack解決堆疊問題

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.staticfile.org/echarts/4.7.0/echarts.min.js"></script>

</head>

<body>
    <div id="myChartPie" style="width: 100%; height: 400px; "></div>
    <div></div>
</body>
<script>
    var echartsPie = echarts.init(document.getElementById("myChartPie"));
    var option = {
        title: {
            text: '武漢天氣預報'
        },
        tooltip: {
            trigger: 'axis'
        },
        legend: {
            data: ['最低溫度', '最高溫度']
        },
        grid: {
            left: '3%',
            right: '4%',
            bottom: '3%',
            containLabel: true
        },
        toolbox: {
            feature: {
                saveAsImage: {}
            }
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            data: [],

        },
        yAxis: {
            type: 'value'
        },
        series: [{
                name: '最低溫度',
                type: 'line',
                data: [],
                itemStyle: {
                    normal: {
                        color: 'black',
                        borderColor: 'black', //拐點邊框顏色
                    }
                },
            }, {
                name: '最高溫度',
                type: 'line',
                data: [],
                itemStyle: {
                    normal: {
                        color: 'red',
                        borderColor: 'red', //拐點邊框顏色
                    }
                },
            }

        ]
    };
    echartsPie.setOption(option);


    function javacalljs(data) {
        /* 將JSON資料轉換為物件 */
        data = JSON.parse(data);
        var weather = data.result.future;
        //時間陣列
        var dateArr = [];
        //最低氣溫陣列
        var temLowerArr = [];
        //最高氣溫陣列
        var temHightArr = [];
        //迴圈遍歷新增資料
        weather.forEach(function(item) {
            var tem = item.temperature.toString().replace("℃", "").split("/");
            dateArr.push(item.date);
            temLowerArr.push(tem[0]);
            temHightArr.push(tem[1]);

        });
        option.xAxis.data = dateArr;
        option.series[0].data = temLowerArr;
        option.series[1].data = temHightArr;
		//最後要更新圖表
        echartsPie.setOption(option);
    }

</script>

</html>

2.android 端編寫佈局及互動程式碼

佈局仍然使用上次的xml檔案

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ProgressBar
        android:layout_width="match_parent"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:id="@+id/chart_bar"
        android:layout_height="10dp"/>
<WebView
    android:layout_width="match_parent"
    android:id="@+id/fragment_webview"
    android:layout_height="match_parent"/>

</LinearLayout>

java 互動程式碼,api選用聚合天氣api,網路框架使用OKHttp



    private ProgressBar chartBar;
    private WebView fragmentWebview;
	private String apiData = "";
	//請求聚合天氣API的url
   private final String url = "http://apis.juhe.cn/simpleWeather/query";
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        chartBar = (ProgressBar) view.findViewById(R.id.chart_bar);
        fragmentWebview = (WebView) view.findViewById(R.id.fragment_webview);
         RequestBody body =new FormBody.Builder()
                .add("key", "你申請的key")
                .add("city", "武漢")
                .build();
                    
 OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder()
                    .url(url)
                    .post(body)
                    .build();



        client.newCall(request).enqueue(new Callback() {
            /*請求失敗時的回撥*/
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e("onFailure: ", e.getMessage());
            }
            /*請求成功時的回撥*/
            @Override
            public void onResponse(Call call, Response response) throws IOException {
					apiData = response.body().string();
            }
        });
		
        fragmentWebview.loadUrl("file:///android_asset/myWebView.html");
        fragmentWebview.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
			// 當進度達到100時傳送資料
                if (newProgress == 100) {
                    fragmentWebview.loadUrl("javascript:javacalljs('"+ apiData +"')");

                    chartBar.setVisibility(View.GONE);

                } else {
                    chartBar.setVisibility(View.VISIBLE);
                    chartBar.setProgress(newProgress);
                }
            }

        });
        
    }

在這裡插入圖片描述