2016年4月12日 星期二

網頁轉APP_PhoneGap


PhoneGap

http://docs.phonegap.com/develop/1-embed-webview/ios/

http://docs.phonegap.com/develop/1-embed-webview/android/

Embedding the Webview

CREATING APPS WITH PHONEGAP AND ANDROID NATIVE COMPONENTS

In this guide we'll walk through the basic steps needed to create a native hybrid Android app that has elements of both native Android components and a Cordova webview. For more information about why you might choose this approach, read this blog post.

Requirements:

Reference App

We'll use this sample application for reference throughout the tutorial. It contains two views; a Cordova view and a native view. The final sample app will have a button on the Cordova webview that will add an item to a list in the native view to show how to communicate between the web and native views. The sample also uses a couple other Cordova plugins to show how they're installed and for further reference use.

Step 1: Create a Base Cordova Project

Most developers use the PhoneGap or Cordova CLI to create their projects, however for this type of project it's not recommended since we are only working with the Android platform project specifically and we don't want to rebuild or overwrite the platform level code each time we run. Instead we'll use the cordova-android project itself. (This is the same project used from the CLI when you add the Android platform).
  1. Begin by cloning or downloading the zip file for the cordova-android Apache Cordova project for Android. Run the following command to execute the create script from the directory containing the cordova-android base project you cloned or unzipped locally to create the default Hello Cordova project. (If you unzipped into your user directory then you should run it from there).
     $ cordova-android/bin/create HybridAndroidApp org.sample.hybridandroidapp
    
    You will see output that looks like the following:
     HybridAndroidApp
     Creating Cordova project for the Android platform:
         Path: HybridAndroidApp
         Package: org.example.hybridandroidapp
         Name: HybridAndroidApp
         Activity: MainActivity
         Android target: android-22
     Copying template files...
     Android project created with cordova-android@4.1.0-dev
    

Step 2: Add Plugins

  1. Next use plugman to add any desired plugins. Plugman is the tool used to work with Cordova plugins when we're not using a CLI specifically. While still on the command line, cd into the root project created above:
     $ cd HybridAndroidApp
    
    Now add plugins using plugman from the command line of the root project with the syntax below. For this sample app we'll add the following set of plugins:
     $ plugman install --platform android --project . --plugin cordova-plugin-whitelist        
     $ plugman install --platform android --project . --plugin cordova-plugin-device        
     $ plugman install --platform android --project . --plugin nl.x-services.plugins.toast
    

Step 3: Import the project into Android Studio

Go to File -> Import Project and select the root HybridAndroidApp project created above. Allow the Gradle Sync to occur by clicking Ok in the dialog that pops up:
Stop and run the app now to ensure you see the default Hello Cordova app running and the DEVICE READY message before moving on.

Step 4: Create a layout for a native view

Next create a layout resource file to represent a native list view. The layout resource is an xml file that defines how a view will look. It will be used in the MyListActivity.java Class created in the next step.
To create a layout, right click on the res folder in the project navigator on the left and then select the New -> Android Resource Directory option. In the dialog popup, select layout for the Directory name and Resource type and leave Source set to main.
Now right click on the new layout folder in the project navigator and select New -> Layout Resource file. Put in a name of activity_list and leave the Root element and Directory name as is.
Paste in the following content to represent a simple list view. We'll use this list view to add items when pressing a button from the Cordova view:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
    />        
</LinearLayout>

Step 5: Create a Native List Activity

Now we need a native Activity class to represent the logic behind this view. Based on the android docs, an activity is a single, focused thing a user can do. Almost all activities interact with the user, so theActivity class takes care of creating a window for your UI. Create a new Java Class calledMyListActivity in your project's java/ folder at the same level as theMainActivity class. In the sample case it's under org.sample.hybridandroidapp. Paste in the following below the package declaration and save it.
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import java.util.ArrayList;

public class MyListActivity extends ListActivity {

    ArrayList<String> list = new ArrayList<String>();

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /** Setting a custom layout for the list activity */
        setContentView(R.layout.activity_list);

        Intent intent = this.getIntent();

        if (intent.hasExtra("items")) {
            list = intent.getExtras().getStringArrayList("items");
        }
        /** The adapter to manage the data for the list **/
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list);

        /** Setting the adapter to the ListView */
        setListAdapter(adapter);

        setResult(RESULT_OK, intent);
    }  
}
Note the line setContentView(R.layout.activity_list);. This is the line where we specify the layout view to associate with this Activity.

Step 6: Add to the AndroidManifest.xml

In this step we'll add our new Activity to the AndroidManifest.xml. Open theAndroidManifest.xml in the root of your project (or it may be listed in Android Studio under amanifests folder depending on your view) and insert an element for MyListActivity in the element as shown below, right below the MainActivity declaration.
    <activity
        android:name=".MyListActivity"
        android:label="MyListActivity">
    </activity>

Step 7: Cordova to Native Communication

Hybrid Plugin

In this section we'll use a custom plugin to communicate between the native and cordova views. You can go through the steps below to create your own plugin, or install or clone it from here for use or if you want to skip the plugin creation process for now and move on to Step 8.
TIP: To directly install it to your project, use the following command from your hybrid android root:
$ plugman install --platform android --plugin https://github.com/hollyschinsky/HybridBridgePlugin.git --project .

Plugin Create Steps (Optional)

  1. Create a new folder somewhere outside of your hybrid android project named HybridBridgePlugin with two subdirectories named src and www.
  2. Next, navigate into the www/js folder and create a JavaScript file for the plugin interface namedHybridBridge.js. Insert the following code:
     var exec = require('cordova/exec'),
         cordova = require('cordova');
    
     function HybridBridge() {
    
     }
     HybridBridge.prototype.addItem = function(item, classname, successCallback, errorCallback) {
         exec(successCallback, errorCallback, "HybridBridge", "addItem", [item, classname]);
     };
    
     module.exports = new HybridBridge();
    
  3. Now create folders to reflect your Java package as subdirectories of the src folder (src/org/sample/hybrid). Navigate into src/org/sample/hybrid and create the Java interface for the plugin in a file named HybridBridge.java. Insert the following code:
     package org.sample.hybrid;
    
     import android.content.Context;
     import android.content.Intent;
    
     import org.apache.cordova.CallbackContext;
     import org.apache.cordova.CordovaPlugin;
     import org.json.JSONArray;
     import org.json.JSONException;
    
     import java.util.ArrayList;
    
     public class HybridBridge extends CordovaPlugin {
         public ArrayList itemsList = new ArrayList();
         public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
             try {
                 if (action.equals("addItem")) {
                     String item = args.getString(0);
                     String className = args.getString(1);
                     Context context = cordova.getActivity().getApplicationContext();
                     Intent intent = new Intent(context,Class.forName(className));
                     itemsList.add(item);
                     intent.putStringArrayListExtra("items", itemsList);
                     cordova.startActivityForResult(this,intent,1);
                     callbackContext.success();
                     return true;
                 }
                 callbackContext.error("Invalid action");
                 return false;
             } catch(Exception e) {
                 System.err.println("Exception: " + e.getMessage());
                 callbackContext.error(e.getMessage());
                 return false;
             }
         }
         public void onActivityResult(int requestCode, int resultCode, Intent data) {
             // Handle a result here if one set in the Activity class started
             System.out.println("Activity Result: " + resultCode); //-1 is RESULT_OK
             if (resultCode==Activity.RESULT_OK) {
                 System.out.println("All good!");
             }
         }     
     }
    
    NOTE: The execute function will create an android Intent for the fully qualified name of theActivity class specified in the parameter. In our sample we will pass in the name of our List Activity class: "org.sample.hybridandroidapp.MyListActivity" and the code will resolve it to the class to be started. The code also adds the latest item to the ArrayList of items being managed for that view and passes in the updated list as an extra to be accessed from the Intent.
  4. Cordova plugins use a plugin.xml file to describe their metadata so they can be added via plugman and submitted to the registry for others to use. In the root of your HybridBridgePlugin folder create a file namedplugin.xml with the following text, replacing with your own plugin details, GitHub repo etc.
     
     <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
           xmlns:android="http://schemas.android.com/apk/res/android"
           id="cordova-plugin-hybrid"
           version="1.0.0">      
       <name>HybridBridge</name>
    
       <description>
           Simple hybrid bridge example
       </description>
    
       <author>Your Name</author>
    
       <license>MIT</license>      
       <keywords>Hybrid, Embedded </keywords>
    
       <engines>
           <engine name="cordova" version=">=3.0.0"/>
       </engines>
    
       <js-module src="www/HybridBridge.js" name="HybridBridge">
           <clobbers target="HybridBridge" />
       </js-module>
    
       
       <platform name="android">
           <config-file target="res/xml/config.xml" parent="/*">
               <feature name="HybridBridge">
                   <param name="android-package" value="org.sample.hybrid.HybridBridge" />
               </feature>
           </config-file>
           <source-file src="src/android/org/sample/hybrid/HybridBridge.java" target-dir="src/org/sample/hybrid"/>
       </platform>      
      </plugin>      
    
    There are also optional repo and issue elements that can also be included if you upload your plugin to a repo and
    helps you share it with others. https://github.com/hollyschinsky/HybridBridgePlugin.githttps://github.com/hollyschinsky/HybridBridgePlugin/issues
    Your final plugin structure should look like the following:
  5. Now, open your terminal and cd into the root of your hybrid android project. Install your new plugin with the following syntax and using the path to your own hybrid plugin after the --plugin option:
       $ plugman install --platform android --plugin ~/HybridBridgePlugin --project .
    
    If you have any issues with the above you can install the sample plugin directly with the following command:
       $ plugman install --platform android --plugin https://github.com/hollyschinsky/HybridBridgePlugin.git --project .
    

  1. Open /assets/www/index.html and modify the app div block to include the new input and button HTML elements shown below:
     <div class="app">
         <h1>Apache Cordova</h1>
         <div id="deviceready" class="blink">
             <p class="event listening">Connecting to Device</p>
             <p class="event received">Device is Ready</p>
         </div>
         <input id="bookmark" type="text"/>
         <button id="btnAdd">ADD ITEM</button>
         <br/>
         <button id="btnDeviceInfo">GET DEVICE INFO</button>
         <br/>
         <button id="btnToast">SHOW TOAST</button>
         <br>
         <button id="btnUrl">OPEN URL</button>
         <br/>
     </div>
    
  2. Open /assets/www/js/index.js and add the following code to handle our new buttons:
    First modify the onDeviceReady function to look as shown here:
      onDeviceReady: function() {
         window.plugins.toast.showLongBottom('Use the back button to return to main.');
         document.getElementById("btnAdd").addEventListener("click", app.addItem);
         document.getElementById("btnToast").addEventListener("click", app.showToast);
         document.getElementById("btnDeviceInfo").addEventListener("click", app.showDeviceInfo);
         document.getElementById("btnUrl").addEventListener("click", app.openWeb);
         app.receivedEvent('deviceready');
      },
    
    Next, still in index.js, define the handlers for each of the buttons registered above directly below thereceivedEvent function:
     addItem: function() {
        console.log("Plugin ADD ITEM CALLED " + HybridBridge);
        var item = document.getElementById("bookmark").value;
        HybridBridge.addItem(item,function(){console.log("Hybrid Bridge Success")},function(e){console.log("Hybrid Bridge Error" + e)});
     },
     showDeviceInfo: function(){
        var message = 'Cordova version: ' + device.cordova;
        message += '\n\nDevice Model: ' + device.model;
        message += '\n\nDevice Version (Android): ' + device.version;
        alert(message);
     },
     showToast: function(){
        window.plugins.toast.showShortCenter('PHONEGAP IS AWESOME!!!');
     },
     openWeb: function(){
        var url = "http://phonegap.com"
        window.open(url)
     }
    

Step 9: Run it!

Run it now from Android Studio and choose either an emulator or device target. Here it is running in a Nexus 5 emulator. Enter text and click Add Item to ensure it's working correctly. Click the other buttons to display device info, show a toast message etc, taking advantage of the other plugins added to the project.

Step 10: Troubleshooting

If you run into any issues, start by checking logcat (the device console for Android) to look for errors. You can use the logcat window from Android Studio or run it from the command line with:
 $ adb logcat
TIP: You can search the output specifically for INFO:CONSOLE to filter the search further and locate your errors.
You could also compare your code to the sample project located here.
Edit this page on GitHub

Binary Tree



http://www.csie.ntnu.edu.tw/~u91029/BinaryTree.html

Binary Tree
「二元樹」是計算機科學最重要的概念,甚至可以說:二元樹開創了計算機科學。
像是資料結構 Binary Search Tree 與 Heap ,交換式排序演算法的 Decision Tree 、資料壓縮的 Huffman Tree 、 3D 繪圖的 BSP Tree 、編譯器的 Parse Tree…… ,這一大堆稀奇古怪的術語,通通都是二元樹。總之,二元樹的應用相當廣泛,是資工系學生必學的基礎概念。
「二元樹」與「樹」,儘管名稱相近,但是概念不相近,至於用途更是天差地遠,兩者可以分別獨立學習。二元樹:資料結構課程的二元搜尋樹章節,會順便引出二元樹的概念;樹:演算法課程的圖論章節,一開始就會介紹樹的定義。
言歸正傳。「二元樹」就是分兩岔的樹,每個節點可以有左小孩和右小孩,每個節點可以有零個、一個、兩個小孩。
順便介紹幾個特殊的二元樹:
full binary tree :除了樹葉以外,每個節點都有兩個小孩。
complete binary tree :各層節點全滿,除了最後一層,最後一層節點全部靠左。
perfect binary tree :各層節點全滿。同時也是 full binary tree 和 complete binary tree 。
Binary Tree 資料結構
第一種方法,是建立節點,運用指標串接各個節點。
 
  1. struct Node
  2. {
  3.     Nodeparent;
  4.     Nodeleft;
  5.     Noderight;
  6.     int data;
  7. };
  8.  
  9. Noderoot = 0;
第二種方法,是讓二進位數字一一對應到二元樹的節點。
建立一個陣列,運用陣列索引值就能得到各個節點:樹根的索引值固定是一,索引值乘上兩倍就得到左小孩,索引值乘上兩倍再加一就得到右小孩,索引值除以二就得到父親。
優點是程式碼簡潔,效率高。
缺點是浪費記憶體空間。如果不是 complete binary tree ,那麼陣列就有很多閒置空格。
另一個缺點是樹的高度受限制。 1024 = 2^10 格的陣列,樹的高度只有 10 ,不能更高了。
 
  1. int tree[5 + 1];    // tree[0]不使用,只有五個節點。
  2. int left_child(int index) {return index * 2;}
  3. int right_child(int index) {return index * 2 + 1;}
  4.  
  5. void binary_tree()
  6. {
  7.     cout << "根為" << tree[1];
  8.     cout << "根的左邊小孩是" << tree[left_child(1)];
  9.     cout << "根的右邊小孩是" << tree[right_child(1)];
  10. }
UVa 112 122
Binary Tree Traversal
二元樹的遍歷順序,理論上總共四種──但是事實上還是只有 DFS 與 BFS 兩種,只不過更動了節點的輸出順序。
注意樹根的位置,就能輕鬆解讀這四種序。
Preorder Traversal 前序遍歷
理論上的遍歷順序是:根、左子樹、右子樹。根排在前面。
即是Depth-first Search。

Inorder Traversal 中序遍歷
理論上的遍歷順序是:左子樹、根、右子樹。根排在中間。
實際上是採用Depth-first Search,只不過更動了節點的輸出順序。

Postorder Traversal 後序遍歷
理論上的遍歷順序是:左子樹、右子樹、根。根排在後面。
實際上是採用Depth-first Search,只不過更動了節點的輸出順序。

Level-order Traversal 層序遍歷
即是Breath-first Search。
 
  1. struct Node
  2. {
  3.     Nodeleft;
  4.     Noderight;
  5.     int data;
  6. };
  7.  
  8. Noderoot = ...;   // 假設已經建立二元樹了
  9.  
  10. // preorder traversal
  11. void traversal(Nodep)
  12. {
  13.     if (!preturn;
  14.     cout << p->data;    // 先輸出樹根
  15.     traversal(p->left); // 次輸出左子樹
  16.     traversal(p->right);// 後輸出右子樹
  17. }
  18.  
  19. // inorder traversal
  20. void traversal(Nodep)
  21. {
  22.     if (!preturn;
  23.     traversal(p->left);
  24.     cout << p->data;    // 挪到中間,改變輸出順序。
  25.     traversal(p->right);
  26. }
  27.  
  28. // postorder traversal
  29. void traversal(Nodep)
  30. {
  31.     if (!preturn;
  32.     traversal(p->left);
  33.     traversal(p->right);
  34.     cout << p->data;    // 挪到後面,改變輸出順序。
  35. }
  36.  
  37. // level-order traversal
  38. void traversal(Noderoot)
  39. {
  40.     queue<Node*> q;
  41.     q.push(root);
  42.     while (!q.empty())
  43.     {
  44.         Nodep = q.front(); q.pop();
  45.         cout << p->data;    // 這行往下挪,結果仍相同。
  46.         if (p->left)  q.push(p->left);
  47.         if (p->rightq.push(p->right);
  48.     }
  49. }
  50.  
  51. // preorder traversal
  52. void traversal(Noderoot)
  53. {
  54.     stack<Node*> s;
  55.     s.push(root);
  56.     while (!s.empty())
  57.     {
  58.         Nodep = s.front(); s.pop();
  59.         cout << p->data;    // 這行往下挪,結果仍相同。
  60.         if (p->rights.push(p->right);
  61.         if (p->left)  s.push(p->left);
  62.         // 堆疊先進後出、顛倒順序,故先放右小孩、再放左小孩。
  63.     }
  64. }
UVa 112 699
Binary Tree Reconstruction
以一棵二元樹能得到前序、中序、後序、層序,那麼以前序、中序、後序、層序能得到一棵二元樹嗎?
只有一種序,是無法還原出一棵二元樹的,有很多可能性。
有兩種序,就有機會還原出唯一一棵二元樹。比方說,只知道 preorder 和 inorder ,求出原本的二元樹。
運用 Divide and Conquer 可以巧妙解決。在 preorder 之中,最左邊的元素就是 root ;在 inorder 之中, root 的兩邊分別為左子樹和右子樹──利用 root 便可區分左子樹和右子樹。子樹也是樹,可以用相同手法繼續分割,最後便可求出整棵樹的架構。
但是只有 preorder 和 postorder 的話,是做不出答案的。因為無法確定樹根的位置。
那麼 level-order 呢?大家就自己想想吧。
UVa 10701 536 548 10410 12347
Polish Notation / Reverse Polish Notation
凡是談到二元樹的前序、中序、後序,總是順便談到四則運算的前序、中序、後序表示法。
我們可以將一道四則運算式子,換成二元樹。
然後列出此二元樹的前序、中序、後序。其中前序就是波蘭表示法,又稱作 prefix ;中序就是原來的四則運算式子、需要括號,又稱作 infix ;後序就是逆波蘭表示法,又稱作 postfix 。
然而,建立二元樹是很麻煩的。能不能略過二元樹,直接把四則運算式子換成波蘭表示法(逆波蘭表示法)呢?當然能!只要運用 stack ,就可以做到這件事情。
 
  1. 通常這是學校作業,所以就不提供程式碼了。
一道四則運算式子,改成波蘭表示法(逆波蘭表示法)之後,計算過程變成由左往右計算,不必顧慮先乘除後加減、不必顧慮括號,只需要一個額外的 stack 作為輔助。
程式語言的四則運算式子,事實上都會被編譯器轉換成波蘭表示法(逆波蘭表示法),以利電腦計算。
 
  1. 通常這是學校作業,所以就不提供程式碼了。
UVa 372 727 11234 172 10700 10847
N-ary Tree
N-ary Tree ( k-way Tree )
「多元樹」就是分 N 岔的樹,每個節點可以有零個、一個、兩個、 …… 、 N 個小孩。
注意到:多元樹,節點只有一個小孩時,沒有左小孩、右小孩的差別;二元樹,節點只有一個小孩時,有左小孩、右小孩的差別。
Left Child/Right Sibling Representation
一棵多元樹,可以改用二元樹表示:多元樹的左小孩,是二元樹的左小孩;多元樹的其餘小孩(左小孩的兄弟),是二元樹的右小孩、右右小孩、 …… 。
芸芸多元樹,皆得簡化成二元樹;區區二元樹,便可描述出多元樹。萬流歸宗、一以貫之。
有興趣的讀者,可以觀察多元樹與轉化過的二元樹的前序、中序、後序、層序。也可以計算一下多元樹的節點數目、樹葉數目、高度。