編輯:關於Android編程
前言:
很長時間一直思考什麼時候需要原生應用於html5開發的web app結合去開發一個App;終於做了一個《立波育兒百科》的應用,才嘗試了這種方式做一個App;
項目介紹:
這是 一個百科類的App,主要包含了育兒、養生、懷孕、飲食、母嬰用品等方面的資料,這些資料有個特點,都是html格式,采用CSS將其分段存儲在數據庫裡;
考慮到要做一個Android版本和Ios版本,所以盡量讓網頁內容得以在2個系統上共享,維護一份網頁內容,使其在2個手機平台上使用;
在App的操作使用方面,主界面就是百科分類,然後用戶進入分類就顯示該分類下的標簽項,用戶通過標簽項來進一步找到自己要看的百科文章;當然還有“文章收藏”和“文章搜索”的功能。
如圖所示:
在文章頁面展示上,采用了jquery mobile的UI風格:頁面標題欄+內容欄,用戶點擊頁面,會使頁面標題欄會自動隱藏/顯示,如果頁面展示超過一屏,我在頁面最右下角加了一個“回到頂部”的快捷方式;當然頁面標題欄還有“返回”和“收藏”的2個按鈕,分別幫助用戶能夠返回上一級的頁面,收藏當前喜歡關注的文章。
如圖所示:
原生和html5的交互界面介紹:
這個是本文的重點,
准備工作:首先我是用python和django template技術獎數據庫的內容按照jquery ui做成的模板批量生成了靜態html頁面,大概20多M吧,我都直接扔到/asset目錄下,好讓webview加載使用。
代碼設計:加載html5網頁的webview會單獨嵌入在一個Activity,我們稱之為WebPageActivity;
我們還要增加一個類ActionHelper專門負責原生程序和JS直接的通信,包含以下功能:添加收藏,設置頁面標題,關閉當前Activity
[java]
package com.souapp.baike.yuer.js;
import android.app.Activity;
import android.os.Handler;
import android.util.Log;
import android.webkit.WebView;
import com.souapp.baike.yuer.db.DBFavoriteOpeator;
import com.souapp.baike.yuer.exception.DataIsExistException;
import com.souapp.baike.yuer.favorite.FavoriteBean;
import com.souapp.common.tools.DateTools;
/****
* 處理JS主動調用自己的方法
* @author Tester
*
*/
public class ActionHelper {
private String TAG="ActionHelper";
private Activity cxt;
private WebView webview;
private String callbackFunction;//條碼掃描結果,給JS的回調函數
private ActionHelper(){}
private static ActionHelper instance;
private Handler handler;
private String result="添加收藏成功.";
public static ActionHelper getInstance(){
if (instance==null){
instance=new ActionHelper();
}
return instance;
}
public void setValue(Activity context,WebView wv,Handler ha){
cxt=context;
webview=wv;
handler=ha;
}
/***
* 把掃碼結果回調給JS
* @param data
*/
public void saveBarcodeScanData(String data){
try{
webview.loadUrl("javascript:"+callbackFunction+"('"+data+"')");
}catch(Exception e){
Log.e(TAG, "",e);
}
}
/***
* 設置頁面標題
* @param name
*/
public void setBaikeTitle(final String name){
try{
handler.post(new Runnable() {
public void run() {
//調用客戶端setContactInfo方法
webview.loadUrl("javascript:setBaikeTitle('"+name+"')");
}
});
}catch(Exception e){
Log.e(TAG, "",e);
}
}
/***
* 搜索頁面裡調用查看本地詳細文章
* @param savepath
*/
public void viewDetail(final String savepath){
try{
Log.d(TAG, "=========viewDetail=========");
}catch(Exception e){
Log.e(TAG, "",e);
}finally{
handler.post(new Runnable() {
public void run() {
//調用JS,顯示操作狀態
webview.loadUrl("file:///android_asset/static_mobile_baike"+savepath);
}
});
}
}
/***
* 把文章加入收藏夾裡
* @param name
*/
public void addFavorite(final String title,final String category,final String tag,final String savepath){
try{
Log.d(TAG, "=========addFavorite=========");
String savedate=DateTools.formatLong2Str(System.currentTimeMillis());
FavoriteBean bean=new FavoriteBean();
bean.setTitle(title);
bean.setCategory(category);
bean.setTag(tag);
bean.setSavepath(savepath.substring(1));
bean.setOrder(0);
bean.setSavedate(savedate);
DBFavoriteOpeator.saveFavorite(cxt,bean);
result="成功添加到收藏夾";
}catch(DataIsExistException e1){
Log.e(TAG, "",e1);
result="提示:"+e1.getMessage();
}catch(Exception e){
Log.e(TAG, "",e);
result="錯誤:"+e.getMessage();
}finally{
handler.post(new Runnable() {
public void run() {
//調用JS,顯示操作狀態
webview.loadUrl("javascript:callBack_echoMsg('"+result+"')");
}
});
}
}
/****
* JS調用關閉Activity
* @param mother
*/
public void exitActivity(){
try{
if (cxt==null) return;
cxt.finish();
}catch(Exception e){
e.printStackTrace();
}
}
/****
* 調用條碼掃描界面
*/
public void startBarCodeScanUI(String url,String invokeFunction){
/* try{
Log.e(TAG, " start url:"+url);
callbackFunction=invokeFunction;
Intent it=new Intent();
it.setClass(cxt, ZXingScannerActivity.class);
it.putExtra("queryUrl", url);//把請求的URl傳給掃碼的頁面
cxt.startActivity(it);
}catch(Exception e){
e.printStackTrace();
}*/
}
}
package com.souapp.baike.yuer.js;
import android.app.Activity;
import android.os.Handler;
import android.util.Log;
import android.webkit.WebView;
import com.souapp.baike.yuer.db.DBFavoriteOpeator;
import com.souapp.baike.yuer.exception.DataIsExistException;
import com.souapp.baike.yuer.favorite.FavoriteBean;
import com.souapp.common.tools.DateTools;
/****
* 處理JS主動調用自己的方法
* @author Tester
*
*/
public class ActionHelper {
private String TAG="ActionHelper";
private Activity cxt;
private WebView webview;
private String callbackFunction;//條碼掃描結果,給JS的回調函數
private ActionHelper(){}
private static ActionHelper instance;
private Handler handler;
private String result="添加收藏成功.";
public static ActionHelper getInstance(){
if (instance==null){
instance=new ActionHelper();
}
return instance;
}
public void setValue(Activity context,WebView wv,Handler ha){
cxt=context;
webview=wv;
handler=ha;
}
/***
* 把掃碼結果回調給JS
* @param data
*/
public void saveBarcodeScanData(String data){
try{
webview.loadUrl("javascript:"+callbackFunction+"('"+data+"')");
}catch(Exception e){
Log.e(TAG, "",e);
}
}
/***
* 設置頁面標題
* @param name
*/
public void setBaikeTitle(final String name){
try{
handler.post(new Runnable() {
public void run() {
//調用客戶端setContactInfo方法
webview.loadUrl("javascript:setBaikeTitle('"+name+"')");
}
});
}catch(Exception e){
Log.e(TAG, "",e);
}
}
/***
* 搜索頁面裡調用查看本地詳細文章
* @param savepath
*/
public void viewDetail(final String savepath){
try{
Log.d(TAG, "=========viewDetail=========");
}catch(Exception e){
Log.e(TAG, "",e);
}finally{
handler.post(new Runnable() {
public void run() {
//調用JS,顯示操作狀態
webview.loadUrl("file:///android_asset/static_mobile_baike"+savepath);
}
});
}
}
/***
* 把文章加入收藏夾裡
* @param name
*/
public void addFavorite(final String title,final String category,final String tag,final String savepath){
try{
Log.d(TAG, "=========addFavorite=========");
String savedate=DateTools.formatLong2Str(System.currentTimeMillis());
FavoriteBean bean=new FavoriteBean();
bean.setTitle(title);
bean.setCategory(category);
bean.setTag(tag);
bean.setSavepath(savepath.substring(1));
bean.setOrder(0);
bean.setSavedate(savedate);
DBFavoriteOpeator.saveFavorite(cxt,bean);
result="成功添加到收藏夾";
}catch(DataIsExistException e1){
Log.e(TAG, "",e1);
result="提示:"+e1.getMessage();
}catch(Exception e){
Log.e(TAG, "",e);
result="錯誤:"+e.getMessage();
}finally{
handler.post(new Runnable() {
public void run() {
//調用JS,顯示操作狀態
webview.loadUrl("javascript:callBack_echoMsg('"+result+"')");
}
});
}
}
/****
* JS調用關閉Activity
* @param mother
*/
public void exitActivity(){
try{
if (cxt==null) return;
cxt.finish();
}catch(Exception e){
e.printStackTrace();
}
}
/****
* 調用條碼掃描界面
*/
public void startBarCodeScanUI(String url,String invokeFunction){
/* try{
Log.e(TAG, " start url:"+url);
callbackFunction=invokeFunction;
Intent it=new Intent();
it.setClass(cxt, ZXingScannerActivity.class);
it.putExtra("queryUrl", url);//把請求的URl傳給掃碼的頁面
cxt.startActivity(it);
}catch(Exception e){
e.printStackTrace();
}*/
}
}
本文和大家一起做一個帶箭頭的圓角矩形菜單,大概長下面這個樣子: 要求頂上的箭頭要對准菜單錨點,菜單項按壓反色,菜單背景色和按壓色可配置。最簡單的做法就是讓UX給
前言在日常開發APP 的過程中,隨著業務的擴展,規模的變化。我們的代碼規模也會逐漸變得龐大,每一個類裡的代碼也會逐漸增多。尤其是Activity和Fragment ,由於
Android中有兩種主要方式使用Service,通過調用Context的startService方法或調用Context的bindService方法,本文只探討純sta
盡管你寫代碼可能通過了世界上所有的性能測試,但是它還是可能會讓人感覺到卡頓。當應用卡的不成樣子時,系統會給你彈一個”Application Not Respo