Пишем программу для Android, рассказывающую анекдоты
В этой статье я расскажу как написал приложение для Android, которое рассказывает вслух анекдоты, используя синтезированный голос от Google.
Примечание редактора
Дорогие подписчики, представляю вам очередной материал автора @pythono. В этой статье автор не только расскажет вам о своей работе, но и продемонстрирует приложение, загруженное в Google Play. Это реально круто!
Приложение удобно тем, что можно слушать анекдоты в наушниках, не глядя в экран, например во время ходьбы, или каких-то повседневных дел, вроде приготовления пищи, или поездки в общественном транспорте.
На момент написания статьи, программа выложена и одобрена в Google Play.
Скачать программу с Google Play
https://play.google.com/store/apps/details?id=ru.pythono.funspeak
Для работы программы также требуется установить синтезатор речи от Google и включить синтез речи в настройках вашего Android устройства.
Интерфейс программы очень прост и состоит из двух больших кнопок - "Расскажи анекдот" и "Остановить синтез речи".
Когда мы нажимаем на кнопку "Рассказать анекдот", программа дает запрос к PHP скрипту на моём сайте, в ответ скрипт высылает ей случайный анекдот, спарсенный из интернета. Программа принимает текст анекдота и читает его вслух с помощью синтезатора речи. Можно было реализовать парсинг анекдота прямо на устройстве Android, но это оказалось медленнее, чем парсинг PHP скриптом, поэтому я выбрал именно скриптовый вариант решения проблемы.
Листинг PHP скрипта fun.php:
<?
include 'phpQuery.php'; // Подключаем phpQuery
// Функция получения текста страницы для phpQuery
function getpage($url)
{
$curl = curl_init($url); // Инициализируем curl по указанному адресу
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // Записать http ответ в переменную, а не выводить в буфер
curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt ($curl, CURLOPT_SSL_VERIFYHOST, 0); // Этот параметр нужен для работы HTTPS
$page = curl_exec($curl); // Получаем в переменную $page HTML код страницы
$document = phpQuery::newDocument($page); // Загружаем полученную страницу в phpQuery
return $document;
};
$elements = getpage('http://anekdotme.ru/random')->find('.anekdot_text'); // Делаем выборку по классу
foreach ($elements as $el) {
$elem_pq = pq($el); // pq - аналог $ в jQuery
$otvet = trim($elem_pq->text()); // Получим текст анекдота
};
echo($otvet); // Выдаем ответ сервера
Для парсинга в PHP скрипте используется curl и библиотека phpQuery
Если мы обратимся к данному скрипту по адресу http://pythono.ru/alina/fun.php, он выдаст нам случайный анекдот.
Задача нашей программы - получить анекдот от скрипта при нажатии на кнопку, и произнести его вслух.
Интерфейс программы - это две кнопки ImageButton, которые расположены одна над другой. При включении программы на первой кнопке отображается картинка "Загрузка".
Когда программа инициализирует синтезатор речи и будет готова произносить фразы вслух, картинка на первой кнопке сменяется на "Расскажи анекдот".
Листинг интерфейса activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical"
tools:context="ru.pythono.funspeak.MainActivity">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center_vertical"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageButton
android:id="@+id/fun"
android:layout_width="300px"
android:layout_height="300px"
android:layout_marginTop="10dp"
android:scaleType="fitCenter"
android:src="@drawable/loading" />
<ImageButton
android:id="@+id/stopbutton"
android:layout_width="300px"
android:layout_height="300px"
android:layout_marginTop="10dp"
android:scaleType="fitCenter"
android:src="@drawable/mute" />
</LinearLayout>
</RelativeLayout>
</FrameLayout>
В AndroidManifest.xml пропишем разрешения на подключение к интернету и запрет поворота в альбомный режим:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ru.pythono.funspeak">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Анекдоты вслух"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Java код программы для получения анекдота использует библиотек jsoup, хотя при желании, можно было обойтись без неё. Но так как я изначально хотел парсить анекдоты на стороне клиента, то эту библиотеку я использовал для получения анекдота от PHP скрипта, просто указав в качестве цели для парсинга знак звездочки.
Листинг Java кода MainActivity.java:
package ru.pythono.funspeak;
import java.util.Locale;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.app.Activity;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.os.AsyncTask;
import android.widget.ImageButton;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import android.widget.ArrayAdapter;
public class MainActivity extends Activity implements TextToSpeech.OnInitListener {
protected static final int RESULT_SPEECH = 1;
private ImageButton fun; // кнопка Анекдот
private ImageButton stopbutton; // кнопка Тихо!
private TextToSpeech mTTS; // Объект синтезатора речи
public final static String EXTRA_MESSAGE = "EXTRA_MESSAGE";
public Elements anekdot;
public String otvet="Сервер не отвечает"; // Фраза, в случае ошибок сервера
private ArrayAdapter<String> adapter;
public Integer stopflag=0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTTS = new TextToSpeech(this, this);
stopbutton = (ImageButton) findViewById(R.id.stopbutton);
fun = (ImageButton) findViewById(R.id.fun);
fun.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fun.setImageResource(R.drawable.loading);
stopflag=1;
mTTS.stop();
new Serverzapros().execute();
}
});
// Ловим нажатие кнопки Тихо!
stopbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopflag=1;
mTTS.stop();
}
});
}
// Устанавливаем русский язык для синтеза речи
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
Locale locale = new Locale("ru");
int result = mTTS.setLanguage(locale);
}
fun.setImageResource(R.drawable.anekdot);
}
// При выключении программы выключаем синтезатор речи
@Override
public void onDestroy() {
if (mTTS != null) {
mTTS.stop();
mTTS.shutdown();
}
super.onDestroy();
}
// Даём запрос к серверу на PHP чтобы получить очередной анекдот
public class Serverzapros extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... arg) {
Document doc;
try {
doc = Jsoup.connect("http://pythono.ru/alina/fun.php").get();
anekdot = doc.select("*");
// Парсим с помощью Jsop Ответ сервера и выделяем текст из div c классом content
for (Element titles : anekdot) { otvet = titles.text(); }
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// Читаем вслух полученный анекдот
@Override
protected void onPostExecute(String result) {
fun.setImageResource(R.drawable.anekdot);
mTTS.speak(otvet, TextToSpeech.QUEUE_ADD, null);
}
}
}
Если вы захотите протестировать приложение, не забудьте скачать и настроить синтез русской речи от Google. На многих телефонах он настроен по умолчанию.
Тема о данной программе на 4pda.ru находится здесь:
http://4pda.ru/forum/index.php?showtopic=884149
Парсинг анекдотов на стороне PHP позволяет быть независимым от источника анекдотов, если сайт, который я сейчас использую в качестве поставщика контента отвалится, я всегда могу заменить его на другой, не выкатывая обновления для Android программы.
С помощью подобных приемов можно легко создать программу, читающую вслух новости, погоду, курсы валют и многое другое.
Материал подготовлен автором @pythono