Android开发中WebView与原生JS的数据交互详解

 更新时间:2016年9月20日 19:57  点击:2280
分本文来分享详细的在Android开发中,如何利用WebView与原生JS的数据交互,本教程附有代码和效果图,是一个不可多得的好教程。

关于WebView

我们知道目前android市场上的一些应用采用的开发方式大致分为三种:Native App、Web App、Hybrid App。本文主要是Hybrid App中实现的主要技术native组件与js的数据交互的理解以及实现。

Android API中提供了WebView组件来实现对html的渲染。所谓的HybridApp开发方式即是汇集了HTML5、CSS3、jS的相关开发技术,以及数据交换格式json/XML。这显然是Web开发工程师的技能。正是因为如此,众多中小企业选择了这种开发方式来减少对android开发工程师的过度依赖,至于这三种开发方式的比较与优劣不在本文考虑之列。

有了WebView这个组件,Android应用开发技术也就转嫁到html与java数据交互上来。说白了就是js与WebView的数据交互,这就是本文所要讨论的。


WebView与js的数据交互

1.        WebView中载入静态页面

 
将WebView添加到应用中。和原生控件一样,在layout引入WebView控件。代码片段如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000"
    android:orientation="horizontal" >
<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />
</LinearLayout>

载入页面:

 

webView = (WebView) findViewById(R.id.webview);
webView.loadUrl("file:///file:///android_asset/page.html");

page.html存储在工程文件的assets根目录下。

2.        引入jquery mobile

引入js框架让我们编写的html页面更接近于原生控件的显示效果。目前主流的移动应用js框架有:jquery mobile和sencha touch(jquery mobile与sencha touch的选型不在本文讨论范围)。本文选择使用jquery mobile。

 

首先,在webview添加对js的支持:

WebSettings setting = webView.getSettings();
setting.setJavaScriptEnabled(true);//支持js

增加对中文的支持:

WebSettings setting = webView.getSettings();
setting.setDefaultTextEncodingName("GBK");//设置字符编码

设置页面滚动条风格:

webView.setScrollBarStyle(0);//滚动条风格,为0指滚动条不占用空间,直接覆盖在网页上

jquery mobile提供的标准页面模板TemplateForJQuery.html:

<!DOCTYPE html>
<html>
    <head>
    <title>Page Title</title>
    
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" href="css/jquery.mobile-1.1.1.min.css" />
    <script src="js/jquery.js"></script>
    <script src="js/jquery.mobile-1.1.1.min.js"></script>
</head>
<body>

<div data-role="page">

    <div data-role="header">
        <h1>Page Title</h1>
    </div><!-- /header -->

    <div data-role="content">    
        <p>Page content goes here.</p>        
    </div><!-- /content -->

    <div data-role="footer">
        <h4>Page Footer</h4>
    </div><!-- /footer -->
</div><!-- /page -->

</body>
</html>

页面依赖的js库、css等均放在assets目录下,目录组织结构如下:



运行应用后的截图:


下面是button 的截图,与原生控件没什么明显区别,有种以假乱真的感觉:


3.        良好的用户体验

运行我们的应用发现,在拥有大量js的页面被载入时,一直处于等待中,这是很糟糕的用户体验。可以加入进度条解决。注意到webview提供的两个方法:setWebViewClient和setWebChromeClient。其中setWebChromeClient方法正是可以处理progress的加载,此外,还可以处理js对话框,在webview中显示icon图标等。对于处理progress的代码片段如下:

webView.setWebChromeClient(new WebChromeClient() {
    public void onProgressChanged(WebView view, int progress) {// 载入进度改变而触发
            if (progress == 100) {
                    handler.sendEmptyMessage(1);// 如果全部载入,隐藏进度对话框
            }
                super.onProgressChanged(view, progress);
        }
});

其中通过handler 消息机制来处理UI线程的更新:

 

        handler = new Handler() {
            public void handleMessage(Message msg) {// 定义一个Handler,用于处理下载线程与UI间通讯
                if (!Thread.currentThread().isInterrupted()){
                    switch (msg.what) {
                    case 0:
                        pd.show();// 显示进度对话框
                        break;
                    case 1:
                        pd.hide();// 隐藏进度对话框,不可使用dismiss()、cancel(),否则再次调用show()时,显示的对话框小圆圈不会动。
                        break;
                    }
                }
                super.handleMessage(msg);
            }
        };

对于setWebViewClient方法,一般用来处理html的加载(需要重载onPageStarted(WebView view, String url, Bitmap favicon))、关闭(需要重载onPageFinished(WebViewview, String url)方法)。

 

setWebViewClient和setWebChromeClient的作用:前者主要用于处理webView的控制问题,如加载、关闭、错误处理等;后者主要处理js对话框、图标、页面标题等。

4.        获取java中的数据

单独构建一个接口,作为处理js与java的数据交互的桥梁,本文封装的代码AndroidToastForJs.java如下:

public class AndroidToastForJs {
    
    private Context mContext;

public AndroidToastForJs(Context context){
        this.mContext = context;
    }
    
//webview中调用toast原生组件
public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
    
//webview中求和
public int sum(int a,int b){
        return a+b;
    }
    
 //以json实现webview与js之间的数据交互
public String jsontohtml(){
        JSONObject map;
        JSONArray array = new JSONArray();
        try {
            map = new JSONObject();
            map.put("name","aaron");
            map.put("age", 25);
            map.put("address", "中国上海");
            array.put(map);
            
            map = new JSONObject();
            map.put("name","jacky");
            map.put("age", 22);
            map.put("address", "中国北京");
            array.put(map);
            
            map = new JSONObject();
            map.put("name","vans");
            map.put("age", 26);
            map.put("address", "中国深圳");
            map.put("phone","13888888888");
            array.put(map);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return array.toString();
    }
}


 

Webview提供的传入js的方法:

webView.addJavascriptInterface(new AndroidToastForJs(mContext), "JavaScriptInterface");

Html页面jsonData.html设计的部分代码如下:

    <script type="text/javascript">
    var result = JavaScriptInterface.jsontohtml();
    var obj = eval("("+result+")");//解析json字符串
    function showAndroidToast(toast)
    {        
        JavaScriptInterface.showToast(toast);
    }
    function getjsonData(){
        var result = JavaScriptInterface.jsontohtml();
        var obj = eval("("+result+")");//解析json字符串
        for(i=0;i<obj.length;i++){
            var user=obj[i];
            document.write("<p>姓名:"+user.name+"</p>");
            document.write("<p>年龄:"+user.age+"</p>");
            document.write("<p>地址:"+user.address+"</p>");
            if(user.phone!=null){
                document.write("<p>手机号码:"+user.address+"</p>");
            }
        }
    }    
    function list(){
        document.write("<div data-role='header'><p>another</p></div>");
    }
    </script>
</head>
<body>
<div data-role="page" >
    <div data-role="header" data-theme="c">
        <h1>Android via Interface</h1>
    </div><!-- /header -->
    <div data-role="content">    
        <button value="say hello" onclick="showAndroidToast('Hello,Android!')" data-theme="e"></button>
        <button value="get json data" onclick="getjsonData()" data-theme="e"></button>    
    </div><!-- /content -->
<div data-role="collapsible" data-theme="c" data-content-theme="f">
   <h3>I'm <script>document.write(obj[0].name);</script>,click to see my info</h3>
   <p><script>document.write("<p>姓名:"+obj[0].name+"</p>");</script></p>
   <p><script>document.write("<p>年龄:"+obj[0].age+"</p>");</script></p>
   <p><script>document.write("<p>地址:"+obj[0].address+"</p>");</script></p>
</div>
    <div data-role="footer" data-theme="c">
        <h4>Page Footer</h4>
    </div><!-- /footer -->
</div><!-- /page -->
</body>

点击say hello按钮运行的截图如下:




另外一篇关于webview与js交互

对于android初学者应该都了解webView这个组件。之前我也是对其进行了一些简单的了解,但是在一个项目中不得不用webview的时候,发现了webview的强大之处,今天就分享一下使用webview的一些经验。

 
1、首先了解一下webview。

webview介绍的原文如下:A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more.

从上面你应该了解到了基本功能,也就是显示网页。之所以我说webview功能强大是因为它和js的交互非常方便,很简单就可以实现。

 

2、webview能做什么?

①webView可以利用html做界面布局,虽然目前还比较少人这么使用,不过我相信当一些客户端需要复杂的图文(图文都是动态生成)混排的时候它肯定是个不错的选择。

②直接显示网页,这功能当然也是它最基本的功能。

③和js交互。(如果你的js基础比java基础好的话那么采用这种方式做一些复杂的处理是个不错的选择)。

 

3、如何使用webview?

这里直接用一个svn上取下的demo,先上demo后讲解。demo的结构图如下:

 
WebViewDemo.java

package com.google.android.webviewdemo;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;

/**
 * Demonstrates how to embed a WebView in your activity. Also demonstrates how
 * to have javascript in the WebView call into the activity, and how the activity
 * can invoke javascript.
 * <p>
 * In this example, clicking on the android in the WebView will result in a call into
 * the activities code in {@link DemoJavaScriptInterface#clickOnAndroid()}. This code
 * will turn around and invoke javascript using the {@link WebView#loadUrl(String)}
 * method.
 * <p>
 * Obviously all of this could have been accomplished without calling into the activity
 * and then back into javascript, but this code is intended to show how to set up the
 * code paths for this sort of communication.
 *
 */
public class WebViewDemo extends Activity {

    private static final String LOG_TAG = "WebViewDemo";

    private WebView mWebView;

    private Handler mHandler = new Handler();

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        mWebView = (WebView) findViewById(R.id.webview);

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setSavePassword(false);
        webSettings.setSaveFormData(false);
        webSettings.setJavaScriptEnabled(true);
        webSettings.setSupportZoom(false);

        mWebView.setWebChromeClient(new MyWebChromeClient());

        mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");

        mWebView.loadUrl("file:///android_asset/demo.html");
    }

    final class DemoJavaScriptInterface {

        DemoJavaScriptInterface() {
        }

        /**
         * This is not called on the UI thread. Post a runnable to invoke
         * loadUrl on the UI thread.
         */
        public void clickOnAndroid() {
            mHandler.post(new Runnable() {
                public void run() {
                    mWebView.loadUrl("javascript:wave()");
                }
            });

        }
    }

    /**
     * Provides a hook for calling "alert" from javascript. Useful for
     * debugging your javascript.
     */
    final class MyWebChromeClient extends WebChromeClient {
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            Log.d(LOG_TAG, message);
            result.confirm();
            return true;
        }
    }
}

 

demo.html

<html>
    <script language="javascript">
        /* This function is invoked by the activity */
        function wave() {
            alert("1");
            document.getElementById("droid").src="android_waving.png";
            alert("2");
        }
    </script>
    <body>
        <!-- Calls into the javascript interface for the activity -->
        <a onClick="window.demo.clickOnAndroid()"><div style="width:80px;
            margin:0px auto;
            padding:10px;
            text-align:center;
            border:2px solid #202020;" >
                <img id="droid" src="android_normal.png"/><br>
                Click me!
        </div></a>
    </body>
</html>

 

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
    <TextView  
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/intro"
        android:padding="4dip"
        android:textSize="16sp"
        />
    
    <WebView
        android:id="@+id/webview"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        />
        
</LinearLayout>

 

4、如何交互?

①android如何调用js。

调用 形式:

mWebView.loadUrl("javascript:wave()");

其中wave()是js中的一个方法,当然你可以把这个方法改成其他的方法,也就是android调用其他的方法。

②js如何调用android。

调用形式:

<a onClick="window.demo.clickOnAndroid()">

代码中的“demo”是在android中指定的调用名称,即

 mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");

代码中的clickOnAndroid()是“demo”对应的对象:new DemoJavaScriptInterface() 中的一个方法。

③双向交互。

当然是把前面的两种方式组合一下就可以了。

 

5、讲解demo。

现在你一定了解了android和js的交互了。是时候分析一些demo了,根据上面讲的你也应该比较清楚了。具体交互流程如下:

①点击图片,则在js端直接调用android上的方法clickOnAndroid();

②clickOnAndroid()方法(利用线程)调用js的方法。

③被②调用的js直接控制html。

 

个人总结:利用webView的这种方式在有些时候UI布局就可以转成相应的html代码编写了,而html布局样式之类有DW这样强大的工具,而且网上很多源码,很多代码片。在UI和视觉效果上就会节省很多时间,重复发明轮子没有任何意义。

本文我们来分享一批Android开发中最常用的组件下载地址及使用说明,都是开源免费的,绝对的干货。

了解常见的开源项目,可以扩大我们的视野,知道有哪些可以利用的资源,对于我们平常的设计和开发很有好处

UI相关

  • 图片

    • ps://github.com/nostra13/Android-Universal-Image-Loader" target="_blank">Android-Universal-Image-Loader:com.nostra13.universalimageloader:异步加载、缓存、显示图片

    • ImageLoader:com.novoda.imageloader:异步加载、缓存、显示图片

    • picasso:com.squareup.picasso:功能强大的图片下载缓存库

    • PhotoView:uk\co\senab\photoview:支持缩放和各种手势的ImageView

  • ListView

    • JazzyListView:com.twotoasters.jazzylistview:扩展的ListView,当列表项目在屏幕上可见时产生动画效果

    • StickyListHeaders:com.emilsjolander.components.stickylistheaders:在ListView中置顶

    • ListViewAnimations:com.haarman.listviewanimations:带动画的ListView

    • drag-sort-listview:拖拽排序ListView的元素

    • android-swipelistview:让listview的item可以向右滑动

  • 下拉刷新

    • Android-PullToRefresh:com.handmark.pulltorefresh:下拉刷新组件

    • android-pulltorefresh:下拉刷新组件

  • 菜单

    • SlidingMenu:com.jeremyfeinstein.slidingmenu:滑动菜单

    • MenuDrawer:滑动菜单组件

  • Action Bar

    • ActionBarSherlock:com.actionbarsherlock:Action Bar组件

    • android-actionbar:Action Bar组件

    • GlassActionBar:玻璃效果的Action Bar

  • ViewPager

    • Android-ViewPagerIndicator:com.viewpagerindicator:分页显示组件

    • PagerSlidingTabStrip:com.astuetz.viewpager:页面滑动组件

    • JazzyViewPager:可自定义动画的ViewPager

  • 兼容

    • NineOldAndroids:com.nineoldandroids:移植Honeycomb版本的动画API到旧版本上

    • HoloEverywhere:移植Android 4.1的Holo主题到旧的版本上

    • GlowPadBackport:GlowPadBackport:移植Android 4.2 GlowPadView到旧版本上

    • android-switch-backport::移植Android 4的Switch widget到旧版本上

  • AChartEngine:org.achartengine:Android上的绘图库

  • android-viewflow:com.taptwo.android.widget:视图切换的效果

  • android-flip:翻页动画组件

  • Android-AppMsg::In-layout notifications

  • android-wheel:kankan.wheel:Android滚动控件

  • Android-ProgressFragment:等待数据的时候,支持显示等待符号的Fragment控件

  • StaggeredGridView:瀑布流GridView布局

  • Cards-UI:卡片布局

  • cardslib:卡片布局

WebApp

  • Cordova:org.apache.cordova:Cordova是PhoneGap贡献给Apache后的开源项目,是从PhoneGap中抽出的核心代码

  • HtmlSpanner:net.nightwhistler.htmlspanner:Android上的网页渲染库,可渲染CSS

  • ChromeView:Chrome内核移植的WebView

推送

  • 个推:com.igexin:手机推送服务

  • JPush:???:极光推送

  • 百度推送:com.baidu.android.pushservice:百度推送服务

  • MQTT:ibm.mqtt:MQTT协议,似乎和推送有关系

语音识别

  • 讯飞SDK:com.iflytek:科大讯飞语音SDK

  • 百度语音识别:com.baidu.voicerecognition:百度语音识别SDK

  • mobvoi:com.mobvoi:移动语音搜索

  • 云知声:cn.yunzhisheng:云知声语音处理

音频视频图像

  • CC视频:com.bokecc:视频云平台

  • Vitamio:io.vov.vitamio:多媒体开发框架

  • leptonica:com.googlecode.leptonica:图像处理库

  • tesseract-ocr:com.googlecode.tesseract:图像OCR库

  • aacdecoder-android:com.spoledge.aacdecoder:Android上的Audio (AAC) 解码器

地图定位

  • 百度定位:com.baidu.location:百度地图SDK

  • 百度地图:com.baidu.mapapi:百度地图SDK

  • amap:com.amap.api,com.autonavi:高德地图API

  • 图吧SDK:com.mapbar:图吧地图API

  • MapABC:com.mapabc:MapABC地图SDK

广告平台

  • 友盟SDK:com.umeng:友盟统计、自动更新、用户反馈、社会化组件

  • 多盟:cn.domob:多盟平台

  • 百度移动联盟:com.baidu.mobads:百度移动联盟

  • google ads:com.google.ads:google广告

  • AdChina:com.adchina:易传媒广告平台

  • AdsMogo:com.adsmogo:芒果移动广告平台

  • Adwo:com.adwo:安沃移动广告平台

  • mobisage:com.mobisage:艾德思奇移动广告平台

  • Miaozhen:com.miaozhen:秒针第三方广告平台

  • AdMaster:cn.com.admaster:admaster广告平台

  • 易积分:com.qiang.escore:易积分移动广告平台

  • inmobi:com.inmobi:国外的广告平台

  • 点信传媒:cn.dx:广告平台

统计分析

  • Flurry:com.flurry:国外流行的统计工具

  • 百度移动统计:com.baidu.mobstat:百度开发者中心

  • Cobub Razor:com.wbtech.ums:移动统计分析工具

  • google analytics:com.google.analytics:google统计

  • lotuseed:com.lotuseed:莲子统计

  • Localytics:com.localytics.android:国外统计分析工具

  • comscore:com.comscore:国外的统计工具

网络通信

  • volley:com.android.volley:Android网络通信库

  • Apache Thrift:com.apache.thrift:远程服务调用框架

  • Netty:org.jboss.netty:异步事件驱动的网络应用程序框架

Http访问

  • Apache HttpClient:org.apache.http

  • android-async-http:com.loopj:异步Http库

  • async-http-client:异步Http和WebSocket库

  • OkHttp:实现了Google开发的SPDY协议,更快的网络传输和加载速度

XMPP协议

  • smack:org.jivesoftware.smack:XMPP客户端类库

  • Jbosh:com.kenai.jbosh:XMPP BOSH规范的Java实现

应用授权

  • Scribe:org.scribe:简单的OAuth认证

  • QQ互联:com.tencent.tauth:QQ互联

  • 百度授权:com.baidu.oauth:百度应用授权

  • weibo授权:com.sina.sso:新浪微博应用授权

社交分享

  • ShareSDK:cn.sharesdk:App分享库

  • facebook-android-sdk:com.facebook:Facebook SDK

  • 腾讯微信:com.tencent.mm:腾讯微信SDK

  • 腾讯微博:com.tencent.weibo:腾讯微博SDK

  • weiboSDK:com.weibo.sdk:新浪微博SDK

  • qweibo:com.mime.qweibo:Q版微博

  • t4j:t4j:网易微博开放平台

  • yixin:im.yixin:易信开放平台

  • 人人SDK:com.renren.api:人人网SDK

  • 翼聊:com.yiliao.android:中国电信天翼开放平台

  • evernote:com.evernote:Evernote API

  • 有道云笔记SDK:com.youdao.note:有道云笔记SDK

移动支付

  • alipay:com.alipay:支付宝

  • tenpay:com.tenpay:QQ财付通

  • umpay:com.umpay:联动优势支付平台

  • 银联支付:com.unionpay:中国银联手机支付平台

  • MMBilling:mm.purchasesdk:中国移动应用内计费SDK

Data解析

  • dom4j:org.dom4j:XML解析库

  • xmlpull:org.xmlpull.v1:XML解析器,Android自带

  • FastJSON:com.alibaba.fastjson:JSON解析器

  • Sparta:com.hp.hpl.sparta:XML、DOM、XPath解析器

  • jsoup:org.jsoup:HTML解析器

  • osbcp-css-parser:com.osbcp.cssparser:CSS解析器

  • HtmlCleaner:org.htmlcleaner:Html清洗解析库

  • Mime4J:org.apache.james.mime4j:MIME邮件格式解析器

序列化

  • google-gson:com.google.gson:序列化反序列化Java对象成Json数据

  • Jackson:org.codehaus.jackson:序列化反序列化Java对象成Json数据

ORM

  • OrmLite:com.j256.ormlite:Java ORM库

  • greenDAO:Android ORM for SQLite

  • AndrOrm:An ORM for Android

网盘

  • PCS:com.baidu.pcs:百度个人云存储

  • vdisk:com.vdisk:微盘开放平台

  • 金山快盘:com.kuaipan:金山快盘开放平台

异常收集分析

  • acra:org.acra:Application Crash Reports for Android

  • Crittercism:com.crittercism:为开发者提供分析诊断应用崩溃的原因

服务器

  • SwiFTP:org.swiftp:Android平台的FTP服务器

  • android-webserver:com.bolutions.webserver:Android平台的Web服务器

Event Bus

  • EventBus:de.greenrobot.event:an Android optimized publish/subscribe event bus

  • otto:基于Guav的Event Bus

Dependency Injection

  • RoboGuice:roboguice:Android平台的Dependency Injection框架

  • roboguice-sherlock:com.github.rtyley:使用RoboGuice实现的ActionBarSherlock

  • Google Guice:com.google.inject:Dependency Injection框架

图标资源

  • Androton-Action-Bar-Icons:一个针对Android 优化过的ICON图标集

  • http://iconsparadise.com/

  • http://iconbench.com/

  • http://www.androidicons.com/

  • https://code.google.com/p/android-ui-utils/

其他组件

  • android-query:com.androidquery:异步任务和操作UI元素

  • ZXing:com.google.zxing:条形码和二维码生成和解码库

  • pinyin4j:net.sourceforge.pinyin4j:中文和拼音转换

  • protobuf:com.google.protobuf:protobuf

  • JZlib:com.jcraft.jzlib:Java实现的zlib库

  • zt-zip:压缩解压库

  • aFileChooser:???:文件浏览器

  • image-chooser-library:???:图片和视频的选择库

  • TOML::跨语言的配置信息存取方案

  • OpenUDID:org.openudid:通用且持久的Unique Device IDentifier (UDID)解决方案

  • Parse:com.parse:各种很棒的后台服务

  • Codec:org.apache.codec:字符串编码解码库

  • jChardet:org.mozilla.intl.chardet:自动检测字符集

  • JRegex:jregex:正则表达式库

  • SQLCipher:info.guardianproject.database:Android数据库加密

  • xiaomi:com.xiaomi:小米开发者平台:推送服务、自动更新、自动发布等

  • DataDroid::以RESTful方式管理数据

  • Afinal::SQLITE的ORM和IOC框架,同时封装了android中的http框架

  • AndroidCommon:Android常用的一些库和功能,如缓存,下拉列表,下载管理,静默安装等

  • ThinkAndroid::Android整体框架:集成了ioc,orm,下载,缓存等模块,能让开发更加快速和高效

不常用组件

  • dnsjava:org.xbill.dns:域名解析

  • sasl:com.novell.sasl.client:sasl认证机制

  • LuaJava:org.keplerproject.luajava:Java嵌入Lua

  • PJSIP:org.pjsip.pjsua:PJSUA是一个开源的命令行SIP用户代理(软电话),用PJSIP协议,PJNATH,和PJMEDIA实现




UI框架

  • GreenDroid

  • Bearded-Hen/Android-Bootstrap

  • donnfelker/android-bootstrap

游戏引擎

  • cocos2d-x

  • libgdx

  • AndEngine

  • MonoGame

其他组件

  • skrollr:视差滚动Javascript引擎

  • androidannotations:扩展Android注解语言

  • android_guides:学习Android和iOs

  • phonegap:WebApp开发引擎


本文我们来讲讲在eclipse开发工具中将android工程生成可安装的apk文件的图文步骤教程,学习android开发的朋友可以参考一下。

eclipse生成andoid安装文件apk的图文步骤如下

1.)生成keystore

按照下面的命令行 在C:\Program Files\Java\jdk1.6.0_10\bin>目录下,输入keytool -genkey -alias android.keystore -keyalg RSA -validity 100000 -keystore android.keystore

参数意义:-validity主要是证书的有效期,写100000天;空格,退格键 都算密码。

命令执行后会在C:\Program Files\Java\jdk1.6.0_10\bin>目录下生成 android.keystore文件。如图-1

 

\

图-1命令行下生成android.keystore

2.)eclipse生成apk文件

选择要打包的项目,右键点击–>Android tools–>Export Signed Application Package…如图-2

 

\

图-2 eclipse 打包工具

接下来的步骤就是不断的next。下面仅贴出图片,不解释。

 

\

step 2:选择打包的项目

 

\

step 3: 选择生成的android.keystore文件并输入密码

 

\

step 4:选择alias key并输入密码

 

\

step 5:最后选择生成android apk文件的目录及文件名

 

\

最终生成的apk文件

以下是本人如何关闭整个Android应用程序呢总结的几种比较简单的实现方法,后面附了一个详细的例子源码。

1. Dalvik VM的本地方法

  android.os.Process.killProcess(android.os.Process.myPid())    //获取PID
  System.exit(0);   //常规java、c#的标准退出法,返回值为0代表正常退出

 

2. 任务管理器方法

   首先要说明该方法运行在Android 1.5 API Level为3以上才可以,同时需要权限

  ActivityManager am = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
  am.restartPackage(getPackageName());
  系统会将,该包下的 ,所有进程,服务,全部杀掉,就可以杀干净了,要注意加上
  <uses-permission android:name=\"android.permission.RESTART_PACKAGES\"></uses-permission>

3. 根据Activity的声明周期

我们知道Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志     Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。

在A窗口中使用下面的代码调用B窗口

Intent intent = new Intent();
intent.setClass(Android123.this, CWJ.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  //注意本行的FLAG设置
startActivity(intent);

接下来在B窗口中需要退出时直接使用finish方法即可全部退出。

 

4.自定义一个Actiivty 栈,道理同上,不过利用一个单例模式的Activity栈来管理所有Activity。并提供退出所有Activity的方法。代码如下:

   public class ScreenManager {
 private static Stack<Activity> activityStack;
 private static ScreenManager instance;
 private  ScreenManager(){
 }
 public static ScreenManager getScreenManager(){
  if(instance==null){
   instance=new ScreenManager();
  }
  return instance;
 }
//退出栈顶Activity
 public void popActivity(Activity activity){
  if(activity!=null){
   activity.finish();
   activityStack.remove(activity);
   activity=null;
  }
 }

//获得当前栈顶Activity
 public Activity currentActivity(){
  Activity activity=activityStack.lastElement();
  return activity;
 }

//将当前Activity推入栈中
 public void pushActivity(Activity activity){
  if(activityStack==null){
   activityStack=new Stack<Activity>();
  }
  activityStack.add(activity);
 }
 //退出栈中所有Activity
 public void popAllActivityExceptOne(Class cls){
  while(true){
   Activity activity=currentActivity();
   if(activity==null){
    break;
   }
   if(activity.getClass().equals(cls) ){
    break;
   }
   popActivity(activity);
  }
 }
}



android 完全退出应用程序实现代码

android退出应用程序会调用android.os.Process.killProcess(android.os.Process.myPid())或是System.exit(0),这只是针对第一个Activity(也就是入口的Activity)时生效。如果有A,B,C三个Activity,而想在B或C中Activity退出,调用上面的方法,往往会销毁当前的Activity返回上一个Activity。当然也可以逐个返回上一个Activity,直到跳转到入口的Activity,最后退出应用程序。但这样比较麻烦,而且逐个返回的体验并不友好。

网上比较流行的方法是定义栈,写一个ExitApplication类,利用单例模式管理Activity,在每个在Activity的onCreate()方法中调用ExitApplication.getInstance().addActivity(this)方法,在退出时调用ExitApplication.getInstance().exit()方法,就可以完全退出应用程序了。
ExitApplication类

import java.util.LinkedList;
import java.util.List;

import android.app.Activity;
import android.app.Application;

public class ExitApplication extends Application {

 private List activityList = new LinkedList();
 private static ExitApplication instance;

 private ExitApplication()
 {
 }
 //单例模式中获取唯一的ExitApplication实例
 public static ExitApplication getInstance()
 {
 if(null == instance)
 {
 instance = new ExitApplication();
 }
 return instance;

 }
 //添加Activity到容器中
 public void addActivity(Activity activity)
 {
 activityList.add(activity);
 }
 //遍历所有Activity并finish

 public void exit()
 {

 for(Activity activity:activityList)
 {
 activity.finish();
 }

 System.exit(0);

 }
 }

 下面的三个类IndexActivity, BActivity,CActivity是简单的例子,分别是IndexActivity?>BActivity?>CActivity的跳转顺序。在每个Activity类中onCreate()方法中调用ExitApplication.getInstance().addActivity(Activity activity)方法。在任何一个Activity界面退出应用程序时,只要调用ExitApplication.getInstance().exit()方法,就可以在任何一个Activity中完全退出应用程序。
IndexActivity 类源代码:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class IndexActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button next=(Button)findViewById(R.id.next_to_b);
        next.setOnClickListener(nextClick);

        Button exit=(Button)findViewById(R.id.exit_main);
        exit.setOnClickListener(exitClick);
        ExitApplication.getInstance().addActivity(this);

    }

    OnClickListener nextClick=new OnClickListener() {

  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub

   Intent intent=new Intent(IndexActivity.this,BActivity.class);
   startActivity(intent);

  }
 };

    OnClickListener exitClick=new OnClickListener() {

  @Override
  public void onClick(View v) {
   // TODO Auto-generated method stub
   ExitApplication.getInstance().exit();
  }
 };
}

BActivity 类源代码:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class BActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

setContentView(R.layout.b);
Button next_to_c=(Button)findViewById(R.id.next_to_c);
next_to_c.setOnClickListener(next_to_cClick);

Button exit_b=(Button)findViewById(R.id.exit_b);
exit_b.setOnClickListener(exitClick);
ExitApplication.getInstance().addActivity(this);

}

OnClickListener next_to_cClick=new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub

Intent intent=new Intent(BActivity.this,CActivity.class);
startActivity(intent);

}
};

OnClickListener exitClick=new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ExitApplication.getInstance().exit();
}
};
}

CActivity 类源代码:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class CActivity extends Activity{

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

setContentView(R.layout.c);

Button exit_c=(Button)findViewById(R.id.exit_c);
exit_c.setOnClickListener(exitClick);
ExitApplication.getInstance().addActivity(this);

}

OnClickListener exitClick=new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ExitApplication.getInstance().exit();
//如果只是调用以下其中的一个方法,并不会完全退出应用
//android.os.Process.killProcess(android.os.Process.myPid());
//System.exit(0);
}
};
}

Android应用项目有时为了方便需要调用第三方文件或者库,本文我们来讲讲如何在Android NDK中调用第三方库文件(.so),及Android JNI找不到第三方库的解决方案。

如何在Android NDK中调用第三方库文件(.so)



1.在project/jni目录下创建prebuilt子目录(目录名可自定义).

2.将第三方.so放到prebuilt中,并创建Android.mk, 内容如下:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE := xxx

    LOCAL_SRC_FILES := libxxx.so

    include $(PREBUILT_SHARED_LIBRARY)

3.在project/jni/Android.mk中加入

    LOCAL_SHARED_LIBRARIES := xxx

4.在project/jni/android.mk的最后加入

    include $(LOCAL_PATH)/prebuilt/Android.mk

5.运行cygwin, 到project目录下, 运行$NDK/ndk-build




Android JNI找不到第三方库的解决方案 cannot load library



    最近做一个jni项目,拿到的so库需要用jni封装一层,等于是在jni的C++代码里调用第三方库的方法,然后整个项目在Android上运行出结果。

    自己用jni生成的so是libaa.so 使用的第三方库是libbb.so。

    到目前为止,遇到的问题是libbb各种找不到。libbb库去哪儿了?

     

    E/AndroidRuntime(11626): Caused by: java.lang.UnsatisfiedLinkError:
    Cannot load library: soinfo_link_image(linker.cpp:1640):
    could not load library libbb.so needed by libaa.so;

    caused by load_library(linker.cpp:750): library libbb.so not found

     

    以上错误是在运行阶段发生的,事实上编译阶段也发生过找不到第三方的问题,表现就是库里实现的方法undefined。

    分两方面解决

     

    1,编译阶段找不到库,需要修改MK文件。

    1.libbb.so放在jni/prebuilt文件夹(自己新建),同时把Android.mk复制一份到prebuilt下。

    2.libbb.so的mk如下:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := bb
    LOCAL_SRC_FILES := libbb.so
    include $(PREBUILT_SHARED_LIBRARY)
    (<Dream>如果第三方提供的是.so文件则无须前面两个步骤)

    3.libaa.so的mk文件需要引入上面的mk。
    LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_MODULE    := aa
    LOCAL_SRC_FILES := aa.cpp
    LOCAL_LDLIBS := -llog
     LOCAL_SHARED_LIBRARIES := bb
    include $(BUILD_SHARED_LIBRARY)
    include $(LOCAL_PATH)/prebuilt/Android.mk
    (<Dream>可以静态链接,这样只产生一个.so,做法如下)
    Android.mak
    include $(BUILD_STATIC_LIBRARY)
    Application.mak
    APP_MODULES:=aa

    这样在编译阶段就可以连接到第三方库咯。

    2.运行阶段找不到库

    在运行阶段找不到库就是Android的事情了。后来发现是load库的顺序(默哀一个,破顺序。。)。

     
    static
        {
            System.loadLibrary(bb);
            System.loadLibrary(aa);
        }
    (<Dream>静态链接,这样就不需要load两个了库)
    先load第三方库,再load自己的库,因为aa库要用bb库里的方法,是依赖于bb库的,所以要先load。。

    这样在运行阶段也可以找到库咯。

[!--infotagslink--]

相关文章

  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • php简单数据操作的实例

    最基础的对数据的增加删除修改操作实例,菜鸟们收了吧...2013-09-26
  • 解决Mybatis 大数据量的批量insert问题

    这篇文章主要介绍了解决Mybatis 大数据量的批量insert问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-09
  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • Antd-vue Table组件添加Click事件,实现点击某行数据教程

    这篇文章主要介绍了Antd-vue Table组件添加Click事件,实现点击某行数据教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-17
  • 详解如何清理redis集群的所有数据

    这篇文章主要介绍了详解如何清理redis集群的所有数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18
  • vue 获取到数据但却渲染不到页面上的解决方法

    这篇文章主要介绍了vue 获取到数据但却渲染不到页面上的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-19
  • php把读取xml 文档并转换成json数据代码

    在php中解析xml文档用专门的函数domdocument来处理,把json在php中也有相关的处理函数,我们要把数据xml 数据存到一个数据再用json_encode直接换成json数据就OK了。...2016-11-25
  • mybatis-plus 处理大数据插入太慢的解决

    这篇文章主要介绍了mybatis-plus 处理大数据插入太慢的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-18
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • postgresql数据添加两个字段联合唯一的操作

    这篇文章主要介绍了postgresql数据添加两个字段联合唯一的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-04
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Vue生命周期activated之返回上一页不重新请求数据操作

    这篇文章主要介绍了Vue生命周期activated之返回上一页不重新请求数据操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-26
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02