讓 Android 開發像 web 開發一樣爽

作者:hanks https://juejin.im/post/5bf12c8751882511a8527ed4

做移動端開發,最蛋疼的就是不能動態發版,不能像 web 那樣發版立即全部用戶生效,然而 lua語言 爲其提供了可能性。lua 是一種腳本語言,使用 lua 來構建跨平臺原生應用有許多好處,比如 lua 語言簡潔高效,可移植性好, Lua虛擬機極爲輕量,僅佔用200到300k的內存空間,且速度極快。

演示

寫一個簡單的代碼演示一下。新建一個 lua 文件,叫做 view.lua, 放在手機的 sdcard 上,文件目錄爲 /sdcard/view.lua

require "import"
import "android.widget.*"
import "android.content.*"

function getView()
    local layout = {
        LinearLayout,
        orientation = "vertical",
        layout_width = "fill",
        layout_height = "fill",
        {
            Button,
            id = "btn",
            layout_marginTop="8dp",
            layout_width = "fill",
            layout_height = "50dp",
            text = "click"
        },
    }
    local view = loadlayout(layout)
    return view
end

運行一下,

屏幕中上半部分是 Android 的 xml 佈局中寫好的代碼,當點擊運行按鈕時,加載 lua 腳本,返回一個 View 對象,然後添加到佈局中。一個簡單的 lua 腳本編寫的視圖就寫好了。 接下來修改一下,設置個點擊事件。

require "import"
import "android.widget.*"
import "android.content.*"

function getView()
    local layout = {
        LinearLayout,
        orientation = "vertical",
        layout_width = "fill",
        layout_height = "fill",
        {
            Button,
            id = "btn",
            layout_marginTop="8dp",
            layout_width = "fill",
            layout_height = "50dp",
            text = "click"
        },
    }
    local ids = {} -- store ids to find view
    local view = loadlayout(layout, ids)
    ids.btn.onClick = function()
        Toast.makeText(activity,"2333",0).show()
    end
    return view
end

運行效果

再來個稍微複雜點的例子,寫個列表,新建 list.lua 文件,放在手機的 sdcard/list.lua

require "import"
import "android.widget.*"
import "android.content.*"
import "android.view.View"
import "androlua.LuaHttp"
import "androlua.LuaAdapter"
import "androlua.LuaImageLoader"

local JSON = require("cjson")
local uihelper = require('uihelper')

-- create view table
local layout = {
    LinearLayout,
    orientation = "vertical",
    layout_width = "fill",
    layout_height = "fill",
    {
        ListView,
        id = "listview",
        dividerHeight = 0,
        layout_width = "fill",
        layout_height = "fill",
    },
}

local item_view = {
    FrameLayout,
    layout_width = "fill",
    layout_height = "240dp",
    {
        ImageView,
        id = "iv_image",
        layout_width = "fill",
        layout_height = "fill",
        scaleType = "centerCrop",
    },
    {
        TextView,
        id = "tv_title",
        background = "#66000000",
        layout_width = "fill",
        layout_height = "fill",
        padding = "32dp",
        gravity = "center",
        maxLines = "5",
        lineSpacingMultiplier = '1.2',
        textSize = "14sp",
        textColor = "#CCFFFFFF",
    },
}


local data = {
    dailyList = {}
}
local adapter

local function getData()
    -- http://baobab.kaiyanapp.com/api/v1/feed
    local url = data.nextPageUrl
    if url == nil then url = 'http://baobab.kaiyanapp.com/api/v1/feed?udid=3e7ee30c6fc0004a773dc33b0597b5732b145c04' end
    if url:find('udid=') == nil then url = url .. '&udid=3e7ee30c6fc0004a773dc33b0597b5732b145c04' end
    print(url)
    LuaHttp.request({ url = url }, function(error, code, body)
        if error or code ~= 200 then
            print('fetch data error')
            return
        end
        local str = JSON.decode(body)
        uihelper.runOnUiThread(activity, function()
            data.nextPageUrl = str.nextPageUrl
            local list = str.dailyList[1].videoList
            for i = 1, #list do
                data.dailyList[#data.dailyList + 1] = list[i]
            end
            adapter.notifyDataSetChanged()
        end)
    end)
end

local function launchDetail(item)
    Toast.makeText(activity, item.title, 0).show()
end

function getView()
    local view = loadlayout(layout)
    adapter = LuaAdapter(luajava.createProxy("androlua.LuaAdapter$AdapterCreator", {
        getCount = function() return #data.dailyList end,
        getItem = function(position) return nil end,
        getItemId = function(position) return position end,
        getView = function(position, convertView, parent)
            position = position + 1 -- lua 索引從 1開始
            if position == #data.dailyList then
                getData()
            end
            if convertView == nil then
                local views = {} -- store views
                convertView = loadlayout(item_view, views, ListView)
                if parent then
                    local params = convertView.getLayoutParams()
                    params.width = parent.getWidth()
                end
                convertView.setTag(views)
            end
            local views = convertView.getTag()
            local item = data.dailyList[position]
            if item then
                LuaImageLoader.load(views.iv_image, item.coverForFeed)
                views.tv_title.setText(item.title)
            end
            return convertView
        end
    }))
    listview.setAdapter(adapter)
    listview.setOnItemClickListener(luajava.createProxy("android.widget.AdapterView$OnItemClickListener", {
        onItemClick = function(adapter, view, position, id)
            launchDetail(data.dailyList[position + 1])
        end,
    }))
    getData()
    return view
end

複製代碼創建 listView , 設置 adapter ,網絡請求,刷新列表。看下效果吧。

代碼放到了 github

:https://github.com/hanks-zyh/luaDevAndroid

原理圖

寫了幾篇文章比較詳細的介紹了原理,想了解的可以看一下

Android 與 Lua 探究 lua 在 Android 中的應用 Lua 嵌入 Android 原理

支持 iOS 嗎?

Lua 是用 c 語言開發的,可移植性比較好,想支持 iOS 的話,原理時一樣的,不過參考目前已有的跨平臺技術。關於跨平臺方面的一些個人見解,目前已有的跨平臺技術每當涉及到不同平臺的特性時,事情就比較蛋疼了,需要單獨去適配,還有建立一堆連接庫,比如選取本地圖片,不同平臺的數據庫,平臺特有 api,真是一份代碼到處運行終是夢,一份兒代碼到處採坑纔是真。

Android 開發能支持到什麼程度?

看到了上面的原理圖就可以知道,支持 Android SDK 幾乎所有的 API。

— — — END — — —

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章