Использование XML и JSON с Android: Часть 2. Создание гибридных Android-приложений с применением JSON

Сочетание JavaScript, JSON, функций обратного вызова и Java-кода Android-SDK для создания гибких мобильных приложений

В этом цикле из двух статей рассматриваются методы работы с двумя наиболее распространенными форматами данных, используемыми сегодня в Интернете – XML и JavaScript Object Notation (JSON) – на платформе Android. Первая часть была посвящена основам XML и JSON. Во второй части мы рассмотрим, как код JavaScript, размещенный в Webkit, обменивается JSON-данными с кодом Java™ в приложении для Android. Эта статья посвящена главным образом JSON, который проявляет себя как наиболее мощный и гибкий подход.

Фрэнк Эйблсон, проектировщик ПО, Независимый разработчик

Когда Фрэнк Эйблсон (Frank Ableson) закончил карьеру баскетболиста в команде своего колледжа, не заключив многолетнего контракта с «Лос-Анджедес Лейкерс», он занялся разработкой компьютерных программ. Он любит решать сложные задачи, особенно из области связи и интерфейсов с аппаратурой. Свободное время Фрэнк проводит со своей женой Никки и детьми. С ним можно связаться по адресу: frank@cfgsolutions.com.



13.04.2011

Для работы с примером кода к этой статье нужно установить Android SDK 1.5 или более поздней версии вместе с Eclipse. Подробнее о настройке этой среды можно прочесть на сайте для разработчиков Android. См. соответствующие ссылки в разделе Ресурсы.

Введение

Трудно представить себе ИТ-сектор, более популярный, чем мобильные телефоны. Многочисленные платформы соперничают за первенство по объемам продаж и популярности. Устройства представляют собой передовые образцы инженерной мысли, но главным движущим фактором их популярности служит пользовательский опыт, ставший возможным благодаря огромному количеству приложений, доступных для этих платформ. В частности, в последнее время за сердца и кошельки деловых клиентов и потребителей состязаются платформы iPhone и Android.

Часто используемые сокращения

  • API: Application Programming Interface – интерфейс программирования приложений
  • CSS: Cascading Style Sheets – каскадные таблицы стилей
  • HTML: HyperText Markup Language – язык разметки гипертекста
  • IDE: Integrated development environment – интегрированная среда разработки
  • SDK: Software Developer Kit – комплект разработчика ПО
  • UI: User Interface – интерфейс пользователя
  • XML: Extensible Markup Language – расширяемый язык разметки

Большинство приложений, доступных для пользователей мобильных устройств, написано с помощью основных SDK, предоставляемых поставщиками платформ. Популярность мобильных устройств в сочетании с большим количеством талантливых программистов, которые набрали сноровку в Интернете за последнее десятилетие, привело к созданию новой модели – гибридному приложению. Оно использует как интерфейсы Web-браузера, так и стандартные мобильные компоненты. Гибридные приложения существуют и для iPhone, и Android, хотя в этой статье основное внимание уделяется гибридным приложениям для Android и использованию JavaScript и JSON.

Гибридные приложения строятся вокруг механизма WebKit, встроенного в элемент WebView Android. Это виджет пользовательского интерфейса, который предоставляет в распоряжение Android-программиста возможности WebKit. Его можно использовать для отображения удаленных Web-страниц внутри приложения, чтобы обеспечить знакомый пользовательский интерфейс как для разработчиков, так и для пользователей, а также мощную и гибкую среду JavaScript в рамках стандартного приложения Android.

Гибридные приложения часто используют виджет WebView, чтобы применить мощь WebKit в первую очередь к элементам пользовательского интерфейса, однако гибридные приложения делают больше, чем простое отображение в виджете некоторого кода HTML. Гибридные приложения универсальны – широта функциональности, содержащейся в Android SDK, в сочетании с Web-технологиями HTML, CSS и JavaScript приводит к тому, что возможности гибридных приложений ограничены лишь вашим воображением. Чтобы наполнить плотью идею гибридного приложения, в этой статье мы рассмотрим пример приложения с именем AndroidJSON, в котором для обмена данными реализуются операции взаимодействия между Activity, WebView и JSON. Это приложение демонстрирует взаимодействие между Activity и HTML/JavaScript, содержащимися в WebView, на примере функций JavaScript-калькулятора.

Сначала рассмотрим механизм WebKit, встроенный непосредственно в Android-приложение.


JavaScript-калькулятор, встроенный в Android

Большинство приложений на базе SDK Android содержит одну или несколько реализаций класса Activity. По существу, класс Activity представляет собой экран или страницу, содержащую элементы пользовательского интерфейса, с которыми работает пользователь приложения.

Activity отображает набор определенных программистом элементов, таких как кнопки, ярлыки, надписи, переключатели, списки и т.д. В SDK Android присутствуют все ожидаемые элементы. В дополнение ко всем этим элементам пользовательского интерфейса имеется специальный виджет, называемый WebView.

JavaScript-калькулятор демонстрирует симбиоз среды Java, Activity и среды JavaScript из WebView. Приложение выходит за рамки простого обращения к WebView для отображения HTML-контента – фактически, это создание Java-среды для обеспечения функциональности в среде JavaScript при такой тесной интеграции того и другого, которая позволяет воспринимать их как одно целое. Когда две среды взаимодействуют, обмен данными происходит в форме JSON для доставки различных функций, каждая из которых подробно рассматривается в этой статье. Начнем с выяснения того, как JavaScript-калькулятор использует виджет WebView.

Перед тем как погрузиться в детали, воспользуемся моментом, чтобы рассмотреть возможности самого приложения. На рисунке 1 показан экран приложения.

Рисунок 1. Демонстрация JavaScript-калькулятора в действии
Демонстрация JavaScript-калькулятора в действии

В этом примере стандартного Android-приложения AndroidJSON экран определяется с помощью компонента Activity. В верхней половине экрана расположены традиционные элементы пользовательского интерфейса, такие как TextView (статическая метка), an EditText (текстовое поле, в которое пользователь вводит формулу) и три кнопки (Simple, Complex и Make Red). В Activity есть также экземпляр элемента WebView, который отображает нижнюю половину экрана.

WebView отображает HTML-файл (index.html), содержащийся в Android-приложении (хотя его можно загрузить и из Интернета). Эта Web-страница содержит заголовок, пример текста, результаты расчета и шесть кнопок для выполнения различных функций (Log Info, Log Error, Dynamic, How Many Calls, History и Kill This App).

Файлы, относящиеся к этому проекту, – это AndroidJSON.java (код Android-приложения), index.html (Web-страница) и main.xml (файл макета пользовательского интерфейса, который мы рассмотрим позднее). Ссылки на эти файлы даны в разделе загрузок.

Сначала рассмотрим функции трех кнопок Activity.

Simple
Кнопка Simple вызывает обработку содержимого поля EditText как математического выражения. Обратите внимание, что содержимое поля EditText, или формула, передается в элемент WebView и обрабатывается в JavaScript.
Complex
Кнопка Complex посылает в WebView объект JSON для вычисления. Впоследствии этот объект интерпретируется кодом JavaScript, и с ним производятся математически манипуляции. Эта кнопка выбирает между функцией сложения элементов массива целых чисел и функцией перемножения элементов того же массива.
Make Red
Третья кнопка здесь главным образом ради забавы. При ее выборе к встроенному содержанию WebView применяется стиль, окрашивающий в красный цвет текстовые элементы, содержащиеся в теге <body>.

Теперь рассмотрим функции файла index.html, включаемые во время выполнения встроенного элемента WebView.

Log Info
Эта кнопка выполняет функцию обратного вызова в Android-приложении, чтобы сделать запись в категории Info журнала приложения.
Error Info
Эта кнопка выполняет функцию обратного вызова в Android-приложении, чтобы сделать запись в категории Error журнала приложения.
Dynamic
Эта кнопка выполняет функцию обратного вызова в Android-приложении, чтобы получить фрагмент текста, который представляет собой правильный код JavaScript. Этот код возвращается в WebView и исполняется, демонстрируя взаимодействие между обеими сторонами приложения. Обратите внимание, что этот подход уязвим для некоторых эксплойтов ввиду слепой опоры на функцию JavaScript eval. Однако здесь нас интересует только взаимодействие, а не создание коммерческого приложения.
How many calls
Каждый раз, когда вызывается одна из функций, в счетчик добавляется единица. Эта кнопка просто отображает содержимое счетчика.
History
Каждый раз, когда вызывается одна из функций, в массив JavaScript добавляется строка с именем этой функции. При нажатии кнопки History этот массив преобразуется в JSON и передается в стандартную часть приложения Android. Массив преобразуется в объект в коде Java, нумеруется, и каждый элемент массива записывается в журнал.
Kill This App
Эта кнопка здесь тоже просто ради забавы. Она инициирует обратный вызов, который прекращает действие Android посредством вызова функции finish().

Как и многие другие приложения, это Android-приложение использует встроенные возможности регистрации Android. Некоторые из снимков экрана, приведенных в этой статье, взяты из представления Dalvik Debug Monitor Service (DDMS) внутри Eclipse, где видно окно LogCat. За дополнительной информацией о том, как использовать инструменты разработки Android, обращайтесь по ссылкам в разделе Ресурсы.

На этом объяснение функций приложения окончено, и теперь мы посмотрим, как построен пользовательский интерфейс.


Построение пользовательского интерфейса

Пользовательский интерфейс для этого приложения включает в себя три описанных выше файла. Начнем с файла макета main.xml, который представлен в листинге 1.

Листинг 1. Файл макета пользовательского интерфейса main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView android:layout_width="fill_parent"  
android:layout_height="wrap_content" android:text="@string/title" />
    <EditText android:id="@+id/formula" android:layout_width="fill_parent" 
android:layout_height="wrap_content" android:text="" android:visible="False" />
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <Button android:text="Simple" android:id="@+id/btnSimple" 
android:layout_width="wrap_content" android:layout_height="wrap_content">
</Button>
        <Button android:text="Complex" android:id="@+id/btnComplex"
 android:layout_width="wrap_content" android:layout_height="wrap_content">
</Button>
        <Button android:text="Make Red" android:id="@+id/btnRed" 
android:layout_width="wrap_content" android:layout_height="wrap_content">
</Button>    
    </LinearLayout>
    <WebView android:layout_width="fill_parent" android:layout_height="fill_parent"
 android:id="@+id/calculator" android:layout_weight="1" />
</LinearLayout>

Этот макет содержит различные элементы пользовательского интерфейса. Обратите внимание, что наличие атрибута android:id позволяет приложению ссылаться на конкретный виджет внутри макета. Например, WebView содержит идентификаторкалькулятора; однако TextView не содержит идентификатора, так как его значение не изменяется в течение всей жизни приложения.

Метод onCreate() из AndroidJSON.java отвечает за расширение макета, как показано в листинге 2.

Листинг 2. Построение пользовательского интерфейса
public class AndroidJSON extends Activity {
    private final String tag = "AndroidJSON";
    private WebView browser = null;
    private int flipflop = 0;

    /** Вызывается при первоначальном создании операции. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final EditText formula = (EditText) this.findViewById(R.id.formula);
        final Button btnSimple = (Button) this.findViewById(R.id.btnSimple);
        final Button btnComplex = (Button) this.findViewById(R.id.btnComplex);
        final Button btnRed = (Button) this.findViewById(R.id.btnRed);
    // оставшаяся часть кода удалена для краткости – он показан в следующих листингах
}

Макет расширяется с помощью вызова setContentView(). Обратите внимание, что элементы пользовательского интерфейса создаются путем вызова метода findViewById(). Файл R.java создается автоматически каждый раз при сохранении файла main.xml. Элементы макета, содержащие атрибут android:id, становятся значениями в классе R.id, как показано в листинге 3.

Листинг 3. R.java
/* АВТОМАТИЧЕСКИ СГЕНЕРИРОВАННЫЙ ФАЙЛ.   НЕ ИЗМЕНЯТЬ. 
 *
 * Этот класс генерируется  автоматически инструментом aapt 
 * по данным ресурсов, которые он обнаружил.   
 * Его не следует изменять вручную. 
 */

package com.msi.androidjson;

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int icon=0x7f020000;
    }
    public static final class id {
        public static final int btnComplex=0x7f050002;
        public static final int btnRed=0x7f050003;
        public static final int btnSimple=0x7f050001;
        public static final int calculator=0x7f050004;
        public static final int formula=0x7f050000;
    }
    public static final class layout {
        public static final int main=0x7f030000;
    }
    public static final class string {
        public static final int app_name=0x7f040001;
        public static final int title=0x7f040000;
    }
}

Позднее мы вернемся к созданию кнопок, а пока сосредоточимся на создании элемента WebView, или виджета. Если кнопки и другие элементы пользовательского интерфейса весьма просты, то WebView требует значительно больших усилий. Но не волнуйтесь – это не так уж сложно, особенно с учетом частого применения верного метода вырезания и вставки! Фрагмент, представленный в листинге 4, вновь взят из метода onCreate() AndroidJSON.java.

Листинг 4. Настройка виджета WebView
        // подключение к нашему браузеру, чтобы с ним можно было работать
        browser = (WebView) findViewById(R.id.calculator);

        // установка клиента WebView для переопределения функциональности по умолчанию 
        browser.setWebViewClient(new wvClient());

        // получение параметров настройки, чтобы сконфигурировать свой экземпляр WebView 
        WebSettings settings = browser.getSettings();

        // JavaScript?  Конечно!
        settings.setJavaScriptEnabled(true);

        // очистка кэша
        browser.clearCache(true);

        // это необходимо для работы "alert()"
        browser.setWebChromeClient(new WebChromeClient());

        // добавление наших специальных функций в среду JavaScript
        browser.addJavascriptInterface(new CalculatorHandler(), "calc");

        // раскомментируйте это, если хотите использовать WebView 
        // как невидимый калькулятор! 
        //browser.setVisibility(View.INVISIBLE);

        // загрузка страницы, чтобы начать работу
        browser.loadUrl("file:///android_asset/index.html");

        // позволяет элементу получить фокус 
        // В некоторых версиях Android WebView неправильно работает с фокусом 
        // похоже, что это работает с Android 2.1, но не 2.2 
        // browser.requestFocusFromTouch();

В листинге 4 обратите внимание, что переменная Activity с именем browser сопряжена с элементом WebView. WebView – достаточно сложный класс, который может быть в высокой степени специализирован. Например, вам нужно создать несколько классов, чтобы получить ожидаемые функции, связанные с Web-браузером. Это одна из тех задач, для решения которых программист должен приложить определенное минимальное количество усилий, чтобы получить некоторые полезные функции. Однако нет предела тому, как далеко можно зайти в этой специализации. Для целей нашего приложения элемент WebView развернут в минимальной степени.

WebViewClient обеспечивает ловушки для захвата различных событий, таких как начало и окончание загрузки страницы, формирование повторного представления, перехват клавиатуры и многие другие события, которые программисты любят ловить и использовать. Аналогично, нужен экземпляр WebChromeClient, чтобы разрешить такие функции, как очень полезная функция JavaScript alert(). Класс WebSettings разрешает использование JavaScript в элементе.

Есть несколько способов обеспечить навигацию элемента WebView по странице. В этом приложении мы используем метод loadurl() с указанием полного пути к файлу index.html, упакованному в качестве ресурса проекта. За дополнительной информацией о настройке элемента WebView обращайтесь к документации пакета android.webkit (см. раздел Ресурсы). Файл с именем index.html загружается в элемент WebView непосредственно из ресурсов, поставляемых вместе с приложением. На рисунке 2 обратите внимание на папку assets. Это идеальное место для хранения HTML-файлов, используемых в гибридных приложениях. (См. текстовую версию рисунка 2.)

Рисунок 2. Проект в Eclipse
Проект в Eclipse

Пожалуй, самые важные и интересные аспекты работы с WebView начинаются на следующем шаге: подключение среды JavaScript WebView к коду Activity Android.


Подключение интерфейса JavaScript

Следующим шагом является активизация кода Java внутри Activity для взаимодействия с кодом JavaScript внутри HTML-файла, управляемого элементом WebView. Это достигается с помощью вызова метода addJavascriptInterface(), как в листинге 4.

Аргументами этой функции служат экземпляры класса Java и идентификатор пространства имен. Например, для нашего приложения определим пространство имен calc и реализуем код в классе с именем CalculatorHandler, как в листинге 5.

Листинг 5. Реализация CalculatorHandler
// обработчик Javascript 
    final class CalculatorHandler
    {
        private int iterations = 0;
        // запись в LogCat (Info)
        public void Info(String str) {
            iterations++;
            Log.i("Calc",str);
        }
        // запись в LogCat (Error)
        public void Error(String str) {
            iterations++;
            Log.e("Calc",str);
        } 
        // пример получения специальной функции, детали которой взяты из 
        // кода стандартного приложения Android
        public String GetSomeFunction()
        {
            iterations++;
            return "var q = 6;function dynamicFunc(v) { return v + q; }";
        }
        // Убить приложение        
        public void EndApp() {
            iterations++;
            finish();
        }
        public void setAnswer(String a)
        {
            iterations++;
            Log.i(tag,"Answer [" + a + "]");
        }
        public int getIterations()
        {
            return iterations;
        }
        public void SendHistory(String s)
        {
            Log.i("Calc","SendHistory" + s);
            try {
                JSONArray ja = new JSONArray(s);
                for (int i=0;i<ja.length();i++) {
                    Log.i("Calc","History entry #" + (i+1) + " is [" + ja.getString(i) 
+ "]");
                }
            } catch (Exception ee) {
                Log.e("Calc",ee.getMessage());
            }
        }
    }

В среде JavaScript мы обращаемся к методам CalculatorHandler посредством синтаксиса window.calc.methodname. Например, CalculatorHandler реализует метод с именем Info(), который принимает строковый аргумент и записывает его в журнал приложения. Чтобы получить доступ к этому методу из среды JavaScript, воспользуемся следующим синтаксисом: window.calc.Info("запись этой строки в журнал приложения!");.

Получив общее представление о том, как код Java вызывается из кода JavaScript, рассмотрим файл index.html, приведенный в листинге 6, чтобы увидеть, как вызываются различные методы.

Листинг 6. Обработка (и исполнение) файла index.html в элементе WebView
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=0.25,
    user-scalable=yes" />
<title>Android to JavaScript with JSON</title>
</head>
<script language="JavaScript">
var cmdHistory = new Array();
function startup() {
    try {
        window.calc.Info("Starting up....");
        cmdHistory[cmdHistory.length] = "startup";
    } catch (ee) {

    }
}
function PerformSimpleCalculation(formula) {
    try {
        cmdHistory[cmdHistory.length] = "PerformSimpleCalculation";
        var answer = eval(String(formula));
        document.getElementById('data').value = answer;
        window.calc.setAnswer(answer);
    }    catch (ee)     {
        window.calc.Error(ee);
    }
}
function PerformComplexCalculation(andmethod) {
    try    {
        /*
         * аргументом этой функции служит один объект, 
         * оперирующий двумя "членами или свойствами": 
         * это строка с именем, соответствующим нужной нам функции. 
         * массив аргументов: это массив целых чисел
         */
        //предупреждение(andmethod.operation);
        //предупреждение(andmethod.arguments.length);
        if (andmethod.operation == "addarray") {
            cmdHistory[cmdHistory.length] = "PerformCompleCalculation-addarray";
            var i;
            var result = 0;
            for (i=0;i<andmethod.arguments.length;i++) {
                result += andmethod.arguments[i];
            }
            document.getElementById('data').value = result;
            window.calc.setAnswer(result);
        }
        if (andmethod.operation == "multarray") {
            cmdHistory[cmdHistory.length] = "PerformCompleCalculation-multarray";
            var i;
            var result = 1;
            for (i=0;i<andmethod.arguments.length;i++) {
                result *= andmethod.arguments[i];
            }
            document.getElementById('data').value = result;
            window.calc.setAnswer(result);            
        }
    }    catch (ee)    {
        window.calc.Error(ee);
    }
}
function dynamicfunction()
{
    try {
        cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic";
        eval(String(window.calc.GetSomeFunction()));
        var result = dynamicFunc(parseInt(document.getElementById('data').value));
        document.getElementById('data').value = result;
    }catch (ee) {
        alert(ee);
    }
}
</script>
<body >
<center>
<h3>Running in Web View :)</h3>
this is some sample text here <br />
<input type="text" id="data" value="starting value"><br />
<button onclick="window.calc.Info(document.getElementById('data').value);">Log
 Info</button>&nbsp;&nbsp;
<button onclick="window.calc.Error(document.getElementById('data').value);">Log
 Error</button><br />
<button onclick="dynamicfunction();">Dynamic</button>
<button onclick="alert(String(window.calc.getIterations()));">How 
    Many Calls</button>
<button onclick="window.calc.SendHistory(JSON.stringify(cmdHistory));">
    History</button>
<button onclick="if (window.confirm('End App?')) window.calc.EndApp();">Kill This
 App</button><br />
</center>
</body>
</html>

Рассмотрим обработчики кнопок в конце листинга 6. По существу, это вызов методов в пространстве имен window.calc, реализованный в классе CalculatorHandler AndroidJSON.java.

Листинг 5 и листинг 6 вместе демонстрируют взаимодействие кода, начатое в среде JavaScript и реализованное в исходном файле Java. Но как инициировать работу кода Activity, которую нужно выполнить в WebView?

Настало время углубиться в код Java.


Вставка кода JavaScript

Начнем с задачи передачи математической формулы в код JavaScript для вычисления. Одна из замечательных (и опасных!) особенностей JavaScript – это функция eval(). Она позволяет выполнять оценку строки кода во время исполнения. В этом примере мы берем строку из элемента EditText и передаем ее среде JavaScript для оценки. В частности, вызываем функцию PerformSimpleCalculation(), присутствующую в листинге 6.

Листинг 7 содержит код из AndroidJSON.java, ответственный за обработку нажатия кнопок.

Листинг 7. Вызов функции PerformSimpleCalculation() JavaScript из Java
  btnSimple.setOnClickListener(new OnClickListener()
  {
       public void onClick(View v) {
         Log.i(tag,"onClick Simple");
         // Выполните действия по щелчку
         try
         {
            String formulaText =  formula.getText().toString();
            Log.i(tag,"Formula is [" + formulaText + "]" );
            browser.loadUrl("javascript:PerformSimpleCalculation(" + formulaText + ");");
         }
         catch (Exception e)
         {
               Log.e(tag,"Error ..." + e.getMessage());
         }
       }
  });

Несмотря на большое число строк этого метода, сосредоточимся только на строке browser.loadurl(), которая передает строку в формате javascript:<code to execute>.

Этот код JavaScript вводится в текущую страницу WebView и исполняется. Таким образом, код Java может исполнять код JavaScript, определенный в WebView.

В примере Simple передается строка. Однако как работать с более сложной структурой? Вот где может помочь JSON. В листинге 8 показано обращение к функции PerformComplexCalculation(), приведенной в листинге 6.

Листинг 8. Вызов более сложной функции с передачей объекта JSON
btnComplex.setOnClickListener(new OnClickListener()
{
     public void onClick(View v) {
         Log.i(tag,"onClick Complex");
         // Выполнение действия по щелчку
         try
         {
             String jsonText = "";

             if (flipflop == 0)
             {     
                 jsonText = "{ \"operation\" : \"addarray\",\"arguments\" :
 [1,2,3,4,5,6,7,8,9,10]}";
                 flipflop = 1;
             } else {
                 jsonText = "{ \"operation\" : \"multarray\",\"arguments\" :
 [1,2,3,4,5,6,7,8,9,10]}";
                 flipflop = 0;
             }
             Log.i(tag,"jsonText is [" + jsonText + "]" );
             browser.loadUrl("javascript:PerformComplexCalculation(" + jsonText + ");");
         }
         catch (Exception e)
         {
             Log.e(tag,"Error ..." + e.getMessage());
         }

     }
});

Рассмотрим функцию JavaScript PerformComplexCalculation из листинга 6. Обратите внимание, что аргумент – это не строка, а созданный нами объект.

  • operation – имя функции или процедуры обработки.
  • arguments – массив целых чисел.

Объект содержит только два свойства, но для решения больших задач его можно сделать сколь угодно сложным. В данном примере функция JavaScript PerformComplexCalculation() поддерживает две операции: addarray и multarray. Когда они выполняют свою работу в ответ на вызов, результат возвращается в код Java с помощью функции window.calc.setAnswer. Таким образом, происходит двухсторонний обмен данными между кодом Java и JavaScript.

В этом примере передается объект JSON, но опыт показывает, что при работе со строками Java, возвращаемыми из кода Java их удобно преобразовывать в строки JavaScript. Это можно сделать путем передачи значения функции String, как в следующем примере: eval(String(formula));.

Функция JavaScript eval() использует строки JavaScript. Без преобразования функция eval практически не делает ничего.

В несколько более сложном примере мы проследим последовательность действий кода при нажатии кнопки Dynamic в WebView.

В последнем примере кода рассмотрим передачу массива строк из среды JavaScript в среду Java.


Обмен объектами JSON

Код JavaScript в примере приложения (index.html) записывает локальные вызововы функций в массив уровня страницы с именем cmdHistory. Каждый раз, когда вызывается функция, в этот массив добавляется новая запись. Например, когда вызывается dynamicfunction(), новая строка будет содержать: cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic";.

В этом подходе нет ничего особенного, это просто пример сбора данных об использовании функций на уровне страницы. Эти данные полезно хранить в базе данных приложения Android. Как вернуть их в код Java?

Чтобы передать массив строковых объектов, вызовем функцию JSON.stringify и передадим ей массив в качестве аргумента. При желании для настройки способа форматирования определенного свойства сложного объекта можно использовать функцию stringify. За дополнительной информацией о том, как это сделать, обращайтесь на json.org (см. раздел Ресурсы).

На рисунке 3 видно, что добавляется в журнал после анализа массива JSON в результате типичного запуска приложения.

Рисунок 3. Разбор массива JSON, переданного из JavaScript
Разбор массива JSON, переданного из JavaScript

Этот пример только сохраняет строковые данные, так что нам придется добавить его в более длинную строку и вызвать функцию Simple в CalculatorHandler, которая, в свою очередь, проанализирует эту строку. Но что если приложение должно отслеживать другие данные, такие как значение определенных переменных, или даже составить профиль кода, записывая продолжительность конкретных вызовов функций? Очевидно, что возможность записи и обмена объектами представляет интерес и в более сложных сценариях.


Заключение

Эта статья знакомит с методами передачи данных между кодом Java в приложении для Android и кодом JavaScript в WebView, а также с более общими свойствами гибридных приложений с использованием WebKit. В гибридных приложениях смешиваются JavaScript, JSON, функции обратного вызова, Java-код из Android SDK и самый важный компонент – ваше воображение – для создания гибких и мощных мобильных приложений.


Загрузка

ОписаниеИмяРазмер
Пример исходного кодаandjson.zip58 КБ

Ресурсы

Научиться

Получить продукты и технологии

  • Android SDK: Загрузка Android SDK, ссылки на справочные материалы по API и последние новости об Android на официальном сайте разработчиков Android. В примерах для этой статьи будет работать версия 1.5 и выше.(EN)
  • Eclipse: получите последнюю версию Eclipse IDE.(EN)
  • Android Open Source Project: Android – это ПО с открытым исходным кодом, что означает, что здесь можно получить исходный код. (EN)
  • JSONLint: попробуйте этот онлайн-валидатор JSON.(EN)
  • Ознакомительные версии продуктов IBM: загрузите или изучайте онлайновые версии продуктов в IBM SOA Sandbox и овладевайте инструментами разработки приложений и связующим ПО для DB2®, Lotus®, Rational®, Tivoli® и WebSphere®.(EN)

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML
ArticleID=646837
ArticleTitle=Использование XML и JSON с Android: Часть 2. Создание гибридных Android-приложений с применением JSON
publish-date=04132011