天天看點

阿齊茲的Python學習筆記——移動應用開發

移動應用開發

在Android上運作Python

至少有一個Python版本可以在Android上運作

[Scripting Layer for Android(SL4A)][1]允許在任何裝置上運作Python

SL4A支援Python 2,而不是Python 3

如何解決Python版本問題?

如果把使用者互動移到智能手機上,這樣模型和部分控制器代碼會保留在伺服器上(仍然運作Python 3),而視圖代碼和其餘控制器代碼将移到智能手機上,就需要重寫這些代碼進而在Python 2上運作

建立開發環境

Google提供了一個跨平台的[Android模拟器][2],允許跟據需要完成手機應用開發

配置SDK和模拟器:

  • 增加一個Android平台:打開Android SDK and AVD Manager(Android SDL和AVD管理器)工具,選擇Available Packages(可用包),然後安裝對應版本的Android平台
  • 建立一個新的Android虛拟裝置(AVD):為AVD指定一個名,并選擇一個目标,選擇虛拟SDcard的大小(512),點選”Create AVD”

AVD是一個模拟的Android手機

安裝和配置Android腳本環境:

  • 導航到以下Web位址:http://code.google.com/p/android-scripting
  • 下載下傳sl4_r2.apk檔案并安裝

為SL4A安裝增加Python:

  • 下載下傳并安裝python_for_android_r1.apk
  • 運作後點選Install來下載下傳、解壓并安裝面向Android的Python支援檔案

在Android上測試Python

測試安裝環境的腳本mydroidtest.py:

import android
app = android.Android()
msg = "Hello from Head First Python on Android"
app.makeToast(msg)
           

将腳本複制到模拟器的SD卡(在終端視窗執行):

tools/adb push mydroidtest.py /sdcard/sl4a/scripts
           

JSON資料交換格式

JSON中的JS代表JavaScript,ON代表對象記法,是Web上使用最廣泛的資料交換格式之一

通過使用你喜歡的程式設計語言所提供的JSON庫,就能建立可以交換的資料。如果可以讀取一個JSON資料流,還可以在必要時重新建立資料

為什麼使用JSON?

  • 這是一種基于文本的格式,與Web工作方式更一緻
  • 這是一個标準,在Python2和Python3上的工作完全相同,沒有相容性問題
  • 由于JSON與語言無關,是以完全可以使用其他程式設計語言編寫的Web工具與伺服器互動
>>> import json #導入JSON庫
>>> names = ['John', ['Johnny', 'Jack'], 'Michael', ['Mike', 'Mikey', 'Mick']]
>>> names
['John', ['Johnny', 'Jack'], 'Michael', ['Mike', 'Mikey', 'Mick']]
>>> to_transfer = json.dumps(names) #将Python多重清單轉換為一個JSON多重清單
>>> to_transfer
'["John", ["Johnny", "Jack"], "Michael", ["Mike", "Mikey", "Mick"]]'
>>> from_transfer = json.loads(to_transfer) #将JSON多重清單轉換回Python格式
>>> from_transfer
['John', ['Johnny', 'Jack'], 'Michael', ['Mike', 'Mikey', 'Mick']]
>>> names
['John', ['Johnny', 'Jack'], 'Michael', ['Mike', 'Mikey', 'Mick']]
           

增加一個新函數,傳回選手名清單:

def get_names_from_store():
    athletes = get_from_store
    response = [athletes[each_ath].name for each_ath in athletes]
    return(response)
           

将資料作為一個JSON資料流傳回給Web請求者;

import json
import athletemodel
import yate

names = athletemodel.get_names_from_store()

print(yate.start_response('application/json')) #Content-type行使用application/json
print(json.dumps(sorted(names)))
           

測試JSON生成的腳本時看到的行為可能存在差異,這取決于你使用的浏覽器

SL4A Android API

SL4A技術為底層Android API提供了一個高層API

通過6個Android API調用,可以在對話框中建立一個選項清單,并建立相應的正負按鈕,用來訓示使用者所做的選擇

import android

app = android.Android() #建立一個Android應用對象

app.dialogCreateAlert("Select an athlete:") 
app.dialogSetSingleChoiceItems(['Mikey', 'Sarah', 'James', 'Julie'])
app.dialogSetPositiveButtonText("Select")
app.dialogSetNegativeButtonText("Quit")
app.dialogShow() #在應用上顯示對話框
resp = app.dialogGetResponse().result #等待使用者的響應
           

向Web伺服器查詢名字清單,作為一個JSON數組傳回,并在智能手機上顯示這個清單:

import android
import json
import time
from urllib import urlencode #這些庫可以提供Web用戶端功能
from urllib2 import urlopen

hello_msg = 'Welcome to Coach Kelly's Timing App'
list_title = 'Here is your list of athletes:'
quit_msg = 'Quitting Coach Kelly's App.'
web_server = 'http://192.168.1.33.8080' #Web伺服器所在的Web位址
get_names_cgi = '/cgi-bin/generate_names.py'

def send_to_server(url, post_data=None):
    """這個函數取一個Web位址和一些可選資料,向Web伺服器發送一個Web請求,Web響應傳回給調用者"""
    if post_data:
        page = urlopen(url, urlencode(post_data))
    else:
        page = urlopen(url)
    return(page.read().decode("utf8"))

app = android.Android() #建立一個Android應用對象

def status_update(msg, how_long=):
    """這個函數用來在手機上顯示簡短的消息"""
    app.makeToast(msg)
    time.sleep(how_long)

status_update(hello_msg) #顯示歡迎消息
athlete_names = sorted(json.loads(send_to_server(web_server + get_names_cgi))) #把Web請求發送到伺服器,然後将JSON響應轉換為一個有序清單
app.dialogCreateAlert(title_list) 
app.dialogSetSingleChoiceItems(athlete_names)
app.dialogSetPositiveButtonText("Select")
app.dialogSetNegativeButtonText("Quit")
app.dialogShow()
resp = app.dialogGetResponse().result #等待使用者點選一個按鈕,然後指派給resp
status_update(quit_msg) #顯示退出消息
           

在Android上選擇清單

如果點選的是第一個按鈕,dialogGetResponse()調用的結果會設定為positive,如果點選的是第二個按鈕,則會設定為negative

dialogGetSelectedItems()調用會傳回所選清單項的索引值

get_data_cgi = '/cgi-bin/generate_data.py' #提供運作時的CGI的名

if resp['which'] in ('positive'):
    selected_athlete = app.dialogGetSelectedItems().result[] #索引值對應對話框傳回清單的第一個元素
    which_athlete = athlete_names[selected_athlete] #使用索引值查找選手名
    athlete = json.loads(send_to_server(web_server + get_data_cgi, {'which_athlete':which_athlete})) #向伺服器發送一個新的Web請求,擷取這個選手的資料
    athlete_title = which_athlete + 'top 3 times:'
    app.dialogCreateAlert(athlete_title) 
    app.dialogSetItems(athlete['Top3'])
    app.dialogSetPositiveButtonText('OK'))
    app.dialogShow()
    resp = app.dialogGetResponse().result
           

cgi-bin/generate_data.py CGI腳本:

import cgi
import json
import athletemodel
import yate

athletes = athletemodel.get_from_store() #從模型得到所有的資料
form_data = cgi.FieldStorage() #處理随請求發送的資料
athlete_name = form_data['which_athlete'].value
print(yate.start_response('application/json')) #啟動一個Web請求,資料類型為JSON
print(json.dumps(athletes[athlete_name])) #在Web響應中包含制定選手的資料,采用JSON格式
           

如何調試

CGI機制預設地會捕獲腳本發送到标準輸出(STDOUT)的所有輸出

将調試消息發送到Web伺服器的控制台,顯示到标準錯誤輸出(STDERR):

import sys #從标準庫中導入sys

print(json.dumps(athletes[athlete_name]), file=sys.stderr) #将輸出重定向到stderr
           

現在可以在Web伺服器的控制台看到Web響應發送的資料

JSON無法處理你的定制資料類型

标準庫的JSON庫隻能處理Python的内置類型,無法處理AthleteList對象

為AthleteList增加一個方法,将資料轉換為一個字典:

@property
def to_dict(self):
    return({'Name': self.name, 'DOB': self.dob, 'Top3':self.top3})
           

使用@property修飾這個方法,對類使用者來說這個方法就像一個新的屬性

為什麼使用@property?

to_dict()方法并沒有以任何方法改變對象資料的狀态,隻是把對象的屬性資料作為一個字典傳回。盡管to_dict()是一個方法,但它表現得更像一個屬性,使用@property修飾符可以指出這一點。類的使用者并不需要知道它們通路to_dict屬性時實際上在運作一個方法,他們看到的隻是一個統一的接口:屬性通路資料,而方法用來管理資料

在真正的手機上運作你的應用

将代碼複制到一個真正的裝置的多種選擇:

  1. 使用藍牙檔案傳輸
  2. 利用USB連接配接完成檔案傳輸
  3. 利用USB使用Android SDK的adb工具
  4. 通過WiFi使用檔案傳輸工具

通過WiFi使用檔案傳輸工具:

  1. 準備你的計算機:運作一個SSH伺服器
  2. 在Android手機上安裝AndFTP:AndFTP工具允許在計算機和Android手機之間通過FTP、SFTP、FTPS傳輸檔案(AndFTP預設使用FTP協定)
  3. 配置AndFTP:将它配置為使用SFTP作為傳輸協定與你的計算機連接配接

小結

  1. Python2、Python3的相容性問題
  2. SL4A、AVD
  3. JSON庫子產品
  4. urllib和urllib2庫子產品
  5. sys子產品的三種輸入流