Translate

понедельник, 22 августа 2011 г.

Программирование под android. Пишем простейшее приложение на android. Локализация.

   Пишем приложение для решения квадратных уравнений. Локализация.
  Давайте же напишем простейшее приложение и локализуем его на русский.


  Для локализации приложений на android создают специальные xml-файлы, в которых прописывают одни и те же тексты на разных языках, в зависимости от настроек языка юзера, использующего приложение. Локализованные ресурсы для каждого языка хранятся в папках с именем вида values-<код языка>. Коды распространенных языков:

  en-английский
  es-испанский
  fr-французский
  de-немецкий
  ja-японский
  ko-корейский
  ru-русский

  При этом, если в настройках языка пользователя стоит язык, для которого мы не создавали локализованные ресурсы, они будут браться из папки values (просто). Поэтому туда логично помещать англоязычные ресурсы.

  Пример системы хорошо локализованного приложения:


 Cоздадим в папке res корня приложения директорию values-ru, а также создадим в ней файл strings.xml: контекстное меню на папке->создать->Other->Android->Android XML File->называем и создаем.
  Откроем вкладку strings.xml внизу, чтобы обратится к содержимому xml-файла приложения, и скопируем туда содержимое аналогичного англоязычного файла. Теперь там XML-код:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, ForBlogActivity!</string>
    <string name="app_name">ForBlog</string>
</resources>

  Удалите строку <string name="hello">Hello World, ForBlogActivity!</string> из обоих файлов.
  У каждого из строковых ресурсов есть название - оно в атрибуте name, и само содержание строки - между ><. Конечно, эти надписи надо переводить.
  Напишем простое приложения, которое будет решать квадратное уравнение:
   В верхней части находятся 3 поля ввода (для коэффициентов уравнения - a, b и с), разделенные вспомогательными текстовыми полями. Внизу находятся 2 кнопки: одна очищает все поля и переводит фокус на поле для ввода первого коэффициента, а вторая решает уравнение. Решение представляется пользователю как всплывающее уведомление, исчезающее через некоторое время, называемое Toast.Оно будет содержать текст Root of equation is <корень> при наличие у уравнения одного корня, Roots of equation is ( <корень1> ; <корень2> ) при наличии двух корней и No roots при отсутствие действительных корней.
  Сначала надо подготовить строковые ресурсы приложения. Их должно быть 7:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">ForBlog</string>
    <string name="note1">Clean</string>
    <string name="note2">Solve</string>
    <string name="note3">Roots of equation is </string>
    <string name="note4">Root of equation is </string>
    <string name="note5">No roots</string>
    <string name="note6">Incorrect data</string>
</resources>

   Смысл первых 6 понятен, а 7-е является сообщением об ошибке, если содержимое какого-либо поля ввода нельзя интерпретировать как число.
   Теперь взглянем на файл главной Activity:

package com.dimiter.for_blog;

import android.app.Activity;
import android.os.Bundle;
public class ForBlogActivity extends Activity{
    @Override
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
   }
}

 Верхние строки подключают пару классов из java-библиотеки.
  Наша Activity есть класс, унаследованный от Activity - вот что гласит 4 строка. Затем объявляется метод onCreate, который вызывается при создании Activity. Здесь происходит ее инициализация (первая строка) и загрузка пользовательского интерфейса из ресурсов. Класс R хранит ссылки на ресурсы, после R указывается тип ресурса, а затем его название. При вызове SetContentView пользовательский интерфейс переписывается, поэтому при повторном ее вызове ранее загруженный интерфейс пропадет.
  Выше надписи @Override можно объявлять поля класса - специальные параметры, которые видны в любом месте класса. Здесь мы объявим текстовые поля и кнопки и инициализируем их в onCreate.
  Но для начала надо добавить их к пользовательскому интерфейсу, для чего откроем файл main.xml.
 Изменять интерфейс здесь можно 2 способами - писать xml-код интерфейса вручную или воспользоваться специальным мастером в другой вкладке - GraphicalLayout. Обычно используют оба метода - второй для наброски GUI, а первый для редактирования мелких деталей.
  Виджеты в UI всегда объединены в группы - в нашем случае был создан вертикальный LynearLayout c одним текстовым полем. Удалим его (поле), убрав в xml - коде <TextView>...</>
  Теперь нам нужно создать горизонтальный LynearLayout и поместить его в дефолтный контейнер для виджетов и их групп (вертикальный LynearLayout). Для сего заглянем в GraphicalLayout и перенесем виджет LynearLayout Horizontal на экран - должна выделиться небольшая полоска.
  Теперь в этот контейнер можно поместить виджеты интерфейса: выбираем поочередно стандартное поле ввода и текстовое поле и помещаем их на экран. Затем кнопки: их мы не будем помещать на горизонтальный LynearLayout, а просто перетащим пониже него, чтобы они занимали весь экран по горизонтали.



  Теперь приступим к мелкому редактированию интерфейса приложения. На текстовых полях и кнопках нужно сделать соответствующие надписи. Для этого щелкаем на виджет и в xml - коде изменяем их свойство text. Текстовое содержимое полей очевидно, а вот у кнопок его нужно брать из ресурсов. Для этого используется запись: @string/<имя ресурса>.
  Также нам нужно задать каждому используемому в программном коде виджету свой id. Изменим свойство id у компонентов на +id/<наш id>. У полей ввода он будет a, b и c соответственно, а у кнопок - cl и sl.
  Полный 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"
    >
    <LinearLayout android:layout_width="fill_parent" android:id="@+id/linearLayout1" android:layout_height="wrap_content">
        <EditText android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="wrap_content" android:id="@+id/a" >
            <requestFocus></requestFocus>
        </EditText>
        <TextView android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_height="wrap_content" android:id="@+id/textView1" android:text="*x^2"></TextView>
        <EditText android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="wrap_content" android:id="@+id/b" ></EditText>
        <TextView android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_height="wrap_content" android:id="@+id/textView2" android:text="*x"></TextView>
        <EditText android:layout_width="wrap_content" android:layout_weight="1" android:layout_height="wrap_content" android:id="@+id/c"></EditText>
        <TextView android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_height="wrap_content" android:id="@+id/textView3" android:text="=0"></TextView>
    </LinearLayout>
    <Button android:text="@string/note1" android:id="@+id/cl" android:layout_width="fill_parent" android:layout_height="wrap_content"></Button>
    <Button android:text="@string/note2" android:id="@+id/sl" android:layout_width="fill_parent" android:layout_height="wrap_content"></Button>
</LinearLayout>

  Пришло время писать Java-код. Сначала объявим поля класса:

private EditText A;
private EditText B;
private EditText C;
private Button Clean;
private Button Solve;
private static final double ACCURACY=1000;

  Последнее поля объявлено с модификатором final - является константой, оно показывает количество цифр после запятой в ответах программы.
 Инициализируем виджеты в onCreate:

  A=(EditText) findViewById(R.id.a);
  B=(EditText) findViewById(R.id.b);
  C=(EditText) findViewById(R.id.c);
  Clean=(Button) findViewById(R.id.cl);
  Solve=(Button) findViewById(R.id.sl);
  Clean.setOnClickListener(this);
  Solve.setOnClickListener(this);
  При этом Eclipse обязательно ругнется на отсутствие необходимых классов - просто щелкайте на значек ошибки справа и выбирайте импорт.
 В первых 5 строках мы инициализировали виджеты по их id. id также является ресурсом. В последних 2 строках я подписал кнопки на событие нажатия на них - теперь общий обработчик кликов - которого мы сейчас вставим - будет реагировать на нажатие этих кнопок.
  Последние 2 строчки вызываю ошибку, потому что никакого обработчика у нас пока и нету. Кликнем на ошибку и выберем Let... , который реализует соответствующий интерфейс. Затем Eclipse ругнется на отсутствие самого обработчика. который можно добавить таким же способом.
  В обработчике нужно прописать действия по нажатию на кнопки. Если была нажата кнопка Clean, очистим поля и переведем фокус в первое из них:
       if (v==Clean){
            A.setText("");
            B.setText("");
            C.setText("");
            A.requestFocus();
        }
    При нажатие на Solve нужно решить уравнение:
if (v==Solve){
            double a=0;
            double b=0;
            double c=0;
            double r1=0;
            double r2=0;
            try{
                a=Double.parseDouble(A.getText().toString());
                b=Double.parseDouble(B.getText().toString());
                c=Double.parseDouble(C.getText().toString());
            }
            catch(Exception e){
                Toast.makeText(this, R.string.note6, Toast.LENGTH_LONG).show();
                return;
            }
            double D;
            D=b*b-4*a*c;
            if (D<0){
                Toast.makeText(this, R.string.note5, Toast.LENGTH_LONG).show();
            }
            if (D==0){
                r1=Math.round(-b/(2*a)*ACCURACY)/ACCURACY;
                Toast.makeText(this, getString(R.string.note3)+" "+r1, Toast.LENGTH_LONG).show();
            }
            if (D>0){
                r1=Math.round((-b+Math.sqrt(D))/(2*a)*ACCURACY)/ACCURACY;
                r2=Math.round((-b-Math.sqrt(D))/(2*a)*ACCURACY)/ACCURACY;
                Toast.makeText(this, getString(R.string.note3)+" ( "+r1+" ; "+r2+" )", Toast.LENGTH_LONG).show();
            }
}

   Сначала объявим 5 локальный переменных - 3 отвечают за коэффициенты в уравнении, а 2 -за корни. Здесь им нужно дать какие-то значения, иначе мы Java выдаст ошибку. Мы их все равно потом переопределим, поэтому напишем нули.
  Далее занесем в переменные значения текстовых полей. Так как у нас нет гарантии, что в полях именно числа, заключим все это в блок обработки исключений try-catch. В блоке catch помещается код, который будет вызван при при наличии исключения, где e - тип ошибки, возникшей в блоке try. Без подобной проверки в случае неверных данных прога вылетела бы с сообщением о неизвестной ошибке.
Обратите внимание на конструкцию вызова уведомления: суть первого параметра будет разобрана позднее, второй - текст уведомления, в третий - продолжительность показа - Toast.LENGHT_LONG или Toast.LENGHT_SHORT. Строковые ресурсы в Toast можно использовать напрямую, если выводиться только строка из ресурсов, а если ее следует соединить с другой строкой, нужно обрабатывать ссылку методом getString(), как показано дальше. При возникновении ошибки нужно вывести сообщение и выйти из обработчика события - return.
  Затем объявляем переменную дискриминанта. Далее следует его определение и ветвление - расчет по различным формулам в зависимости от соотношения дискриминанта и нуля. Стоит обратить внимание на то, что корни перед выводом округляются посредством умножением на константу точности, округлением до целого и последующим делением на константу точности.
Полный код класса:

package com.dimiter.for_blog;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class ForBlogActivity extends Activity implements OnClickListener {
    /** Called when the activity is first created. */
    private EditText A;
    private EditText B;
    private EditText C;
    private Button Clean;
    private Button Solve;
    private static final double ACCURACY=1000;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        A=(EditText) findViewById(R.id.a);
        B=(EditText) findViewById(R.id.b);
        C=(EditText) findViewById(R.id.c);
        Clean=(Button) findViewById(R.id.cl);
        Solve=(Button) findViewById(R.id.sl);
        Clean.setOnClickListener(this);
        Solve.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if (v==Clean){
            A.setText("");
            B.setText("");
            C.setText("");
            A.requestFocus();
        }
        if (v==Solve){
            double a=0;
            double b=0;
            double c=0;
            double r1=0;
            double r2=0;
            try{
                a=Double.parseDouble(A.getText().toString());
                b=Double.parseDouble(B.getText().toString());
                c=Double.parseDouble(C.getText().toString());
            }
            catch(Exception e){
                Toast.makeText(this, R.string.note6, Toast.LENGTH_LONG).show();
                return;
            }
            double D;
            D=b*b-4*a*c;
            if (D<0){
                Toast.makeText(this, R.string.note5, Toast.LENGTH_LONG).show();
            }
            if (D==0){
                r1=Math.round(-b/(2*a)*ACCURACY)/ACCURACY;
                Toast.makeText(this, getString(R.string.note3)+" "+r1, Toast.LENGTH_LONG).show();
            }
            if (D>0){
                r1=Math.round((-b+Math.sqrt(D))/(2*a)*ACCURACY)/ACCURACY;
                r2=Math.round((-b-Math.sqrt(D))/(2*a)*ACCURACY)/ACCURACY;
                Toast.makeText(this, getString(R.string.note3)+" ( "+r1+" ; "+r2+" )", Toast.LENGTH_LONG).show();
            }
        }
    }





   Теперь осталось запустить приложение. Для этого нажмите на значек с зеленой стрелкой в верхнем меню. Система, возможно, предложит создать виртуальное устройство. Создав и запустив виртуальный девайс, нажмите на MENU и вы увидите экран приложения. 

   

Комментариев нет:

Отправить комментарий

Related Posts Plugin for WordPress, Blogger...