Случайны выбор дневника Раскрыть/свернуть полный список возможностей
\n";
}


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

После того как пользователь дошел до последнего слова или завершил тест, открывается активтити, где выведен результат, как отмечалось выше это класс ResultTest, я не думаю, что он требует дополнительных комментариев, но следует заметить, что для построения Html-таблицы была использована функция loadDataWithBaseURL(null, TestWords.table_result, «text/html», «UTF-8», null), а также применен WebView.



Вот и подобрался я к самому интересному, а именно к загрузке слов с сервера. Класс отвечающий за это называется Load, на его реализацию ушло примерно 18 часов, т.к. там используется класс RecyclerView, а это для меня было что-то новое и в начале он вел меня в ступор, но в итоге, я все же с ним разобрался. Так что будет правильным, если свое повествование, о создании класса Load, я начну именно с него.



Первым делом хочется сказать, что этот класс получился достаточно большим, как ни старался его уменьшить, но все же рабочим. Для его использования был создан xml-файл с CheckBox'ом и TextView'ом, изначально скрытым. Здесь TextView служит для создания алфавита указателя, как можно увидеть на картинке выше. О том как он создается, я уже говорил, но здесь есть один момент, без которого, создание алфавита не получится и его опишу чуть позже.



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



Сначала я перегрузил три функции, onCreateViewHolder, onBindViewHolder, getItemCount, а также класс ViewHolder. GetItemCount не представляет особого интереса, т.к. она возвращает только размерность. Начну свое описание с класса ViewHolder.



public static class ViewHolder extends RecyclerView.ViewHolder {
public CheckBox chkbox;
public TextView tv_alph;
public ViewHolder(View v) {
super(v);
chkbox = (CheckBox) v.findViewById(R.id.rv_chkbox);
tv_alph = (TextView) v.findViewById(R.id.tv_alph);
}
}


Этот класс довольно прост и не требует никаких комментариев. Далее идет функция onCreateViewHolder, она служит для создания объектов ViewHolder.



public RecyclerLoad.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.content_checkbox, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}


Теперь рассмотрим функцию onBindViewHolder.



public void onBindViewHolder(final ViewHolder holder, final int position) {
if(index_alph[position]) {
holder.tv_alph.setText(Alph[position]);
holder.tv_alph.setVisibility(View.VISIBLE);
} else holder.tv_alph.setVisibility(View.GONE);
holder.chkbox.setText(Eng_Array[position] + " - [" +
Trans_Array[position] + "] - " +
Rus_Array[position]);
if(this_load.menu_load_1 != null)
this_load.menu_load_1.setTitle("Загрузить все слова (" + Integer.toString(amount) + ")");
holder.chkbox.setOnCheckedChangeListener(null);
holder.chkbox.setChecked(checked_box[position]);
holder.chkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked)
checked_words_load++;
else
checked_words_load--;
checked_box[position] = isChecked;
if(this_load.menu_load_2 != null)
this_load.menu_load_2.setTitle("Заг. выделенные слова (" + Integer.toString(checked_words_load) + ")");
}
});
if (position >= amount - 1) {
Log.d("MyLog", "Подкачка!!!");
LoadWords(sub_str);
onBind = true;
}
}


Что интересного здесь можно отметить, первое — объект holder заполняется данными, второе — чтобы не было дублирования нажатия CheckBox'ов вызываются функции setOnCheckedChangeListener и setChecked, далее во всех CheckBox'ах перегружается функция onCheckedChanged, для того чтобы в пункте меню менялось значение «количетсво» и последнее — это оператора if проверяющий условие предпоследнего слова, как только пользователь до него доходит вызывается функция подгрузки слов LoadWords.



Внимательный читатель наверное неоднократно заметил переменную sub_str, настало время рассказать о ней подробнее. Это переменная String, он хранит строку введенную пользователем в Edit'е «Найти: ». Т.к. в программе реализован живой поиск, то она передаются в функцию после каждого изменения текста в данном Edit'e, код представлен ниже.



find_words.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
FindWord(null);
}
});
public void FindWord(View view) {
mAdapter.Find(find_words.getText().toString());
mAdapter.notifyDataSetChanged();
}


Из кода видно, что после изменения текста вызывается функция FindWord, в которой вызывается метод Find, класса RecyclerLoad, где загружаются слова с сервера, которые содержат подстроку введенную пользователем, а затем вызывается функция обновления.



public void Find(String sub_str) {
this.sub_str = sub_str;
amount = 0;
Eng_Array = null;
Trans_Array = null;
Rus_Array = null;
checked_box = null;
index_alph = null;
Alph = null;
LoadWords(sub_str);
}


Перед вызовом LoadWords, все переменные класса RecyclerLoad обновляются, т.к. загружаются совершенно новые данные.



public void LoadWords(String sub_str) {
ClientLoadWords clw = new ClientLoadWords();
clw.LoadWords("2(!!)" + (sub_str.length() != 0 ? sub_str : "(--)"), amount);
try {
clw.join();
} catch (InterruptedException e) {
Log.d("MyLog", "ShowViewWords: " + e);
}
if(clw.int_error == -1) {
Toast toast = Toast.makeText(this_load.getApplicationContext(),
"Нет соединения с сервером!", Toast.LENGTH_SHORT);
toast.show();
}
amount += clw.amount;
Log.d("MyLog", "amount = " + amount);
String [] temp_Eng_Array = new String[amount];
String [] temp_Trans_Array = new String[amount];
String [] temp_Rus_Array = new String[amount];
String [] temp_Alph = new String[amount];
boolean [] temp_checked_box = new boolean[amount];
boolean [] temp_index_alph = new boolean[amount];
int temp_amount = Eng_Array != null ? Eng_Array.length : 0;
if(Eng_Array != null)
for(int i = 0; i < Eng_Array.length; i++) {
temp_Eng_Array[i] = Eng_Array[i];
temp_Trans_Array[i] = Trans_Array[i];
temp_Rus_Array[i] = Rus_Array[i];
temp_Alph[i] = Alph[i];
temp_checked_box[i] = checked_box[i];
temp_index_alph[i] = index_alph[i];
}
for(int i = 0; i < clw.amount; i++) {
temp_Eng_Array[i + temp_amount] = clw.Eng_Array[i];
temp_Trans_Array[i + temp_amount] = clw.Trans_Array[i];
temp_Rus_Array[i + temp_amount] = clw.Rus_Array[i];
temp_checked_box[i + temp_amount] = false;
temp_index_alph[i + temp_amount] = false;
temp_Alph[i + temp_amount] = "";
if(!first_chr.equals(String.valueOf(clw.Eng_Array[i].toUpperCase().charAt(0)))) {
Log.d("MyLog", "First Chr: " + first_chr + ", me.getKey(): " + clw.Eng_Array[i].toUpperCase().charAt(0) +
" boolean: " + first_chr.equals(String.valueOf(clw.Eng_Array[i].toUpperCase().charAt(0))));
first_chr = String.valueOf(clw.Eng_Array[i].toUpperCase().charAt(0));
temp_Alph[i + temp_amount] = first_chr + ":";
temp_index_alph[i + temp_amount] = true;
}
}
for(int i = 0; i < temp_Eng_Array.length; i++) {
Log.d("MyLog", "temp_Alph: " + temp_Alph[i] + ", temp_index_alph = " + temp_index_alph[i] + ", i = " + i);
}
Eng_Array = temp_Eng_Array;
Trans_Array = temp_Trans_Array;
Rus_Array = temp_Rus_Array;
checked_box = temp_checked_box;
index_alph = temp_index_alph;
Alph = temp_Alph;
}


Функция LoadWords получилась большой, так что я отмечу самые важные моменты. Во-первых класс ClientLoadWords — это подобие класса ClientAddWords, только он принимает данные с сервера, а не отправляет. Ему так же передается строка с кодом операции и строкой поиска. Второй параметр функции LoadWords, количество слов уже полученных слов, эта переменная нужна, чтобы сервер знал сколько он слов отправил и сколько осталось отправить еще. Код функции LoadWords приведен ниже.



public void run() {
InetAddress addr = null;
try {
addr = InetAddress.getByName("192.168.1.137");
} catch (UnknownHostException e) {
Log.d("MyLog", "ClientLoadWords LoadWords 1: " + e);
}
Client c;
try {
c = new Client(addr);
} catch (IOException e) {
Log.d("MyLog", "Socket failed: " + e);
int_error = -1;
return;
}
c.Out(str_user);
c.Out(Integer.toString(begin));
amount = 0;
try {
amount = Integer.parseInt(c.In());
} catch (IOException e) {
Log.d("MyLog", "LoadWords ClientLoadWords 3: " + e);
}
Log.d("MyLog", "Amount: " + amount);
Id_Array = new int[amount];
Eng_Array = new String[amount];
Trans_Array = new String[amount];
Rus_Array = new String[amount];
try {
for (int i = 0; i < amount; i++) {
Id_Array[i] = Integer.parseInt(c.In());
Eng_Array[i] = c.In();
Trans_Array[i] = c.In();
Rus_Array[i] = c.In();
}
} catch (IOException e) {
Log.d("MyLog", "LoadWords ClientLoadWords 4: " + e);
}
Sort();
}


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



Теперь вернемся в функцию LoadWords. Конструкция clw.join() ожидает завершения потока в классе ClientLoadWords, и только затем продолжает выполнение остальных операторов. Так же если объект clw возвращает код ошибка равный -1, то выводится подсказка и функция завершает свое выполнение. Далее, либо инициализируются массивы и туда заносятся полученные данные, либо уже к этим массивам данные дополняются, а также алфавитный указатель сразу жестко закрепляется и булевы значени отображения TextView'а заносятся в массив index_alph, иначе бы TextView дублировался.



Я думаю, на этом рассмотрение клиентского приложения можно закончить, т.к. самые интересные моменты, такие как отправка данных, живой поиск, создание теста, подгрузка слов и т. д., были рассмотрены, а пункт «Просмотреть слова», можно и пропустить, потому что его создания практически ничем не отличается от вывода результат после окончания теста, по сути это та же Html-таблица, только не цветная, так что приступим к серверному приложению.



Серверное приложение



Серверное приложение, является многопоточным, использует базу данных MySQL и передает данные по средством протокола TCP, это все что нужно знать, чтобы приступить к рассмотрению программа. За принятие/отправку данных отвечает класс ServerOneJabber. Он наследует класс Thread. Полностью приводить код данного класса я не буду, т.к. это не имеет смысла.



public ServerOneJabber(Socket s) throws IOException, SQLException {
socket = s;

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

sqldb = new SqlDB();

start();
}


Конструктор не представляет ничего сложного, стоит только обратить внимание на объект sqldb, все что о нем следует знать, это то, что он отвечает за связь с БД. Объекты in и out далее оборачиваются в функции In и Out, это сделано для удобства.



public void run() {
String message_user = new String("");

try {
message_user = Out();
} catch(IOException e) {
System.out.println(e);
}

System.out.println("message_user: " + message_user);

try {
switch(message_user.charAt(0)) {
case '1':
AddWord(message_user);
break;
case '2':
TransferWord(message_user);
break;
}
} catch(SQLException e) {
System.out.println(e);
} catch(IOException e) {
System.out.println(e);
}
}


Предназначение функции run заключается только в определении кода операции и вызова соответствующей функции. Рассмотрим каждую по очереди.



public void AddWord(String str) throws SQLException  {
String[] str_user = Split(str, "(!!)");

for(int i = 0; i < str_user.length; i++)
System.out.println("str_user: " + str_user[i]);

sqldb.AddWord(str_user[1], str_user[2], str_user[3]);
}


В функции AddWord все понятно. В sqldb передаются данные карточки и заносятся в БД с помощью метода AddWord. Метод Split получает на вход строку отправленную клиентом и строку разделитель, она была написана, потому что стандартная функция split класса String работала не правильно, я так и не разобрался почему.



public void TransferWord(String str) throws SQLException, IOException {
String [] user_str = Split(str, "(!!)");

for(int i = 0; i < user_str.length; i++) {
System.out.println("user_str: " + user_str[i]);
}

if(sqldb.CountSQL() == 0) {
In("0");
return;
}

int begin = new Integer(Out());

System.out.println("Loading Words...");

String [] data;

if(user_str[1].equals("(--)"))
data = sqldb.AllWords();
else
data = sqldb.Find(user_str[1]);

read_amount_words = (data.length - begin > 100 ? 100 : data.length - begin);

In(Integer.toString(read_amount_words));

for(int i = begin; i < begin + ((data.length - begin) > 100 ? 100 : data.length); i++) {
System.out.println("i = " + i + ", data.length = " + data.length);

if(i == data.length)
break;

String [] str_data = Split(data[i], "(!!)");

for(int j = 0; j < str_data.length; j++)
System.out.println("str_data: " + str_data[j]);

In(str_data[0]);
In(str_data[1]);
In(str_data[2]);
In(str_data[3]);
}
}


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



public class Server {
static final int PORT = 8080;

static public void main(String[] args) throws IOException {
ServerSocket s = new ServerSocket(PORT);
System.out.println("Server Started");

try {
while(true) {
Socket socket = s.accept();
try {
System.out.println("Client Connection");
new ServerOneJabber(socket);
} catch(IOException e) {
socket.close();
}
}
} catch(SQLException e) {
System.out.println(e);
} finally {
s.close();
}
}
}


В классе Server содержится метод main, и если к серверному приложению подключается клиент, то создается класс ServerOneJabber в новом потоке.



Заключение



Вот и подошла к завершению данная статья. Теперь, после написания данной программы, я могу учить английские слова, когда сижу на парах, где-нибудь в очереди или же дома. Надеюсь это статья окажется для кого-нибудь полезной, старался описать все как можно подробнее, но это у меня всегда плохо получалось. Спасибо за внимание и потраченное время.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303064/



Найдено 14975 сообщений
Cообщения с меткой

приложение - Самое интересное в блогах

Следующие 30  »
kiev2376393

Twitter обновил мобильное приложение Fabric, расширив функционал аналитики

Пятница, 25 Июня 2016 г. 03:52 (ссылка)

Twitter заметно обновил приложение платформы Fabric для разработчиков мобильных продуктов. Главным преимуществом версии стала улучшенная аналитика внутри приложения.

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
NetFact

Грипп, ОРЗ: эффективная профилактика и лечение народными безлекарственными методами / C. Мирошниченко (2011) PDF » NetFact.Ru: Скачать бесплатно – Популярная Интернет Библиотека

Вторник, 21 Июня 2016 г. 14:54 (ссылка)
netfact.ru/health/2601-grip...1-pdf.html


Грипп, ОРЗ: эффективная профилактика и лечение народными безлекарственными методами / C. Мирошниченко (2011) PDF




Автор сконцентрировал всю доступную на сегодняшний девай достоверную информацию о гриппе и ОРЗ, о способах всенародного безлекарственного лечения этих заболеваний и эффективных мерах профилактики. Приложение включает рекомендации, воспользовавшись какими, вы сможете повысить собственный иммунность.



ОГЛАВЛЕНИЕ



• Вступление

• Грипп и ОРЗ: течение, лечение, профилактика

• Осложнения гриппа и ОРЗ

• Изумрудная аптека

• Лечение медом, мумие и иными природными оружиями

• Приложение



Название: Грипп, ОРЗ: эффективная профилактика и лечение всенародными безлекарственными методами

Автор: C.А. Мирошниченко

Издание: БАО

Год: 2011

Формат: pdf

Страниц: 224

Качество: хорошее

Размер: 30,28 Мб



Скачать: Грипп, ОРЗ: эффективная профилактика и лечение народными безлекарственными методами / C. Мирошниченко (2011) PDF



Скачать | Download | TurboBit.net

http://turbobit.net/5820ohabvxt0/ORZ-Gryppe.rar.html



Скачать | Download | HitFile.net

http://www.hitfile.net/iXqQIuY/ORZ-Gryppe.rar.html



Скачать | Download | Файлообменник.рф

http://файлообменник.рф/rdznbvqr19br/ORZ-Gryppe.rar.html



Скачать | Download | BornCash.org

http://borncash.org/load/1734000830



Скачать | Download | StartFiles.org

http://startfiles.org/load/1734000830



Скачать | Download | GoldFiles.org

http://goldfiles.org/load/1734000830



Скачать | Download | File-Space.org

http://file-space.org/files/get/2UxpGuKVDI/orz-gryppe.rar.html

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] Когда программные продукты общаются с нами, должны ли они быть дружелюбными

Суббота, 18 Июня 2016 г. 18:46 (ссылка)

image



В фильме Спайка Джонса 2013 года «Она» усатый Хоакин Феникс, переживший неудачную любовь, со всей страстью влюбляется в своего личного робота-помощника по имени Саманта.



Сюжетная линия могла бы показаться немного смешной и нелепой большинству из нас, но рост количества чат-ботов показывает, насколько сильно люди желают разговаривать с машиной как с человеком.



Предназначение Саманты, как и любой технологии (особенно ботов), состоит в том, чтобы сделать жизнь пользователя легче. Мы желаем не нажимать кнопки и клавиши на сайте, а просто проговаривать вопросы и сразу же получать ответы. И поскольку научная фантастика — всё же фантастика, она, действительно, позволяет хотя бы очень приблизительно представить, как мир должен работать.



Быстрее — всегда лучше, и разговор, по мере совершенствования структуры общения, обработки естественного языка и ботов с искусственным интеллектом, всё больше вытесняет нажатие клавиш, становясь нашим предпочтительным методом нахождения информации.



На последней конференции по программным продуктам и технологиям компании Microsoft (Build developers conference) гендиректор Сатья Наделла провозгласил: «Боты являются новыми приложениями»; такую же позицию демонстрируют и действия других технических гигантов, таких как, например, Фейсбук, который вошёл в эту сферу, выпустив свои боты для Messenger Platform. Не будем забывать и про Telegram.



Даже Slack вводит боты в вашу рабочую среду, чтобы помогать во всём — от планирования встреч до нахождения новой красивой фотографии.



Чтобы убедиться в стремительном развитии разработки ботов, достаточно посмотреть через океан, где боты добились громадного успеха — в Азии, благодаря таким платформам как WeChat и Kik, на которые приходит более 650 миллионов пользователей в месяц.



Но, действительно, всё это и есть будущее? Отставим наши приложения и сайты и будем только разговаривать?



И если мы всё же сделаем так, то как оно всё должно работать?



Нам всем нужен кто-то, с кем можно поговорить



Чат-боты не являются чем-то новым.



Ещё в 1966 году программист Массачусетского технологического института Йозеф Вайценбаум опубликовал программу Eliza, которая анализировала слова, вводимые в компьютер, а затем подыскивала к ним ответ из подготовленного списка, имитируя человеческое общение.



Eliza была предназначена для моделирования работы психотерапевта — явно не для имитации человека вообще. Но Вайценбаум был обеспокоен увиденной реакцией пользователей программы Eliza.



image

Моё общение с Eliza…



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



В намерения Вайценбаума при разработке своего «чат-бота» ни в коем случае не входило создание «друга» или какой-то «личности», с которой можно было бы поддерживать контакт, он просто хотел сделать полезную утилиту. Ну, как какое-то приложение. Фактически в своей книге «Computer Power and Human Reason» («Мощь компьютера и мышление человека») он напрямую отверг идею, что компьютеры могли бы заменить человеческий интеллект.



По мысли Вайценбаума, тогда в конце 60-х, цель того «чат-бота» и всей той технологии, в действительности, состояла лишь в том, чтобы просто создать ещё один инструмент, расширяющий интеллектуальные возможности пользователя.



И, несмотря на подаваемое научной фантастикой утопическое видение будущего, заполненного мыслящими помощниками со свободной волей, большинство ботов в настоящее время является просто инструментами. Джаред Ньюман пишет в журнале Fast Company:



«Наилучшим подходом к ботам является думать о них, как о новом виде модели взаимодействия. Так же как мобильные приложения сокращают длинные меню ПО настольных компьютеров, так и чат-боты направляют пользователей в узкий набор взаимодействий, одинаковых для разных ботов.»



«Осуществляется ли такое действие путём ввода текста, отдачи команд голосом или остроумными шутками — вторично.»




Как всякий хороший продукт разработки опыта взаимодействия, бот предназначен для того, чтобы сделать взаимодействие легче, чем оно есть сейчас. Он предназначен устранять «трение» — т.е. такие взаимодействия, которые мешают людям интуитивно и легко выходить на их цели, и устранять любые барьеры, возникающие при использовании вашего продукта.



И для этого есть серьёзные основания.



Вспомним, что, когда компания Amazon ввела оплату в один клик, её годовой доход увеличился прим. на 2,4 млрд. долларов.



Или как приложение Bilingual Child утроило свой доход, когда предложило опцию «Купить всё» вместо покупки пользователем каждой «книги» отдельно.



Боты ориентированы на обеспечение результатов именно такого типа для каждого взаимодействия.



Бизнес знает, что люди, в основном, не имеют желания загружать какие-то инструкции и изучать их, чтобы использовать некоторое новое приложение для чтения новостей или заказа еды. В то время как у каждого отдельного приложения есть свой собственный процесс адаптации и своя кривая обучения, с чат-ботом не требуется обучение его использованию. Если вы в состоянии вводить с клавиатуры или говорить, то вы в состоянии сразу же начать взаимодействовать с ботом.



Требуется ли индивидуальность для программы-утилиты?



Всё сказанное выше порождает интересный вопрос: если полезность и лёгкость использования являются целью, то требовать ли от ботов «дружественности»?



Дэн Гровер, разработчик WeChat, в своём недавнем посте на тему «почему боты не заменят приложения», исследует, как Microsoft представляет себе работу ботов, рассматривая одну из самых основных (и, вне всяких сомнений, самых важных!) задач человечества: заказ пиццы.



image



В версии Microsoft наш пользователь общается с Пицца-ботом, как если бы тот был его другом. Этот бот знает привычки своего «друга». Знает, где тот живёт. И, предположительно, снимет деньги с него напрямую без необходимости ввода какой-либо информации об оплате.



Утилита — вычёркиваем.



Индивидуальность — может быть, немного подсушено, но немного.



Дэн затем сравнивает вышеуказанный процесс с его опытом заказа пиццы на боте Пицца-Хат сервиса WeChat:



image

ИТОГО: 16 нажатий (6 из которых — ввод моего PIN-кода для платежа)



Бот Пицца-Хат меньше похож на дружелюбного помощника; он, скорее, квалифицированный приёмщик заказа, только предоставляющий вам возможности реализовать ваше желание — заказать пиццу.



По мнению Дэна, трудность взаимодействия можно охарактеризовать количеством нажатий на кнопки — сколько раз требуется нажать кнопки на экране, чтобы получить желаемый результат?



Если считать так, то сдержанный бесстрастный бот Пицца-Хат убедительно выигрывает у дружелюбного Пицца-бота от Microsoft. Чем меньше нажатий, тем меньше затруднений. Но обязательно ли это значит улучшенное взаимодействие?



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



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



Вспомните, что некоторые из ваших приложений, такие как календарь или список контактов, имеют тот же внешний вид, что и их физические аналоги:



image



Разработчики продуктов полагали, что пользователь будет ментально не в состоянии перейти к хранению контактов на своём телефоне или в компьютере, если это не будет похоже на то, с чем он уже знаком.



Для ботов, утверждает Дэн, индивидуальность является тем же самым — в «диалоговом дизайне» не требуются элементы классического общения, такие как утончённость обращения, приветствия, подшучивание и т.д. Если такие элементы создают затруднения, то почему вы будете использовать бот, а не приложение? Когда новизна проходит, остаётся только имеющая значение полезность.



Посмотрите на Siri. Конечно, этот виртуальный помощник знает, как отпустить несколько шуток, но конечной целью всегда является полезность.



Задать вопрос, получить ответ. Всё!



Что же, в будущем нет места дружественности?



С другой стороны, разве перспектива взаимодействия с пользователем, обеспечиваемая персональным помощником, наподобие Samantha, не то, чего мы все желаем? И поскольку боты не разрабатываются всё же, как устройства с искусственным интеллектом «на все руки», перспектива более естественного взаимодействия представляется привлекательной.



Поскольку большинство ботов функционирует в среде, в которой мы взаимодействуем с другими людьми — например, Messenger, Slack и другие чат-сервисы, мы не можем не проецировать человеческие ценности на них. Поэтому, почему бы не придать им индивидуальность?



Но, как отмечает Эммет Коннолли, директор по разработке продукта в Intercom, наличие индивидуальности не подразумевает права претендовать на то, чтобы быть человеком:



«Не сбивайте с ног собственных пользователей (или, иначе, — не дурачьте их). Это означает — не используйте индикаторы „идёт набор на клавиатуре“ или искусственные задержки, чтобы заставить бот казаться больше похожим на человека. Наоборот, сообщения бота должны иметь особый стиль и быть чётко маркированы, показывая, что их генерирует не человек. Но это не исключает предоставление боту какой-то индивидуальности.»



У индивидуальности есть свои цели за пределами простого «действовать как человек».



Себастиан Крумхаузен, разработчик Sure (бота Facebook Messenger, ориентированного на помощь при поиске предложений для поддержки устойчивого бизнеса), предполагает, что индивидуальность помогает, в целом, улучшать взаимодействие с пользователем.



«Индивидуальность бота не улучшает взаимодействие с позиции эффективности или лёгкости использования, но она делает такое взаимодействие более приятным. Если у бота есть индивидуальность, то пользователи оказываются более терпимыми к ситуации при каком-то сбое.»



image



Вместо того чтобы действовать полностью по сценариям (скриптам), бот Sure использует то, что называют «ИИ (искусственный интеллект) с участием человека»: члены команды могут плавно входить в общение, если возникает вопрос, не вписывающийся в рамки текущей функциональности бота.



Поэтому, проектируя индивидуальность для бота, разработчики, предположительно, закладывают свои собственные черты характера — дружелюбие, остроумие, добродушие, спокойствие. Все эти качества смягчают ситуацию, если вы не получаете сразу же требуемый ответ.



«Первоначально люди обращались к нам довольно грубо, особенно когда работа не ладилась,» — разъясняет Крумхаузен. «Однако когда мы добавили к реакциям немного причудливости, люди стали более открытыми и более дружелюбными.»



Специалисты по маркетингу называют такое явление «антропоморфизмом бренда», и компании давно используют этот метод.



Как разъясняет Тайлер Кауэн в The New Yorker, за десятилетия до того, как боты типа Sure показали нам свои причудливые индивидуальности, предназначенные для обеспечения взаимодействия, Scrubbing Bubbles от компании Dow Chemical втолковывали потребителям, как «мы делаем всю работу, поэтому вам не придётся делать её», мультяшная музыкальная группа California Raisins пела: «До меня дошли слухи …», а рисованный пекарь компании Pillsbury, хихикая, рассказывал о печенье, рулетах и булочках.



«Корпорации создают такие образы по простой причине: они знают, что потребители лучше реагируют на продукты, которые, как представляется потребителям, взаимодействуют с ними на персональном уровне.»



С ботами, однако, общение является двусторонним. Это означает, что бот не просто создаёт персональную связь с брендом, но отвечает за обслуживание и, как объясняет Крумхаузен, за совершение взаимодействия.



«Точно так же, как в ситуации, когда вы создаёте какой-то продукт, очень важно то, что он должен быть предельно сфокусирован с самого начала. Поэтому общение, действительно, находится в центре внимания. Мы обнаружили важность того, чтобы бот в известной степени подталкивал или вёл общение в желаемом нами направлении.»



Почти совершенным примером этого является новое приложение Quartz.



Точно так же как Sure, это приложение использует комбинирование сценариев (скриптов) и письменных вмешательств человека. Сами сюжеты и контент полностью написаны журналистами Quartz в стиле и тоне их бота и голоса их бренда.



image



Здесь имеется присущий Quartz налёт причудливости с множеством смайликов, с шутками и элементами лёгкого «трёпа», но маршрут движения «выбери сам» решительно является аспектом взаимодействия, предлагая только две возможности для каждого сюжета: читать дополнительно или двигаться дальше.



Как отмечает Джаред Ньюман в своей статье в журнале Fast Company, здесь имеет место не то взаимодействие, которое обеспечивает компьютер; здесь действуют пока ещё сценарии. Наши ответы также.



Риск наделения бота индивидуальностью



Приложение Quartz, будучи одним из лучших примеров комбинирования в боте полезности и индивидуальности, также показывает некоторые необычные проблемы.



Здесь точно так же, как иногда в ситуации, когда приходится вступать в общение с кем-то на вечеринке, нет никакой гарантии, что вам понравится персона, с которой вы вступили в разговор. И даже при том, что большинство разработчиков ботов пытается создать необычного и забавного собеседника, с которым легко ладить — он может быстро наскучить.



В приложении Quartz его реакция порой кажется натянутой, похожей на перегонку важного новостного сюжета в версию, которую ваш прохлаждающийся с банкой пива приятель рассказал бы вам и которая, на самом деле, не очень соответствует самому событию.



Возможно, в этом больше из эпизода, в котором Эммет Коннолли призывал не «дурачить» ваших пользователей.



Индивидуальность — это, конечно, прекрасно, но мы всё время знаем, что говорим не с другим человеком. Они не знают нас. Они не могут считать социальные признаки. Бесхитростное использование смайликов является просто иной формой индикаторов «набор на клавиатуре идёт» при «очеловечивания» общения.



Также, как давний подписчик на ежедневную новостную рассылку Quartz, я нашёл это приложение более привлекательным, чем прокручивание просто ещё одного списка статей. Но, поскольку оно — автономное приложение, а не бот в Messenger, я задавался вопросом, стал бы я входить в это приложение, чтобы гарантировать его сохранение (сами сохранение и открытие автономного приложения могут быть просто слишком затруднительными для меня).



И именно здесь скрывается «подводный камень», как разъясняет Крумхаузен применительно к Sure:



«Важно, чтобы было эффективно и чтобы люди получали ожидаемый быстрый ответ сразу же. Как и любое другое онлайн-взаимодействие с пользователем он должен быть быстрым и эффективным. И если результат не лучше или не быстрее, чем при существующем взаимодействии — в нашем случае что-нибудь вроде Google Maps или Yelp, то люди не будут использовать рассматриваемый продукт.»



Далее, такой быстрый ответ означает нахождение человека уже в нужном окружении. Сама процедура загрузки приложения и действия по его открытию (а не простое прочитывание сообщений электронной почты в среде, в которой я часто нахожусь) представляют собой больше затруднений, чем того заслуживает результат.



Оставляя в стороне аргументы по индивидуальности — закрепятся ли боты вместо приложений?



Всё вышесказанное сводится к главному вопросу применительно к ботам: заменят ли они известные нам на сегодня приложения?



Для большинства ответ — нет!



Боты — то ли дружелюбный разговорчивый «друг», то ли чистая утилита — являются просто частью технической экосистемы. Они дают возможность уменьшить затруднения в ключевых местах вашего продукта, будь то поддержка, предложения или продажи.



И, в конце концов, то, что они делают, может быть более важным, чем то, что они говорят.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303566/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
kiev2376393

Facebook удалит ваши фотографии, если вы не скачаете приложение Moments

Среда, 16 Июня 2016 г. 03:32 (ссылка)

Facebook продолжает делить своё приложение на части. Сначала от него «откололся» Messenger, который отличается назойливостью, уязвимостями и с аппетитом ест батарею, а теперь — Moments. Если у вас была настроена автоматическая синхронизация фото со смартфона

Читать далее...
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
kiev2376393

Сила в науке: Google выпустил приложение для исследований

Суббота, 11 Июня 2016 г. 08:14 (ссылка)

Компания Google выпустила приложение “Научный журнал“, которое позволяет проводить научные исследования, сообщает TechToday.В новинке от Google можно измерить уровень громкости, количество света, ускорение движения и другие физические параметры.Фото - TechToday Программа

Читать далее...
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] Создание приложения под Android или проект без названия

Пятница, 10 Июня 2016 г. 12:33 (ссылка)

Предыстория



Одним прекрасным днем я решил начать изучать английский язык, и непосредственно перед изучением посоветовался с преподавателем, который этот язык преподает, т.к. думал, что он поделиться со мной приобретенным когда-то опытом. В итоге, мы сошлись с ним на том, что мне лучше всего начать свое изучение со слов языка, потому что в основном я использую свои знания, когда посещаю англоязычные сайты, а уж потом браться за грамматику. Он предложил очень интересный способ изучения(по крайней мере для меня). В свое время, чтобы слова отложились в памяти, он брал обычный лист бумаги, разлиновывал его на равные прямоугольники с одной стороны и разрезал лист, затем на одной из сторон получившегося прямоугольника писал английское слово, а на другой перевод, после этого он брал коробку, складывал туда получившиеся карточки, перемешивал и извлекал по одной, смотрел на слово и проговаривал перевод.

Если проделывать данную процедуру каждый день по час или два и периодически, пополнять свою картотеку, то слова запоминаются очень хорошо.



С тех пор я решил, что всегда буду так делать и в ближайшем будущем начну читать на английском языке, как на своем родном! Но через некоторое время меня начало утомлять резать карточки и тратить на это время, к тому же времени мне всегда категорически не хватает, в этот момент меня посетила мысль, а почему бы не создать программу под ОС android(т.к. у меня телефон именно с этой системой), которая будет выполнять аналогичную функцию!



Именно с этого момента зародился проект, которому я не придумал название.



Цель



Целью данного проекта, изначально, являлось автоматизация добавления слов в картотеку и дальнейшая их эксплуатация, но позже меня посетило еще пару идей и было очень интересно развивать проект, но спустя недели две это приелось и мне стало скучно, а полностью его забрасывать, как все предыдущие, я не хотел и поэтому решил попробовать себя в качестве автора данной статьи и поделиться полученным опытом в области сетевого программирования и программирования под android. В данной статье я постараюсь, на сколько это возможно, последовательно и шаг за шагом описать всю процедуру создания данной программы.



Программа



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



Описание



Первое, о чем хотелось бы поведать, так это о меню, я постарался сделать его как можно привлекательнее, у меня всегда был «отменный» вкус, поэтому вот что из этого вышло.



image



Как видно на изображении, особенного ничего в нем нет, но при нажатии на кнопку «Проверка слов» или «Слова», появляется, так сказать, субменю.



image



image



Как видно из изображений сверху таким же свойством обладают кнопки «В Алфавитном порядке», «В Обратном порядке» и «Рандом». Их все я пометил специальным символом «+», а при раскрытии символ заменяется на «-». При повторном нажатии на один из пунктов раскрытого меню, оно сворачивается в исходное положение.



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



Как я уже говорил, перед созданием проекта, меня посетило много идей и одна из них, это упрощение добавление слов в программу. Никому не секрет, что человек существо ленивое и не каждому придется по вкусу вручную создавать свою картотеку, тем более если нужно заполнить аж три поля(хотя транскрипцию заполнять не обязательно), в век развития интернета и передачи данных на большие расстояния за одно мгновенье.



image



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



Также в программе есть функции изменения и удаления слов. Здесь совсем все просто: после нажатия на нужный пункт меню перед нами открывается активити, где слова расположены в алфавитном порядке. Окна удаления и изменения слов практически ничем не отличаются, лишь только иконкой на кнопке со словом, поэтому для их создания применялся один xml-файл.



image



image



Если пользователь изменят слово, то для его изменения используется xml-файл добавления слов, только с другим функционалом, все три поля заполнены старыми значениями.



image



После ввода новых значений, при нажатии на соответствующую кнопку, слово изменяется и сохраняется на устройстве пользователя без внесения изменений в БД на сервере. Удаление слов/слова, сделано тоже очень просто, я даже не представляю себе, как можно усложнить данный процесс.



image



image



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



Теперь, когда я описал один из основных функционалов, а именно добавление/удаление/изменение слов, рассмотрим наиболее важный, прохождение теста по данным словам, а затем опишу альтернативный способ добавления слов.



Можно было заметить, на рисунке выше, что тест можно проходить в трех разных порядках: алфавитный, обратный и рандом. Тестируемым объектом может быть либо английский вариант слова, либо русский, либо транскрипция.



image



Как видно из рисунка, активно поле с английским вариантом слова, значит тестируется именно этот вариант. В зависимости от выбранного теста, всегда активно только одно поле ввода, остальные изменению не подлежат. Строка «Статус» указывает на то, верен ли введенный вариант пользователя, для того чтобы это узнать, необходимо нажать на кнопку «Проверка», так же показано сколько слов пройдено и их число, кнопку «Далее» подробно можно не рассматривать, но хотелось бы отметить, что можно было бы добавить кнопку возращения к предыдущему слову. Тест можно завершить дойдя до последнего слова или же пунктом меню.



image



После того как вы прошли или завершили тест, вашему вниманию предоставляется ваш результат.



image



Слова, которые были введены правильно отображаются зеленым цветом, остальные красным, далее вы можете либо перейти в главное меню или пройти тест заново.



Теперь рассмотрим альтернативный способ добавления слов, чтобы им воспользоваться, нужно перейти в пункт меню «Загрузить» и там можно будет просматривать слова, которые были добавлены на сервер, способом описанным выше.



image



На рисунке видно, что данное активити практически не отличается от активити изменения и удаления, за исключением того, что здесь находятся CheckBox'ы, вместо Button'ов.



Хотелось бы отметить, что слова с сервера поступают небольшими порциями, а именно по сто штук, после того как пользователь доходит до предпоследнего, подгружается еще сто и так далее, пока сервер не вернет последнее слово. Для того чтобы слово/слова можно было добавить к себе в картотеку, следует воспользоваться пунктами меню.



image



Как видно на изображении, можно загрузить выделенные слова, или те слова которые загруженные на данный момент. Какое количество слов будет сохранено, показано слева от пункта меню.



На изображениях выше, можно заметить, что у активити изменения/удаления/загрузки слов есть Edit — «Найти», т.к. он реализован одинаков везде, то рассмотрим только на примере окна Загрузки.



Не смотря на простоту реализации, поиск слов в этой программе является моей любимой разработкой(не считай подгрузки слов с сервера). Он является «живим», ищет, английские и русские слова, а также прост и удобен в применении.



image



image



image



image



Так же в программе имеется пункт меню «Просмотреть слова», где все слова выводятся в HTML-таблице.



image



Напоследок хотелось бы отметить, что весь функционал всех активити, продублирован в меню.



image



image



image



image



image



Реализация



Как было не трудно догадаться, программа состоит из двух частей, это серверное и клиентское приложение, так что данный пункт будет разделен на две части, и по отдельность опишу реализацию каждого. Я рассмотрю, только то, что считаю самым необходимым, иначе статья получиться очень громоздкой, тем более, что большая часть программы не представляет собой ничего трудного.



Клиентская часть



Клиентскую часть я начну описывать по порядку, так что первым делом мы рассмотрим создание меню, если быть точнее — реализацию сворачивание/разворачивание субменю. Данный фрагмент очень прост и практически не требует объяснений, так что я опишу только логику кода.











Как видно из фрагмента кода xml-файла, изначально все пункты субменю скрыты, далее, при нажатии на соответствующую кнопку, они становятся видимыми, а другие пункты, которые были активны, сворачиваются, внизу представлена одна из функций, остальные практически ничем не отличаются.



public void Alphabet(View view) {
click_alphabet = !click_alphabet;
if(Btn_Null())
Btn_Gone();
btn_english = (Button) findViewById(R.id.english1);
btn_transcription = (Button) findViewById(R.id.transcription1);
btn_russian = (Button) findViewById(R.id.russian1);
if(click_alphabet) {
btn_english.setVisibility(View.VISIBLE);
btn_transcription.setVisibility(View.VISIBLE);
btn_russian.setVisibility(View.VISIBLE);
btn_alphabet.setText("В АЛФАВИТНОМ ПОРЯДКЕ -");
} else {
Btn_Gone();
btn_alphabet.setText("В АЛФАВИТНОМ ПОРЯДКЕ +");
}
}


Переменная click_alphabet — проверяет, было ли повторное нажатие на кнопку, если «да», то субменю, за который отвечает данный пункт, сворачивается.



Функция Btn_Null() — проверяет инициализицию всех кнопок.

Функция Btn_Gone() — сворачивает абсолютно все пункты/подпункты меню.



Теперь рассмотрим добавление слова в БД на сервер и на смартфон. Все слова, которые пользователь себе добавил, хранятся в классе TreeMap, ключом для данного класса является английское слово, а транскрипция и перевод хранятся в классе TransRus.



public class TransRus {
private String transcription;
private String russian;
boolean error;
TransRus() {
transcription = new String("");
russian = new String("");
error = false;
}
void getTranscription(String tr) {
transcription = tr;
}
void getRussian(String rs) {
russian = rs;
}
String setTranscription() {
return transcription;
}
String setRussian() {
return russian;
}
void getError(boolean t) {
error = t;
}
boolean setError() {
return error;
}
}


Класс TreeMap обернут в оболочку класса CollectionWords, также для него был написан компаратор, который игнорирует регистр букв.



class ComparatorNotRegister implements Comparator {  public int compare(String str1, String str2) {
return str1.compareToIgnoreCase(str2);
}
}
public class CollectionWords {
static TreeMap coll_words = null;
static final String file1 = "english";
static final String file2 = "transcription";
static final String file3 = "russian";
static void InitializationCollWords() {
if(coll_words != null)
return;
coll_words = new TreeMap(new ComparatorNotRegister());
}
static void PutCollWords(String english, String transcription, String russian) {
TransRus tr = new TransRus();
tr.getTranscription(transcription);
tr.getRussian(russian);
coll_words.put(english, tr);
}
static void ChangedWordEng(String old_english, String new_english, String transcription, String russian) {
TransRus temp = coll_words.get(old_english);
coll_words.remove(old_english);
PutCollWords(new_english, transcription, russian);
}
static void DeleteWords(String eng) {
coll_words.remove(eng);
}
static void WriteWords(AppCompatActivity t) {
try(
BufferedWriter eng = new BufferedWriter(new OutputStreamWriter(t.openFileOutput(file1, t.MODE_PRIVATE)));
BufferedWriter trans = new BufferedWriter(new OutputStreamWriter(t.openFileOutput(file2, t.MODE_PRIVATE)));
BufferedWriter rus = new BufferedWriter(new OutputStreamWriter(t.openFileOutput(file3, t.MODE_PRIVATE)))) {
for(Map.Entry me : CollectionWords.AllWords()) {
eng.write(me.getKey() + "\n");
trans.write(me.getValue().setTranscription() + "\n");
rus.write(me.getValue().setRussian() + "\n");
}
} catch (FileNotFoundException e) {
Log.d("MyLog", "WF: " + e);
} catch (IOException e) {
Log.d("MyLog", "WIOE: " + e);
} catch(NullPointerException e) {
Log.d("MyLog", "WN: " + e);
} catch (Exception e) {
Log.d("MyLog", "WE: " + e);
}
}
static void ReadWords(AppCompatActivity t) {
try(
BufferedReader eng = new BufferedReader(new InputStreamReader(t.openFileInput(file1)));
BufferedReader trans = new BufferedReader(new InputStreamReader(t.openFileInput(file2)));
BufferedReader rus = new BufferedReader(new InputStreamReader(t.openFileInput(file3)))) {
String str_eng;
String str_trans;
String str_rus;
while(((str_eng = eng.readLine()) != null) &&
((str_trans = trans.readLine()) != null) &&
((str_rus = rus.readLine()) != null)) {
CollectionWords.PutCollWords(str_eng, str_trans, str_rus);
}
Log.d("MyLog", "Hyi tam");
} catch (FileNotFoundException e) {
Log.d("MyLog", "RF: " + e);
} catch (IOException e) {
Log.d("MyLog", "RIO: " + e);
} catch(NullPointerException e) {
Log.d("MyLog", "RN: " + e);
}
}
static Set> AllWords() {
return coll_words.entrySet();
}
}


Данный класс не представляет ничего сложного, как можно заметить, все слова хранятся в текстовых файлах english, transcription и russian, для этого следовало бы использовать БД, но я не стал сильно заморачиваться, т.к. все и так работает. Функции WriteWords, ReadWords служат для сохранения слов, здесь следует отметить, только то, что, чтобы функция работала, ей нужно будет передать указатель this, из класса, который ее вызвал. Сразу бросается в глаза, тот факт, что все функции статические, это было сделано специально, чтобы не дублировать класс много раз, все остальное понятно и комментарии будут лишними. Теперь, когда дополнительные оболочки рассмотрены, можно описать функцию добавления.



public void AddWord(View view) {
CollectionWords.InitializationCollWords();
if(english_language.getText().length() == 0 || russian_language.getText().length() == 0) {
Toast toast = Toast.makeText(getApplicationContext(),
"Заполните обязательные поля!", Toast.LENGTH_SHORT);
toast.show();
return;
}
if(status != 0 && status == MainActivity.INT_CHG) {
CollectionWords.ChangedWordEng(old_english, english_language.getText().toString(),
transcription_language.getText().toString().length() == 0 ? "-" : transcription_language.getText().toString(),
russian_language.getText().toString());
Back(null);
}
CollectionWords.PutCollWords(english_language.getText().toString(),
(transcription_language.getText().toString().length() == 0 ? "-" : transcription_language.getText().toString()),
russian_language.getText().toString());
ClientAddWords caw = new ClientAddWords();
caw.ServerAddWords("1(!!)" + english_language.getText().toString() + "(!!)" +
(transcription_language.getText().toString().length() == 0 ? "-" : transcription_language.getText().toString())
+ "(!!)" +
russian_language.getText().toString());
english_language.setText("");
transcription_language.setText("");
russian_language.setText("");
}


Из фрагмента кода видно, что обязательными полями здесь являются enlish_language и russian_language, если они не заполнены, то добавления слова не произойдет, функция завершится и всплывет сообщение с подсказкой. Как я говорил ранее, для добавления и изменения слов, используется один xml-файл, а соответственно и класс тоже, поэтому здесь присутствует второй оператор if, который проверяет переменную status, хранящее значение о том, был ли осуществлен вход в данную функцию, с целью изменения слова.

Особый интерес представляет собой класс ClientAddWords, который служит для отправки слова на сервер. Т.к. на данный момент Android Studio требует, чтобы всё, что связанно с сетью происходило в отдельном потоке, я решил создать класс, который за это отвечает. В программе присутствует еще один, возвращающий слов с сервера.



Как видно из кода, сначала создается объект ClientAddWords, потом объект вызывает функцию, ей передается строка, разделенная символом «(!!)», этот символ отделяет код операции, предназначенный для сервера, в данном случае это «1», а также английское слово, транскрипцию и перевод, это служит для того, чтобы сервер мог правильно отделить данные друг от друга, как вы уже догадались именно эта строка и передается серверу.



Создание класса, для работы с сетью, очень удобно, ведь подключение клиента к серверу идет именно в тот момент, когда вызывается функция ServerAddWords, а после передачи, клиент отключается от серверного приложения, так что дополнительной нагрузки на сервер нет. Ниже приведен класс ClientAddWords.



public class ClientAddWords extends Thread {
String str_user;
void ServerAddWords(String str) {
str_user = str;
start();
}
public void run() {
Log.d("MyLog", "Run Client");
InetAddress addr = null;
try {
addr = InetAddress.getByName("192.168.1.208");
} catch (UnknownHostException e) {
Log.d("MyLog", "ServerAddWords ClientAddWords: " + e);
}
Client c;
try {
c = new Client(addr);
} catch (IOException e) {
Log.d("MyLog", "Socket failed: " + e);
return;
}
c.Out(str_user);
c.Close();
}
}


Как видно, в данной реализации кода, нет ничего сложного и он не требует дополнительных разъяснений, код класса Client, представлен ниже.



public class Client extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
InetAddress addr;
public String In() throws IOException {
return in.readLine();
}
public void Out(String str) {
out.println(str);
}
public Client(InetAddress addr) throws IOException {
this.addr = addr;
Log.d("MyLog", "Making client");
try {
socket = new Socket(addr, 8080);
} catch (IOException e) {
Log.d("MyLog", "Socket failed: " + e);
throw e;
}
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
} catch (Exception e) {
Log.d("MyLog", "In/Out: " + e);
try {
socket.close();
}
catch (IOException e2) {
Log.d("MyLog", "Client: Socket not closed");
}
}
}
public void Close() {
try {
socket.close();
in.close();
out.close();
} catch (IOException e) {
Log.d("MyLog", "Close Client: " + e);
}
}
}


Здесь также нет интересных моментов, данный пример кода можно найти на любом сайте посвященный сетевому программированию.



Сейчас мы рассмотрим класс, отвечающий за изменение и удаление слов, как я уже не раз говорил они используют один xml-файл, и самое интересное в его реализации — это заполнение layout'a button'ами.









В самом xml-файле интерес представляет только этот кусок кода, здесь видно что layout'у задается id — ll_find, это нужно для того, чтобы создавать кнопки программно.



class MyButton extends Button {
private String str_eng;
private String str_trans;
private String str_rus;
private int index;
public MyButton(Context context) {
super(context);
}
void setEnglish(String eng) {
str_eng = eng;
}
void setTranscription(String trans) {
str_trans = trans;
}
void setRussian(String rus) {
str_rus = rus;
}
void setIndex(int id) { index = id; }
String getEnglish() { return str_eng; }
String getTranscription() {
return str_trans;
}
String getRussian() {
return str_rus;
}
int getIndex() { return index; }
}


Отмечу сразу данный класс, как не трудно догадаться он предназначен лишь для хранения значений карточки, а именно английское слов, его транскрипцию и перевод.



Первая функция, которую следует описать — это CreateButton, код представлен ниже.



public MyButton CreateButton(int i, String eng, String trans, String rus) {
final MyButton btnNew = new MyButton(this);
btnNew.setBackgroundResource(R.drawable.background_button);
btnNew.setText(eng + " - " + rus);
btnNew.setEnglish(eng);
btnNew.setTranscription(trans);
btnNew.setRussian(rus);
btnNew.setIndex(i);
if(status == MainActivity.INT_DEL) {
btnNew.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_delete_button, 0, 0, 0);
btnNew.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder ad;
Find context;
context = Find.this;
String title = "Удаление слова";
String message = "Вы уверены?";
String button1String = "Да";
String button2String = "Нет";
ad = new AlertDialog.Builder((Context) context);
ad.setTitle(title);
ad.setMessage(message);
ad.setPositiveButton(button1String, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int arg1) {
CollectionWords.DeleteWords(btnNew.getEnglish());
ll_layout.removeView(btnNew);
}
});
ad.setNegativeButton(button2String, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int arg1) {
}
});
ad.show();
}
});
}
else {
btnNew.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_changed_button, 0, 0, 0);
btnNew.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("MyLog", "Changed Words");
ChangedWord((MyButton) v);
ll_layout.removeView((MyButton) v);
}
});
}
return btnNew;
}


Здесь есть пару интересных моментов, а именно изменение заднего фона кнопки, далее, в зависимости от того, с какой целью посещается данный класс, это создание иконки у кнопки, за это отвечает функция setCompoundDrawablesWithIntrinsicBounds, а также реализация события setOnClickListener, тут либо создается диалоговое окно и происходит удаление слова и btnNew, либо вызывается функция ChangedWord, которая открывает активити, предназначенное для изменения слова.



Следующая функция, про которую следует рассказать, это ShowViewWords, ее предназначение занесение button'ов в layout.



public void ShowViewWords(LinearLayout.LayoutParams lParams, String sub_str) {
int i = 0;
String first_chr = new String("");
for(Map.Entry me : CollectionWords.AllWords()) {
if(sub_str.length() != 0 && (me.getKey().toLowerCase().indexOf(sub_str.toLowerCase()) == -1 &&
me.getValue().setRussian().toLowerCase().indexOf(sub_str.toLowerCase()) == -1))
continue;
if(!first_chr.equals(String.valueOf(me.getKey().toUpperCase().charAt(0)))) {
first_chr = String.valueOf(me.getKey().toUpperCase().charAt(0));
TextView temp = new TextView(this);
temp.setText(first_chr + ":");
temp.setTextSize(25f);
ll_layout.addView(temp, i, lParams);
i++;
}
ll_layout.addView(CreateButton(i, me.getKey(), me.getValue().setTranscription(), me.getValue().setRussian()),
i, lParams);
i++;
}
if(i == 0) {
LinearLayout.LayoutParams l = CreateParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_VERTICAL);
TextView not_found = new TextView(this);
not_found.setText("Ничего не найдено");
ll_layout.addView(not_found, l);
}
}


Здесь также происходит создание и добавление TextView'а, который хранит значение первой буквы слова, отличающегося от первой буквы следующего слова. Постарался объяснить как можно лучше, но на всякий случай в пример приведу изображение.



image



За это отвечает вот этот кусок кода.



if(!first_chr.equals(String.valueOf(me.getKey().toUpperCase().charAt(0)))) {
first_chr = String.valueOf(me.getKey().toUpperCase().charAt(0));
TextView temp = new TextView(this);
temp.setText(first_chr + ":");
temp.setTextSize(25f);
ll_layout.addView(temp, i, lParams);
i++;
}


Изначально переменной first_chr, присваивается пустая строка, так что если цикл проходит первый раз, то в нее обязательно занесется значение.



За условие цикла отвечает данная строка.



for(Map.Entry me : CollectionWords.AllWords()) 


О предназначении первого оператора if, я расскажу позже, т. к. это относится к поиску, а о поиске расскажу в последнюю очередь.



 ll_layout.addView(CreateButton(i, me.getKey(), me.getValue().setTranscription(), me.getValue().setRussian()),
i, lParams);


А за добавление в ll_layout, отвечает это конструкция, здесь вызывается функция CreateButton, рассмотренная выше и возвращающая значение MyButton, далее добавляется индекс и параметры этой кнопки.



Функция ShowViewWords, вызывается из функции CreatesButton, а функция CreatesButton вызывается уже из onCreate. Код CreatesButton приведен ниже.



public void CreatesButton(String str_find) {
ll_layout.removeAllViews();
LinearLayout.LayoutParams lParams = CreateParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT,
Gravity.LEFT);
lParams.topMargin = 1;
ShowViewWords(lParams, str_find);
}


Код функции CreateParams:



public LinearLayout.LayoutParams CreateParams(int width, int height, int gravity) {
LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams(width, height);
lParams.gravity = gravity;
return lParams;
}


На данном этапе описании программы, я подошел к реализации класса TestWords, который отвечает за тестирование слов. Как и обычно в нем нет ничего сложного, но есть пару моментов, которые следует рассмотреть. Самый первый, это выбор пользователем теста, как ни трудно догадаться всего может быть девять вариантов тестирования, а именно заданный порядок слов(в алфавитном, в обратном и рандом) и объект тестирования(английски, транскрипция, русский). Так что самой первой вызывается функция StatusTest. Она определяет по коду, какие из Edit'ов должны быть заблокированы, и инициализирует переменную индексом, под которым стоит слово.



public void StatusTest() {
switch (status) {
case MainActivity.INT_ALPH_ENG:
edit_transcription.setRawInputType(0x00000000);
edit_russian.setRawInputType(0x00000000);
next_words = 0;
break;
case MainActivity.INT_ALPH_TRANS:
edit_english.setRawInputType(0x00000000);
edit_russian.setRawInputType(0x00000000);
next_words = 0;
break;
case MainActivity.INT_ALPH_RUS:
edit_english.setRawInputType(0x00000000);
edit_transcription.setRawInputType(0x00000000);
next_words = 0;
break;
case MainActivity.INT_REVS_ENG:
edit_transcription.setRawInputType(0x00000000);
edit_russian.setRawInputType(0x00000000);
next_words = CollectionWords.coll_words.size() - 1;
break;
case MainActivity.INT_REVS_TRANS:
edit_english.setRawInputType(0x00000000);
edit_russian.setRawInputType(0x00000000);
next_words = CollectionWords.coll_words.size() - 1;
break;
case MainActivity.INT_REVS_RUS:
edit_english.setRawInputType(0x00000000);
edit_transcription.setRawInputType(0x00000000);
next_words = CollectionWords.coll_words.size() - 1;
break;
case MainActivity.INT_RAND_ENG:
rand_next_words = new Random();
next_words = MethodRandomWords();
edit_transcription.setRawInputType(0x00000000);
edit_russian.setRawInputType(0x00000000);
break;
case MainActivity.INT_RAND_TRANS:
rand_next_words = new Random();
next_words = MethodRandomWords();
edit_english.setRawInputType(0x00000000);
edit_russian.setRawInputType(0x00000000);
break;
case MainActivity.INT_RAND_RUS:
rand_next_words = new Random();
next_words = MethodRandomWords();
edit_english.setRawInputType(0x00000000);
edit_transcription.setRawInputType(0x00000000);
break;
}
}


В случае алфавитного порядка переменной next_words, присваивается 0, обратный порядок — это размер класса TreeMap минус 1 и рандомный порядок, специальная функция, которая возвращает случайное значение в next_words.



Функция MethodRandomWords служит для того, чтобы не вернуть одно и тоже случайное значение несколько раз.



После инициализации всех Edit'ов и вызова функции StatusTest, выполняется метод ReadWord.



public void ReadWord() {
last_words++;
amount_words.setText(last_words + "/" + CollectionWords.coll_words.size());
switch (status) {
case MainActivity.INT_ALPH_ENG:
nw = VecNextWord(next_words);
edit_english.setText("");
edit_transcription.setText(nw.getValue().setTranscription());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_ALPH_TRANS:
nw = VecNextWord(next_words);
edit_transcription.setText("");
edit_english.setText(nw.getKey());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_ALPH_RUS:
nw = VecNextWord(next_words);
edit_russian.setText("");
edit_english.setText(nw.getKey());
edit_transcription.setText(nw.getValue().setTranscription());
break;
case MainActivity.INT_REVS_ENG:
nw = VecNextWord(next_words);
edit_english.setText("");
edit_transcription.setText(nw.getValue().setTranscription());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_REVS_TRANS:
nw = VecNextWord(next_words);
edit_transcription.setText("");
edit_english.setText(nw.getKey());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_REVS_RUS:
nw = VecNextWord(next_words);
edit_russian.setText("");
edit_english.setText(nw.getKey());
edit_transcription.setText(nw.getValue().setTranscription());
break;
case MainActivity.INT_RAND_ENG:
nw = VecNextWord(next_words);
edit_english.setText("");
edit_transcription.setText(nw.getValue().setTranscription());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_RAND_TRANS:
nw = VecNextWord(next_words);
edit_transcription.setText("");
edit_english.setText(nw.getKey());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_RAND_RUS:
nw = VecNextWord(next_words);
edit_russian.setText("");
edit_english.setText(nw.getKey());
edit_transcription.setText(nw.getValue().setTranscription());
break;
}
status_true_word.setText("Статус:-");
}


Цель этого метода, загрузить первое слов, за это отвечает функция VecNextWord, параметр которой индекс и возвращаемым значением является Map.Entry, а также указать количество слов и обнулить статус.



Следующую роль играют всего две функции, Check — проверяет правильность введенного слова и при случае меняет Статус, NextWord — возвращает следующее по списку слово, в зависимости от выбранного порядка. Код функций приведен ниже.



public void Check(View view) {
check_bool = true;
Log.d("MyLog", "Status: " + status);
switch (status) {
case MainActivity.INT_ALPH_ENG:
Log.d("MyLog", "Check()");
if(edit_english.getText().toString().equals(nw.getKey())) {
Log.d("MyLog", "True");
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
Log.d("MyLog", "False");
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_ALPH_TRANS:
Log.d("MyLog", "Check()");
if(edit_transcription.getText().toString().equals(nw.getValue().setTranscription())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_ALPH_RUS:
Log.d("MyLog", "Check()");
if(edit_russian.getText().toString().equals(nw.getValue().setRussian())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_REVS_ENG:
Log.d("MyLog", "Check()");
if(edit_english.getText().toString().equals(nw.getKey())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_REVS_TRANS:
Log.d("MyLog", "Check()");
if(edit_transcription.getText().toString().equals(nw.getValue().setTranscription())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_REVS_RUS:
Log.d("MyLog", "Check()");
if(edit_russian.getText().toString().equals(nw.getValue().setRussian())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_RAND_ENG:
Log.d("MyLog", "Check()");
if(edit_english.getText().toString().equals(nw.getKey())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_RAND_TRANS:
Log.d("MyLog", "Check()");
if(edit_transcription.getText().toString().equals(nw.getValue().setTranscription())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
case MainActivity.INT_RAND_RUS:
Log.d("MyLog", "Check()");
if(edit_russian.getText().toString().equals(nw.getValue().setRussian())) {
status_true_word.setText("Статус: Верно");
Log.d("MyLog", "next_words: " + next_words);
nw.getValue().getError(true);
} else {
status_true_word.setText("Статус: Не верно");
}
break;
}
}

public void NextWord(View view) throws InterruptedException {
if(last_words >= CollectionWords.coll_words.size()) {
ResultTestGo();
return;
}
if(!check_bool && last_words != 0)
Check(view);
AddWordInTable(nw.getValue().setError());
last_words++;
amount_words.setText(last_words + "/" + CollectionWords.coll_words.size());
switch (status) {
case MainActivity.INT_ALPH_ENG:
next_words++;
nw = VecNextWord(next_words);
edit_english.setText("");
edit_transcription.setText(nw.getValue().setTranscription());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_ALPH_TRANS:
next_words++;
nw = VecNextWord(next_words);
edit_transcription.setText("");
edit_english.setText(nw.getKey());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_ALPH_RUS:
next_words++;
nw = VecNextWord(next_words);
edit_russian.setText("");
edit_english.setText(nw.getKey());
edit_transcription.setText(nw.getValue().setTranscription());
break;
case MainActivity.INT_REVS_ENG:
next_words--;
nw = VecNextWord(next_words);
edit_english.setText("");
edit_transcription.setText(nw.getValue().setTranscription());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_REVS_TRANS:
next_words--;
nw = VecNextWord(next_words);
edit_transcription.setText("");
edit_english.setText(nw.getKey());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_REVS_RUS:
next_words--;
nw = VecNextWord(next_words);
edit_russian.setText("");
edit_english.setText(nw.getKey());
edit_transcription.setText(nw.getValue().setTranscription());
break;
case MainActivity.INT_RAND_ENG:
next_words = MethodRandomWords();
nw = VecNextWord(next_words);
edit_english.setText("");
edit_transcription.setText(nw.getValue().setTranscription());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_RAND_TRANS:
next_words = MethodRandomWords();
nw = VecNextWord(next_words);
edit_transcription.setText("");
edit_english.setText(nw.getKey());
edit_russian.setText(nw.getValue().setRussian());
break;
case MainActivity.INT_RAND_RUS:
next_words = MethodRandomWords();
nw = VecNextWord(next_words);
edit_russian.setText("");
edit_english.setText(nw.getKey());
edit_transcription.setText(nw.getValue().setTranscription());
break;
}
status_true_word.setText("Статус:-");
check_bool = false;
}


Я не думаю, что у кого-то могут возникнуть трудности с кодом этих функция, но необходимо отметить пару моментов. Как было показано на изображении выше, после прохождения или завершения теста, формируется Html-таблица, для удобного отображения результата. Исход код таблицы, для быстродействия программы, формируется во время прохождения теста, при помощи функции AddWordInTable(nw.getValue().setError()), ей передается булево значение.



public void AddWordInTable(boolean temp) {
table_result += "
" + nw.getKey() +
"
" + nw.getValue().setTranscription() +
"
" + nw.getValue().setRussian() +
"
" + (temp ? "Верно" : "Не верно") + "
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
Chizz_TecTeP

Обновление быстропоста. Версия 2.7.3. Кнопка поделиться.

Среда, 08 Июня 2016 г. 20:38 (ссылка)


Сегодня в сообществе лиру идет обсуждение посещаемости Лирушки. Я подумал, что посещаемость в том числе растет, если есть ссылки с других социальных сетей на посты лирушечные. И решил добавить возможность поделиться ссылкой на пост прямо из быстропоста.



Сделать это можно из меню в окне просмотра поста.





Это на примере поста Роста.





Лучше всего в гугл плюс получается. Он и картинку из поста подхватывает сразу.



Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
KtoNaNovenkogo

Знакомимся с AppCoins и начинаем зарабатывать

Пятница, 04 Июня 2016 г. 00:37 (ссылка)

Это цитата сообщения Dmitriykn Оригинальное сообщение

Зарабатываем в интернете с телефона через мобильное приложение AppCoins



http://ktonanovenkogo.ru/zarabotok_na_saite/monetizaciy/zarabatyvaem-v-internete-s-telefona-mobilnoe-prilozhenie-appcoins.html




Зарабатываем в интернете с телефона через мобильное приложение AppCoins | KtoNaNovenkogo.ru - создание, продвижение и заработок на сайте




  1. Знакомимся с AppCoins и начинаем зарабатывать

  2. Интерфейс, особенности и партнерская программа

  3. Вывод заработанных денег из AppCoins

  4. Подытоживаем


AppCoins 

Какие варианты заработка предлагает мобильное приложение AppCoins  и как можно получать деньги со своего телефона
Комментарии (0)КомментироватьВ цитатник или сообщество
Dmitriykn

Зарабатываем в интернете с телефона через мобильное приложение AppCoins

Пятница, 04 Июня 2016 г. 00:34 (ссылка)
ktonanovenkogo.ru/zarabotok...coins.html


Зарабатываем в интернете с телефона через мобильное приложение AppCoins | KtoNaNovenkogo.ru - создание, продвижение и заработок на сайте




  1. Знакомимся с AppCoins и начинаем зарабатывать

  2. Интерфейс, особенности и партнерская программа

  3. Вывод заработанных денег из AppCoins

  4. Подытоживаем


AppCoins 

Какие варианты заработка предлагает мобильное приложение AppCoins  и как можно получать деньги со своего телефона
Комментарии (0)КомментироватьВ цитатник или сообщество
kiev2376393

В приложении Google для iOS появился AMP-контент

Среда, 01 Июня 2016 г. 11:13 (ссылка)

Google обновил поисковое приложение для iOS. В числе основных нововведений – включение страниц с ускоренной загрузкой (Accelarated Mobile Pages, AMP) в результаты поиска.




Страницы этого формата содержатся в разделе «Top Stories»

Читать далее...
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<приложение - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda