Oi Habr!
Caro leitor! Se você está interessado na análise de html e no desenvolvimento do Android, este artigo é para você. Espero que você encontre muitas coisas interessantes e úteis. Nele, quero compartilhar minha experiência neste campo.
Descrição do problema
Um pouco sobre mim. Sou estudante do terceiro ano do ITA SFU. Como todos os alunos, preciso olhar para o horário das aulas todos os dias. E preciso conhecer a programação não apenas no dia seguinte, mas também com uma ou duas semanas de antecedência.
Parece, por que não salvar o cronograma e usá-lo? Infelizmente, existem várias razões que impedem isso, a saber:
- A programação para uma semana pode ser muito diferente da programação para outra
- A programação não é constante e pode mudar
Obviamente, existe um site com uma programação, mas não é muito conveniente, pois apenas exibe uma tabela bruta com uma programação por 20 semanas. O aluno tem que virar uma página grande, procurando uma programação para o dia desejado. Além disso, no modo offline, a programação fica indisponível.
Decidi fazer um pequeno aplicativo que poderia analisar o site com a programação do meu instituto e teria o seguinte conjunto de guloseimas:
- Exibição: número da semana atual, data, dia da semana e programação para esse dia
- A capacidade de rolar a programação com os botões "voltar" e "próximo"
- Se não houver Internet, mostre a versão offline mais recente da programação
Prossiga para a execução
Então, arregaçando as mangas, comecei a trabalhar. Você precisa começar pequeno. Ou seja, da edição do arquivo de manifesto. Vale lembrar que nosso aplicativo funcionará com a Internet e é muito importante obtermos a permissão apropriada:
Arquivo de manifestoVá para manifestos-> AndroidManifest.xml. Adicione permissão. O resultado é algo como isto:
<?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>
Agora vamos para a interface. Por enquanto, vamos nos concentrar na funcionalidade e não abusar de widgets. Portanto, coloquei apenas quatro widgets: título, caixa de texto e botões: indo e voltando.
Marcação de atividade <?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>
Agora vamos começar a analisar. É aqui que o maravilhoso analisador de código aberto Jsoup nos ajuda. Eu imediatamente rejeitei a opção usando o WebView, pois achei esse método extremamente inconveniente. Além disso, eu realmente não queria usar um widget extra, sem o qual você pode fazer facilmente.
Conexão JsoupAdicione a dependência ao build.gradle:
implementation 'org.jsoup:jsoup:1.11.1'
Não esqueça que trabalhar com a web para Android é uma tarefa difícil. Para impedir que o aplicativo seja interrompido, você precisa trabalhar com a Web localizada fora do fluxo da UI. Portanto, usaremos a classe AsyncTask. Vamos colocar a funcionalidade básica nele e depois transferir os dados para o fluxo da interface do usuário.
Para aqueles que não estão familiarizados com o AsyncTask, quero dizer que essa classe deve estar localizada dentro da classe da sua atividade. A classe em si é mostrada abaixo.
Código de atividade com a classe 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, obtemos os dados neste formulário:
Programação de uma semana Vamos analisar os métodos que usamos:
Crie um elemento do tipo Documento
Document document = null;
Nós temos a página
document = Jsoup.connect(url).get();
Agora obtemos o conteúdo da tag body
answer = document.body().html();
O Jsoup também pode recuperar o conteúdo de outras tags principais. Por exemplo, você pode obter o título da página usando o método title () etc. Método Html () Retorna o código html, e text () é texto sem formatação sem tags html.
Após receber o código html, você pode convertê-lo em texto sem formatação, removendo todas as tags. Isso pode ser feito usando parse (htmlcode) .text ():
return Jsoup.parse(answer).text();
Eu gostaria de compartilhar alguns métodos Jsoup mais úteis que não foram usados:
Element link = document.select("tag");
A imagem no spoiler acima é um exemplo de programação de uma semana. De fato, 20 dessas semanas serão devolvidas a nós. Agora, nossa tarefa é encontrar hoje neste conjunto de dados e exibi-lo.
Trazendo à mente
Então o que nós temos? Aprendemos como converter o código html de uma página em uma string que pode ser facilmente analisada. Isso pode ser feito facilmente usando os métodos de string .split () e .replace ().
Em geral, o algoritmo terá esta aparência.
Primeiro, obtemos a data desejada no Android. Então fazemos dois ciclos, um aninhado no outro. O primeiro ciclo percorre as semanas, o segundo, que está dentro, percorre os dias da semana. Se a data do dia coincidir com a data recebida do Android, exibiremos a programação deste dia na caixa de texto. No entanto, todos podem escrever esse algoritmo à sua maneira. Anexei minha versão de sua implementação.
Código completo da atividade 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;
a busca da agenda ocorre no método formating (). Ao enviar uma data para o método de entrada, obteremos uma programação para esse dia. Para que possamos implementar facilmente o código dos botões "voltar" e "próximo"
Próximo código do botão:
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 o Calendário, obtemos a data de hoje. Usando o método add, adicionamos o número de dias registrados na contagem à data de hoje. O código para o botão voltar será semelhante, apenas a contagem precisará diminuir o valor.
Conclusão
Obviamente, você pode trabalhar no design, mas esse é outro tópico. Eu só queria compartilhar as tecnologias básicas. Nos spoilers abaixo, anexei capturas de tela com um design aprimorado. Também adicionei várias funções, por exemplo: configurações, a capacidade de selecionar um grupo de estudo, etc. O aplicativo em si pode ser visualizado um pouco mais tarde, assim que eu o lembrar.
Captura de tela do aplicativo