четверг, 16 октября 2008 г.

Знакомство с Android. Часть 3: Использование диалогов

В этой части мы сделаем проверку вводимых параметров по следующим правилам:
  • Число столбцов должно быть не меньше 5 и не больше 25.
  • Число строк должно быть не меньше 5 и не больше 35.
  • Начальное количество клеток должно быть не больше, чем ячеек на поле.
Если какое-то из этих условий не выполняется, будем выводить соответствующее предупреждение
Кроме того, мы добавим кнопку Close, при нажатии на которую приложение будет закрываться, спрашивая вначале согласие пользователя.

Простой диалог

Сначала добавим в класс StartActivity.java следующие константы:

StartActivity.java

// код результата проверки
private static final int ALERT_NONE = 0; // параметры введены верно
private static final int ALERT_COLUMNS = 1; // некорректное число столбцов
private static final int ALERT_ROWS = 2; // некорректное число строк
private static final int ALERT_CELLS = 3; // некорректное начальное число клеток

// границы допустимых значений числа столбцов
private static final int COLUMNS_MIN = 5;
private static final int COLUMNS_MAX = 25;

// границы допустимых значений числа строк
private static final int ROWS_MIN = 5;
private static final int ROWS_MAX = 35;
Теперь добавляем метод, осуществляющий проверку введенных параметров:

StartActivity.java

private int checkInputParameters(int cols, int rows, int cells)
{
    if (cols < COLUMNS_MIN || cols > COLUMNS_MAX)
    {
        return ALERT_COLUMNS;
    }
    
    if (rows < ROWS_MIN || rows > ROWS_MAX)
    {
        return ALERT_ROWS;
    }
    
    if (cells > rows * cols)
    {
        return ALERT_CELLS;
    }
    
    return ALERT_NONE;
}
Метод onClick теперь должен работать немного по-другому: сначала проверять введенные параметры, и, если проверка прошла (ALERT_NONE), открывать окно RunActivity, иначе же показывать предупреждение. Итак, onClick будет выглядеть так:

StartActivity.java

public void onClick(View v)
{
    EditText rowsEditor = (EditText)findViewById(R.id.rows_count);
    EditText colsEditor = (EditText)findViewById(R.id.columns_count);
    EditText cellsEditor = (EditText)findViewById(R.id.cells_count);
    
    int cols = Integer.parseInt(colsEditor.getText().toString());
    int rows = Integer.parseInt(rowsEditor.getText().toString());
    int cells = Integer.parseInt(cellsEditor.getText().toString());
    int alertCode = checkInputParameters(cols, rows, cells);
    if (alertCode != ALERT_NONE)
    {
        showDialog(alertCode);
        return;
    }
    Intent intent = new Intent();
    intent.setClass(this, RunActivity.class);
    
    intent.putExtra(RunActivity.EXT_COLS, cols);
    intent.putExtra(RunActivity.EXT_ROWS, rows);
    intent.putExtra(RunActivity.EXT_CELLS, cells);

    startActivity(intent);
    finish();
}
Метод showDialog(id) класса Activity пытается открыть диалог. При этом вызывается метод onCreateDialog, возвращающий объект класса Dialog. Так что нужно перекрыть метод onCreateDialog и сконструировать тот диалог, который нам нужен. Ну у нас тут всё просто, диалоги будут отличаться только выводимым сообщением, так что можно сделать следующее:
@Override
protected Dialog onCreateDialog(int id)
{
    DialogInterface.OnClickListener doNothing = new DialogInterface.OnClickListener()
    {
        public void onClick(DialogInterface dialog, int whichButton) 
        {
        }
    };
    int alertMessage;
    
    switch (id)
    {
        case ALERT_COLUMNS:
            alertMessage = R.string.alert_columns;
            break;
        case ALERT_ROWS:
            alertMessage = R.string.alert_rows;
            break;
        case ALERT_CELLS:
            alertMessage = R.string.alert_cells;
            break;
        default:
            return null;
    }
    
    return new AlertDialog.Builder(this)
        .setMessage(alertMessage)
        .setNeutralButton(R.string.ok, doNothing)
        .create(); 
}
В strings.xml при этом нужно добавить следующие значения:

strings.xml

<string name="alert_columns">Incorrect columns number: should be from 5 to 25</string>
<string name="alert_rows">Incorrect rows number: should be from 5 to 35</string>
<string name="alert_cells">Number of cells is greater then the size of grid</string>
<string name="ok">OK</string>
Итак, в методе onCreateDialog мы решили, какое сообщение (alertMessage) будем выводить, создали диалог с помощью AlertDialog.Builder, вывели туда сообщение, поставили единственную кнопку OK и привязали к ней обработчик doNothing, который ничего не делает (нам, в принципе, делать ничего и не надо). Аналогичным образом можно добавить иконку формы, добавить ещё кнопок и т.д.
Подробнее про то, как строятся диалоги, можно посмотреть в адроидовских сэмплах - там на самом деле все достаточно понятно и просто.
Теперь при вводе некорректных данных мы видим вот это:
Ошибка при вводе некорректных данных

Диалог для закрытия приложения

Добавим на форму RunActivity кнопку Close. Для этого напишем такую разметку в run.xml:

run.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:id="@+id/message"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dip"
    />
    <Button
        android:id="@+id/close"
        android:text="@string/close"
        android:textStyle="bold"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
</LinearLayout>
В strings.xml добавим следующие значения:

strings.xml

<string name="yes">Yes</string>
<string name="no">No</string>
<string name="close">Close</string>
<string name="submit_close">Are you sure you want to close this wonderful application?</string>
Теперь вносим изменения в класс RunActivity:

RunActivity.java

public class RunActivity extends Activity implements OnClickListener
{
    public static final String EXT_COLS = "cols";
    public static final String EXT_ROWS = "rows";
    public static final String EXT_CELLS = "cells";
    
    Button mCloseButton;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.run);

        mCloseButton = (Button) findViewById(R.id.close);
        mCloseButton.setOnClickListener(this);

        Bundle extras = getIntent().getExtras();
        int cols = extras.getInt(EXT_COLS);
        int rows = extras.getInt(EXT_ROWS);
        int cells = extras.getInt(EXT_CELLS);

        TextView message = (TextView)findViewById(R.id.message);
        message.setText("Rows: " + rows + "\nColumns: " + cols + "\nCells: " + cells);
    }

    public void onClick(View view)
    {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        
        builder
            .setMessage(R.string.submit_close)
            // кнопка "Yes", при нажатии на которую приложение закроется
            .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener()
                {
                    public void onClick(DialogInterface dialog, int whichButton) 
                    {
                        finish();                           
                    }
                })
             // кнопка "No", при нажатии на которую ничего не произойдет
            .setNegativeButton(R.string.no, new DialogInterface.OnClickListener()
                {
                    public void onClick(DialogInterface dialog, int whichButton) 
                    {
                        
                    }
                })
            .show();
    }
}
Объяснять тут особо нечего, и так все понятно. Теперь, при нажатии на кнопку Close, мы видим следующее:
Подтверждение закрытия приложения
При нажатии на Yes приложение закроется, на No — продолжит работу.
Исходники примера

9 комментариев:

Анонимный комментирует...

Дарья, спасибо за полезные примеры!!
у меня есть вопрос немножко off topic - как вам удается вставлять куски кода в blog. Я пробовал на blogspot.com - почему-то половину не видно ... пробовал pre тэги - не помогло. Буду признателен за совет. Спасибо!

darja комментирует...

У меня свой подсветчик синтаксиса. А в общем-то можно использовать любой существующий.

Анонимный комментирует...

Здравствуйте, Дарья.
Не могли бы Вы объяснить, зачем нам нужен обработчик doNothing?

Евгений комментирует...

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

Nikolay Noskov комментирует...

int cols=0;
int rows=0;
int cells=0;
try {
cols = Integer.parseInt(colsEditor.getText().toString());
rows = Integer.parseInt(rowsEditor.getText().toString());
cells = Integer.parseInt(cellsEditor.getText().toString());
} catch (Exception e) {

}
Я бы добавил, а то совсем легко приложение падает. :)

Vik комментирует...

Подскажите пожалуйста есть ли
возможность не закрывать приложение а вернутся к начальному окну приложения ?

Syslie комментирует...

2 Vik плохо читал предидущую статью - раз из первого окна во второе можно то и обратно так же) Только что проверил - работает.

Helmik комментирует...

При наводе курсором мышки на showDialog пишет:
this method is deprecated. Use the new DialogFragment class with FragmentManager instead. Думаю, стоит сделать update статьи.Но спасибо огромное за интересный материал, перехожу к 4-й части.

MaxTyT комментирует...

2 Vik я посто убрал finish() в первом окне, теперь при нажатии кнопки назад или кнопки Close переходит обратно