Sem apresentações longas, mostrarei como organizar de forma rápida e fácil uma arquitetura conveniente do seu aplicativo. O material será útil para aqueles que não estão muito familiarizados com o padrão mvvm e as corotinas Kotlin.
Portanto, temos uma tarefa simples: receber e processar uma solicitação de rede, exibir o resultado em uma exibição.
Nossas ações: a partir da atividade (fragmento), chamamos o método desejado ViewModel -> ViewModel acessa o identificador de retrofit, executando a solicitação através das corotinas -> a resposta é enviada para os dados ao vivo como um evento -> na atividade que recebe o evento, transferimos os dados para a visualização.
Configuração do projeto
Dependências
Manifesto
<manifest ...> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
Retrofit Setup
Crie um objeto Kotlinovsky
NetworkService . Este será o nosso cliente de rede - singleton
O singleton UPD é usado para facilitar o entendimento. Os comentários indicaram que é mais apropriado usar a inversão de controle, mas este é um tópico separado.
object NetworkService { private const val BASE_URL = " http://www.mocky.io/v2/"
Interface API
Usamos solicitações bloqueadas para o serviço falso.
Pare a diversão, aqui começa a magia do corutin.
Marcamos nossas funções com a palavra-chave
suspender diversão ....O retrofit aprendido a trabalhar com as funções de suspensão do Kotlin da versão 2.6.0, agora executa diretamente uma solicitação de rede e retorna um objeto com dados:
interface Api { @GET("5dcc12d554000064009c20fc") suspend fun getUsers( @Query("page") page: Int ): ResponseWrapper<Users> @GET("5dcc147154000059009c2104") suspend fun getUsersError( @Query("page") page: Int ): ResponseWrapper<Users> }
ResponseWrapper é uma classe de wrapper simples para nossas solicitações de rede:
class ResponseWrapper<T> : Serializable { @SerializedName("response") val data: T? = null @SerializedName("error") val error: Error? = null }
Classe de data
Usuários data class Users( @SerializedName("count") var count: Int?, @SerializedName("items") var items: List<Item?>? ) { data class Item( @SerializedName("first_name") var firstName: String?, @SerializedName("last_name") var lastName: String? ) }
ViewModel
Criamos uma classe abstrata
BaseViewModel a partir da qual todos os nossos ViewModel serão herdados. Aqui residimos em mais detalhes:
abstract class BaseViewModel : ViewModel() { var api: Api = NetworkService.retrofitService()
Eventos
Uma solução interessante do Google é agrupar classes de data em uma classe de wrapper Event, na qual podemos ter vários estados, geralmente LOADING, SUCCESS e ERROR.
data class Event<out T>(val status: Status, val data: T?, val error: Error?) { companion object { fun <T> loading(): Event<T> { return Event(Status.LOADING, null, null) } fun <T> success(data: T?): Event<T> { return Event(Status.SUCCESS, data, null) } fun <T> error(error: Error?): Event<T> { return Event(Status.ERROR, null, error) } } } enum class Status { SUCCESS, ERROR, LOADING }
Aqui está como isso funciona. Durante uma solicitação de rede, criamos um evento com o status LOADING. Estamos aguardando uma resposta do servidor e, em seguida, agrupe os dados com o evento e os envie com o status especificado. Na visualização, verificamos o tipo de evento e, dependendo do estado, definimos estados diferentes para a visualização. O padrão de arquitetura MVI é baseado na mesma filosofia.
ActivityViewModel
class ActivityViewModel : BaseViewModel() {
E finalmente
Mainatividade
class MainActivity : AppCompatActivity() { private lateinit var activityViewModel: ActivityViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) activityViewModel = ViewModelProviders.of(this).get(ActivityViewModel::class.java) observeGetPosts() buttonOneClickListener() buttonTwoClickListener() }
Código fonte