Hola habr
Estimado lector! Si está interesado en el análisis html y el desarrollo de Android, este artículo es para usted. Espero que encuentres muchas cosas interesantes y útiles. En él quiero compartir mi experiencia en este campo.
Descripción del problema
Un poco sobre mi. Soy un estudiante de tercer año de ITA SFU. Como todos los estudiantes, necesito mirar el horario de clases todos los días. Y necesito saber el horario no solo al día siguiente, sino también con una o dos semanas de anticipación.
Parecería, ¿por qué no solo guardar el horario y usarlo? Desafortunadamente, hay una serie de razones que evitan esto, a saber:
- El horario de una semana puede ser muy diferente del horario de otra.
- El horario no es constante y puede cambiar
Por supuesto, hay un sitio con un horario, pero no es muy conveniente, ya que solo muestra una tabla en bruto con un horario durante 20 semanas. El estudiante tiene que pasar una página grande, buscando un horario para el día deseado. Además, en el modo fuera de línea, la programación deja de estar disponible.
Decidí hacer una pequeña aplicación que pudiera analizar el sitio con el horario de mi instituto y que tuviera el siguiente conjunto de cosas:
- Pantalla: número de semana actual, fecha, día de la semana y horario para ese día
- La capacidad de desplazarse por la programación con los botones "atrás" y "siguiente"
- Si no hay Internet, muestre la última versión descargada de la programación fuera de línea
Proceder a la ejecución
Entonces, arremangándome las mangas, me puse a trabajar. Necesitas empezar de a poco. Es decir, desde la edición del archivo de manifiesto. Vale la pena recordar que nuestra aplicación funcionará con Internet y es muy importante para nosotros obtener el permiso apropiado:
Archivo de manifiestoVaya a manifiestos-> AndroidManifest.xml. Agregar permiso El resultado es algo como esto:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapplication"> <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
Ahora pasemos a la interfaz. Por ahora, centrémonos en la funcionalidad y no en abusar de los widgets. Por lo tanto, coloqué solo cuatro widgets: Título, cuadro de texto y botones: adelante y atrás.
Marcado de actividad <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/WeekNumber" android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" " app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/timetable" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="100dp" android:ems="10" android:inputType="textMultiLine" android:text="" app:layout_constraintTop_toBottomOf="@+id/WeekNumber" tools:layout_editor_absoluteX="0dp" /> <Button android:id="@+id/next" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" app:layout_constraintBottom_toBottomOf="parent" tools:layout_editor_absoluteX="0dp"></Button> <Button android:id="@+id/down" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" app:layout_constraintBottom_toTopOf="@+id/next" tools:layout_editor_absoluteX="0dp"></Button> </androidx.constraintlayout.widget.ConstraintLayout>
Ahora comencemos a analizar. Aquí es donde nos ayuda el maravilloso analizador de código abierto Jsoup. Inmediatamente descarté la opción usando WebView, ya que este método me pareció extremadamente inconveniente. Además, realmente no quería usar un widget adicional, sin el cual puedes hacerlo fácilmente.
Conexión JsoupAgregue la dependencia a build.gradle:
implementation 'org.jsoup:jsoup:1.11.1'
No olvides que trabajar con web para Android es una tarea difícil. Para evitar que la aplicación se cuelgue, debe trabajar con la web ubicada fuera de la transmisión de la interfaz de usuario. Por lo tanto, utilizaremos la clase AsyncTask. Pondremos la funcionalidad básica en él y luego simplemente transferiremos los datos a la secuencia de la interfaz de usuario.
Para aquellos que no están familiarizados con AsyncTask, quiero decir que esta clase debe ubicarse dentro de la clase de su actividad. La clase en sí se muestra a continuación.
Código de actividad con clase AsyncTask package com.example.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class MainActivity extends AppCompatActivity { public boolean offline; public String request; public String WeekNumber; public int count;
Como resultado, obtenemos los datos de esta forma:
Analicemos los métodos que utilizamos:
Crear un elemento de tipo Documento
Document document = null;
Obtenemos la página
document = Jsoup.connect(url).get();
Ahora obtenemos el contenido de la etiqueta del cuerpo
answer = document.body().html();
Jsoup también puede recuperar el contenido de otras etiquetas principales. Por ejemplo, puede obtener el título de la página utilizando el método title (), etc. Método html () Devuelve el código html y text () es texto sin etiquetas html.
Una vez recibido el código html, puede convertirlo a texto sin formato, eliminando todas las etiquetas. Esto se puede hacer usando parse (htmlcode) .text ():
return Jsoup.parse(answer).text();
Me gustaría compartir algunos métodos Jsoup más útiles que no se utilizaron:
Element link = document.select("tag");
La imagen en el spoiler anterior es un ejemplo de un calendario de una semana. De hecho, se nos devolverán 20 de esas semanas. Ahora nuestra tarea es encontrar hoy en este conjunto de datos y mostrarlo.
Trayendo a la mente
Entonces, ¿qué tenemos? Aprendimos a convertir el código html de una página en una cadena que se puede analizar fácilmente. Esto se puede hacer fácilmente usando los métodos de cadena .split () y .replace ().
En general, el algoritmo se verá así.
Primero obtenemos la fecha deseada de Android. Luego hacemos dos ciclos, uno anidado en el otro. El primer ciclo recorre las semanas, el segundo, que está dentro de él, recorre los días de la semana. Si la fecha del día coincide con la fecha recibida de Android, mostramos la programación de este día en el cuadro de texto. Sin embargo, todos pueden escribir este algoritmo a su manera. Adjunto mi versión de su implementación.
Código de actividad completo package com.example.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class MainActivity extends AppCompatActivity { public boolean offline; public String request; public String WeekNumber; public int count;
la búsqueda de la programación se produce en el método formating (). Al enviar una fecha al método de entrada, obtendremos un cronograma para ese día. Entonces podemos implementar fácilmente el código para los botones "atrás" y "siguiente"
Código del siguiente botón:
count++; Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DAY_OF_YEAR,count); Date dayformat = calendar.getTime(); SimpleDateFormat format = new SimpleDateFormat("dd MMMM"); formating(format.format(dayformat));
Usando Calendario obtenemos la fecha de hoy. Usando el método de agregar, agregamos el número de días registrados en conteo a la fecha de hoy. El código para el botón Atrás será similar, solo el conteo deberá disminuir el valor.
Conclusión
Por supuesto, puedes trabajar en el diseño, pero ese es otro tema. Solo quería compartir las tecnologías básicas. En los spoilers a continuación, adjunté capturas de pantalla con un diseño mejorado. También agregué varias funciones, por ejemplo: configuraciones, la capacidad de seleccionar un grupo de estudio, etc. La aplicación en sí se puede ver un poco más tarde, tan pronto como lo recuerde.
Captura de pantalla de la aplicación