67
Grandroid Grandroid Android Android 開開 開開 App App 開開開開開開 開開開開開開 Rovers 2011-06-05

Grandroid Android 開源 App 開發框架介紹 Rovers 2011-06-05

Embed Size (px)

Citation preview

GrandroidGrandroid

AndroidAndroid 開源開源 AppApp開發框架介紹開發框架介紹

Rovers

2011-06-05

自我介紹自我介紹

Rovers

恩海科技創辦人

盯字庫作者

Grandroid IntroductionGrandroid Introduction

Target UserTarget User 想節省開發時間的使用者 想專注在 App 功能設計的創業家 Framework 愛好者 Design Pattern 擁護者 討厭 XML 排版的人 愛用國貨的支持者

Design GoalsDesign Goals• 縮短 App 開發時間• 提昇 App 品質• 提昇程式碼可閱讀性• 封裝經常重複被使用的程式碼• 一行程式碼哲學

FeaturesFeaturesObject-Relational Mapping(ORM)Predefined ActionsNew Layout MechanismEnhanced ActivitySimple Dialog ModelSimple AdapterUI Data PersistanceUsable Service JSON-Java ConverterHTTP POSTActivity-Phase Broadcast HandlingAnimate Effect

Sample App –Sample App – 「我的書庫」「我的書庫」設計功能

◦ 可新增書籍◦ 提供書本的清單◦ 提供單本書的檢視◦ 書籍提供「借出」及

「歸還」功能

特色◦ 以 CodeScanner 掃描

ISBN 碼◦ 自動尋找書本封面圖片◦ 可設定每本書的閱讀進度

FEATURESFEATURES

Object-Relational MappingObject-Relational Mapping◦ 新增資料

◦ 刪除資料

◦ 修改資料

◦ 查詢資料

◦ 產生 Table

helper.insert(book);

helper.delete(book.get_id());

helper.update(book);

List<Book> books = helper.select();List<Book> books = helper.select(“where status=1”);Book book = helper.selectSingle(“where _id=1”);

GenericHelper helper = new GenericHelper(new FaceData(…), Book.class);

POJO DesignPOJO Design

Low-Level Database APILow-Level Database API

Predefined ActionsPredefined Actions• 換頁• 回前頁• 撥電話• 吐司• 通知 (Notification)• 對話方塊• 開網頁• 自定義 Action

換頁換頁new GoAction(context,

Page.class).execute();

new GoAction(context, Page.class).setSubTask(0).execute();

回前頁回前頁new BackAction(context).execute();

撥電話撥電話new

DialAction(context,””,”0223825675”).execute();

吐司吐司new

ToastAction(context).setMessage(“hello”).execute();

通知通知 (Notification)(Notification)new NotifyAction(context).setTitle(“ 新訊息” ) .setContent(“ 你被邀請加入一個社

團” ).execute();

對話方塊對話方塊new AlertAction(context).setData(“ 系統” ,“ 你有一篇未完成的草稿,是否要繼續編輯 ?” ,new

GoAction(context,” 是” ,ActivityEditor.class) ,new

GoAction(context,” 否” ,ActivityMain.class)).execute();

開網頁開網頁new

URLAction(context,”http://www.google.com”).execute();

自定義自定義 ActionActionnew Action(){

public boolean execute(){}

}

new ContextAction(context){public boolean execute(Context context){}

}

new ThreadAction(context,0){public boolean execute(Context context){}

}

New Layout MechanismNew Layout Mechanism

如何做出以下的排版如何做出以下的排版 ??RelativeLayout LinearLayout

ListView

Button Button

如何做出以下的排版如何做出以下的排版 ??RL LL

Button

SV

Button

Button

TextView

TextView

ImageView

ImageView

Button

TextView

Grandroid Layout ConceptGrandroid Layout Concept

1. 使用 LayoutMaker 物件2. RelativeLayout 、 ScrollView 會自

動產生3. 每生成一個 Panel ,需要執行跳脫,

才能回到父 Panel4. 一行程式碼 = 一個 Layout 動作

Example 1Example 1LinearLayout

Text1

Button

Text2

@Overridepublic void onCreate(Bundle bundle) { super.onCreate(bundle);

LayoutMaker m = new LayoutMaker(this);

m.addTextView(“Text1”);

m.add(m.createTextView(“Text2”),m.layFW(1));

m.add(maker.createButton(“Button”),m.layFW(0));

}

Tip: addXXX() = createXXX + add()

LayoutMaker MethodsLayoutMaker MethodsCreate View Create & Add

ViewCreate & Enter Panel

Others

createTextView addTextView addTopBanner escape

createButton addButton addBottomBanner

add

createImage addImage addRowLayout layWW

createSpinner addSpinner addColLayout layFF

createListView addListView layFW

createCheckBox addCheckBox layWF

createEditText addEditText getLastLayout

createRadioGroup

addRadioGroup getRootLayout

Example 2 (1/7)Example 2 (1/7)LL

LayoutMaker m = new LayoutMaker(this);

m.addTopBanner();

m.addTextView(“Text1”);

m.addButton(“Button1”);

m.escape();

m.addBottomBanner();

m.addButton(“Button2”);

m.escape();

m.add(m.createTextView(“Text2”),m.layFF());

RL

Text1 Button1

Button2

Text2

Example 2 (2/7)Example 2 (2/7)LL

LayoutMaker m = new LayoutMaker(this);

RL Last Layout

Example 2 (3/7)Example 2 (3/7)LL

LayoutMaker m = new LayoutMaker(this);

m.addTopBanner();

RL Last Layout

Example 2 (4/7)Example 2 (4/7)LL

LayoutMaker m = new LayoutMaker(this);

m.addTopBanner();

m.addTextView(“Text1”);

m.addButton(“Button1”);

RL

Text1 Button1

Last Layout

Example 2 (5/7)Example 2 (5/7)LL

LayoutMaker m = new LayoutMaker(this);

m.addTopBanner();

m.addTextView(“Text1”);

m.addButton(“Button1”);

m.escape();

RL

Text1 Button1

Last Layout

Example 2 (6/7)Example 2 (6/7)LL

LayoutMaker m = new LayoutMaker(this);

m.addTopBanner();

m.addTextView(“Text1”);

m.addButton(“Button1”);

m.escape();

m.addBottomBanner();

m.addButton(“Button2”);

m.escape();

RL

Text1 Button1

Button2

Last Layout

Example 2 (7/7)Example 2 (7/7)LL

LayoutMaker m = new LayoutMaker(this);

m.addTopBanner();

m.addTextView(“Text1”);

m.addButton(“Button1”);

m.escape();

m.addBottomBanner();

m.addButton(“Button2”);

m.escape();

m.add(m.createTextView(“Text2”),m.layFF());

RL

Text1 Button1

Button2

Text2

Last Layout

Enhanced ActivityEnhanced Activity• Activity 改繼承 Face 類別• 新增 Menu• 載入 layout xml 元件• 挑選日期或時間• 挑選命令• 收聽事件廣播• 設定按鈕事件

ActivityActivity 改繼承改繼承 FaceFace 類別類別

新增新增 MenuMenuaddMenu(new GoAction(this, " 關於 ",

FrameAbout.class));

載入載入 layout xmllayout xml 元件元件Spinner sp =

(Spinner)loadLayout(R.layout.sp);

挑選日期或時間挑選日期或時間pickDateTime(new DateTimePickModel(…)

{…});

挑選命令挑選命令pickObject(new

ObjectPickModel(context,cmds){…});

收聽事件廣播收聽事件廣播 registerBundledAction(“EVENT_A”, new GoAction(this,

FrameA.class).setSubTask(0));

設定按鈕事件設定按鈕事件setButtonEvent(btnEdit, new

ContextAction(this){…});

Simple Dialog ModelSimple Dialog Model• 輸入對話方塊

• 客製化對話方塊

輸入對話方塊輸入對話方塊 new InputDialogMask(this, “ 系統” , “”, “ 請輸入

密碼 ", null) { @Override public boolean executeAction(String

string) { //handle user input return true; } }.show();

客製化對話方塊客製化對話方塊new DialogMask(this) {

@Override

public boolean setupMask(Context c, Builder builder, LayoutMaker maker) throws Exception {

((LinearLayout) maker.getLastLayout()).setGravity(Gravity.CENTER_HORIZONTAL);

maker.addTextView(" 你的朋友欠你書一個月了 ! 是否要提醒他還書 ?").setPadding(5, 5, 5, 5);

Book book = helper.selectSingle(5);

maker.addImage(ImageView.class, book.getPath());

maker.add(maker.createTextView(" 就是這本 !"), maker.layFW()).setGravity(Gravity.CENTER);

builder.setTitle(" 提醒 ");

builder.setPositiveButton(new DialAction(c, " 打電話 "));

builder.setNegativeButton(new Action(" 寄信 "));

return true;

}

}.show();

Simple AdapterSimple Adapter• ObjectAdapter

• Base on List<Object>

• FaceDataAdapter• Base on SQL

• JSONAdapter• Base on JSONArray

ObjectAdapterObjectAdapterList<Book> books = new GenericHelper<Book>(new FaceData(c,

“db"), Book.class).select();

maker.addListView(new ObjectAdapter<Book>(this, books) {

@Override

public View createRowView(int i, Book t) {

}

@Override

public void fillRowView(int i, View view, Book t) {

}

@Override

public void onClickItem(int index, View view, Book item) {

}

@Override

public void onLongPressItem(int index, View view, Book item) {

}

});

FaceDataAdapterFaceDataAdapterGenericHelper helper = new GenericHelper(new FaceData(this, "db"),

Book.class);

maker.addListView(new FaceDataAdapter<Book>(this, helper, "where status=1", false) {

@Override

public View createRowView(int i, Book t) {

}

@Override

public void fillRowView(int i, View view, Book t) {

}

@Override

public void onClickItem(int index, View view, Book item) {

}

@Override

public void onLongPressItem(int index, View view, Book item) {

}

});

JSONAdapterJSONAdapterJSONArray array = new

Mon("http://someweb/api").sendAndWrapArray();

maker.addListView(new JSONAdapter(this,array) {

@Override

public View createRowView(int i, JSONObject jo) {

}

@Override

public void fillRowView(int i, View view, JSONObject jo) {

}

@Override

public void onClickItem(int index, View view, JSONObject jo) {

}

@Override

public void onLongPressItem(int index, View view, JSONObject jo) {

}

});

UI Data PersistanceUI Data Persistance

Timer ServiceTimer Service

JSON-Java ConverterJSON-Java Converter

//Java to JSON JSONObject jo = new

JSONConverter().fromObject(book);

//JSON to JavaBook book = new

JSONConverter().toObject(jo, Book.class);

HTTP POSTHTTP POST// 取得 server 回傳字串String content = new

Mon(url).put(“uid”,uid).send();

// 取得 server 回傳 JSONObjectJSONObject jo = new

Mon(url).put(“uid”,uid).sendAndWrap();

// 取得 server 回傳 JSONArrayJSONArray ja = new

Mon(url).put(“uid”,uid).sendAndWrapArray();

Activity-Phase Broadcast Activity-Phase Broadcast HandlingHandling

如何設計一個這樣的情境:◦背景上傳照片◦上傳完畢之後立刻顯示於目前畫面◦若使用者沒有正在使用 App ,顯示通知

(Notification)◦上傳過程中使用者可能切換到別的頁面

Sample CodeSample Code在 Face 裡捕捉 UPLOAD_DONE 事件 :registerBundledAction("UPLOAD_DONE", new

ShowImageAction(...));

在 Service 裡設計if(AppStatus.ON_TOP) { Intent intent = new Intent(); intent.setAction(“UPLOAD_DONE”); this.sendBroadcast(intent);}else{ new NotifyAction(this).setContent("title", "content").setGroup(0) .setAutoCancel(true).setIcon(R.drawable.icon).execute();}

註: UPLOAD_DONE 需先於 AndroidManifest.xml 中宣告

Animate EffectAnimate Effect翻頁動畫 ( 全頁 )平移動畫 ( 元件 )

翻頁動畫翻頁動畫

平移動畫 平移動畫 (1/3)(1/3)

平移動畫 平移動畫 (2/3)(2/3)

平移動畫 平移動畫 (3/3)(3/3)

如何執行切換動作 ?

方法 1 :

方法 2 :

呼叫 part.next() 、 part.previous()

Other UtilitiesOther Utilities• ImageUtil

◦ 快速載入、縮放、裁切、疊合圖片• LayoutUtil

◦ 取得螢幕寬高及真正的解析度• GPSUtil

◦ 快速取得最後已知的位置及重新定位• UserUtil

◦ 快速取得使用者所有帳號及聯絡人• PhoneUtil

◦ 取得網路狀態及手機硬體 ID

FAMILY LIBRARIESFAMILY LIBRARIES

Grandroid Family LibrariesGrandroid Family Libraries• Facepaper

• 整合 Facebook Library ,提供更簡單的介面• Grangeo

• 提供 GeoFace 及地理方面的功能• Gransfer

• 提供更容易上傳、下載檔案及 Cache 圖片的方法• Gramara

• 提供 CameraFace 、處理已知硬體 Bug ,並提供更更易用的介面

• Raingo• 封裝 MongoDB ,提供簡便的 CRUD Servlet

FURTHER WORKFURTHER WORK

簡報結束簡報結束

敬請指教敬請指教