В прошлый раз мы расставили кнопки согласно плану. Теперь пришло время подумать над логикой приложения.
База вопросов - строковый массив - будет хранится в ресурсах. Однако класть ее в strings.xml неправильно - тогда пришлось бы создавать для каждого вопроса новый ресурс.
Существует еще один вид ресурсов, позволяющий хранить массивы любых типов данных. Они хранятся в файле arrays.xml. Создадим такой. Для тестирования создадим подобие базы - она будет хранится в arrays.xml в следующем формате:
База вопросов - строковый массив - будет хранится в ресурсах. Однако класть ее в strings.xml неправильно - тогда пришлось бы создавать для каждого вопроса новый ресурс.
Существует еще один вид ресурсов, позволяющий хранить массивы любых типов данных. Они хранятся в файле arrays.xml. Создадим такой. Для тестирования создадим подобие базы - она будет хранится в arrays.xml в следующем формате:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="Questions">
<item>/nQuestion1/Variant11/Variant12/Variant13/Variant14/1/</item>
<item>/nQuestion2/Variant21/Variant22/Variant23/Variant24/2/</item>
<item>/nQuestion3/Variant31/Variant32/Variant33/Variant34/3/</item>
<item>/nQuestion4/Variant41/Variant42/Variant43/Variant44/4/</item>
<item>/nQuestion5/Variant51/Variant52/Variant53/Variant54/1/</item>
<item>/nQuestion6/Variant61/Variant62/Variant63/Variant64/2/</item>
<item>/nQuestion7/Variant71/Variant72/Variant73/Variant74/3/</item>
<item>/nQuestion8/Variant81/Variant82/Variant83/Variant84/4/</item>
</array>
</resources>Syhi-подсветка кода
Все, что расположено между тегами array, является единицами массива. Для каждого вопроса мы закодируем вопрос, его 4 варианта ответа и номер правильного в вашенаписанном виде. n - любой символ, который должен присутствовать, таковы особенности алгоритма обработки этих строк, который будет изложен и разобран ниже. Разделитель (знак /) теперь ни в коем случае нельзя использовать ни в вопросах, ни в ответах.<resources>
<array name="Questions">
<item>/nQuestion1/Variant11/Variant12/Variant13/Variant14/1/</item>
<item>/nQuestion2/Variant21/Variant22/Variant23/Variant24/2/</item>
<item>/nQuestion3/Variant31/Variant32/Variant33/Variant34/3/</item>
<item>/nQuestion4/Variant41/Variant42/Variant43/Variant44/4/</item>
<item>/nQuestion5/Variant51/Variant52/Variant53/Variant54/1/</item>
<item>/nQuestion6/Variant61/Variant62/Variant63/Variant64/2/</item>
<item>/nQuestion7/Variant71/Variant72/Variant73/Variant74/3/</item>
<item>/nQuestion8/Variant81/Variant82/Variant83/Variant84/4/</item>
</array>
</resources>Syhi-подсветка кода
В коде создадим 3 массива: первый содержит строки с вопросами, второй - двумерный - матрицу ответов, а третий - коды правильных вариантов. Также нужно объявить переменную, хранящую количество вопросов в базе. Заведем константу еще и для разделительного символа - вдруг нам захочется его изменить:
private static final int QUESTIONS=8;
private static final char DELIMITER='/';
private String[][] AnsMatrix=new String[VARIANTS][QUESTIONS];
private int[] RightAnswers=new int[QUESTIONS];
private String[] Ques=new String[QUESTIONS];
private TypedArray Base;Syhi-подсветка кода
private static final char DELIMITER='/';
private String[][] AnsMatrix=new String[VARIANTS][QUESTIONS];
private int[] RightAnswers=new int[QUESTIONS];
private String[] Ques=new String[QUESTIONS];
private TypedArray Base;Syhi-подсветка кода
Для извлечения и разбора вопросов из базу нужно создать объект специально класса, принимающий данные из ресурсов.
Теперь будем писать важную функцию LoadQuestions, которая распределит наши данные по массивам:
private void LoadQuestions(){
Resources res=getResources();
Base=res.obtainTypedArray(R.array.Questions);
for (int i=0;i<QUESTIONS;i++){
Ques[i]=getSubstringBetweenDelimiters(0,1,Base.getString(i));
for (int j=0;j<VARIANTS;j++){
AnsMatrix[j][i]=getSubstringBetweenDelimiters(j+1,j+2,Base.getString(i));
}
RightAnswers[i]=Integer.parseInt(getSubstringBetweenDelimiters(VARIANTS+1,VARIANTS+2,Base.getString(i)));
}
}Syhi-подсветка кода
Вероятно, вы заметили, что в этом коде использован метод getSubstringBetweenDelimiters(), который надо подготовить перед написанием алгоритма.Resources res=getResources();
Base=res.obtainTypedArray(R.array.Questions);
for (int i=0;i<QUESTIONS;i++){
Ques[i]=getSubstringBetweenDelimiters(0,1,Base.getString(i));
for (int j=0;j<VARIANTS;j++){
AnsMatrix[j][i]=getSubstringBetweenDelimiters(j+1,j+2,Base.getString(i));
}
RightAnswers[i]=Integer.parseInt(getSubstringBetweenDelimiters(VARIANTS+1,VARIANTS+2,Base.getString(i)));
}
}Syhi-подсветка кода
Он принимает 3 параметра: исходную строку, и два целых числа и определяют подстроку, лежащую в исходной строке между теми по счету разделителями, которые определяют первые 2 аргумента. Например, в строке "/cats/dogs/pets/rats/" при целых параметрах 2 и 3 должен возвратить строку pets. Код метода:
private String getSubstringBetweenDelimiters(int k, int m, String str){
int index1=0;
int index2=0;
int len=str.length();
int dels=0;
for (int i=0;i<len;i++){
if (str.charAt(i)==DELIMITER){
dels++;
}
if (dels==k){
index1=i;
}
if (dels==m){
index2=i;
}
}
return str.substring(index1+2, index2+1);
}Syhi-подсветка кода
Для извлечения подстроки нужно будет узнать индексы разделителей на заказанных местах. За это отвечают переменные index1 и index2. Затем определим длину исходной строки (для цикла) и инициализируем счетчик разделителей в 0. Затем обойдем всю строку, и если текущий символ является разделителем, прибавим к счетчику 1. Здесь же, если значение счетчика совпало с одним их целых аргументов функции, можно присваивать соответствующему индексу номер текущего символа.int index1=0;
int index2=0;
int len=str.length();
int dels=0;
for (int i=0;i<len;i++){
if (str.charAt(i)==DELIMITER){
dels++;
}
if (dels==k){
index1=i;
}
if (dels==m){
index2=i;
}
}
return str.substring(index1+2, index2+1);
}Syhi-подсветка кода
В конце мы просто возьмем подстроку от одного индекса до второго. Тут, правда, есть один нюанс: мы должны их немного изменить из за характера строковых операций Java.
Теперь вернемся к LoadQuestions(). Первые две строки инициализируют строковый массив из ресурсов.Затем мы обойдем все вопросы и:
-Занесем в массив вопросов подстроку от первого до второго разделителя.
-Для каждого из вариантов ответа занесем в соответствующую ячейку двумерного массива подстроку от 1+n до 2+n разделителя
-Последнюю часть строки определим как элемент массива кодов правильных ответов.
На сегодня все, в следующий раз мы завершим разработки нашего детища.
Скачать исходник всей программы можно здесь
Все классно, давно ищу такую программу. Как посмотреть на готовые исходники? Мне не все понятно. Где и в каком месте нужно прописать данный код?
ОтветитьУдалитьДобавил ссылку для скачивания исходников в конце статьи.
ОтветитьУдалитьБольшое спасибо за исходники теперь понятнее. Димитер скажите, а можно реализовать интерфейс программы похожый на ___http://www.youtube.com/watch?v=LStnG8tVfXc&feature=plcp вот эту. То есть нужно что-бы при выборе ответа была возможность указывать несколько правильных ответов. И сразу было видно, попадание или ошибка?
ОтветитьУдалитьДа, можно. Только для этого придется сильно менять код:
ОтветитьУдалить-в XML файле нужно будет вместо одного правильного ответа указывать много. Сами правильные ответы в пределах /набор ответов/ надо разделять каким-то специальным знаком
-лучше написать класс, содержащий массив из правильных ответов, сам массив мы должны получать путем разбора строки /набор ответов/ со специальными разделителями. Таким образом, придется хранить массив таких классов(вопросов же в базе много)
-изменить код нажатия на кнопки. Пусть теперь мы будем менять цвет кнопок (синий - выбран ответ, красный - нет). Метод для изменения цвета: .setBackgroundColor(); Цвет можно писать константами : Color.RED; Color.BLUE или в шестнадцатиричной форме (0xff44ff)
-при нажатии на кнопку с вопросом нужно будет проверить цвета всех кнопок и сверить их с набором правильных ответов из класса, затем вывести уведомление Toast о том, правильно ли выбраны ответы, затем перейти к следующему вопросу и покрасить все кнопки в начальный цвет
Димитер
ОтветитьУдалитьогромное спасибо, Димитер скажите а этот вариант подойдет для теста с большим количеством вопросов? или лучше с бд работать?
Да, это работает достаточно быстро. Теоретически можно и быстрее, но в этом просто нет необходимости.
ОтветитьУдалитьчто бы как то представить скажу вопросов будет минимум 500 с картинками а количество ответов от 3 до 5 включительно
ОтветитьУдалитьНичего страшного.
ОтветитьУдалить