Etape 2: Mettre en place les composants nécessaires respectant l'architecture ci-dessus.
Activity principal: HomeActivity
Fragments: ArticlesFragment, ArticleDetailFragment
Layouts: home_activity, articles_list_fragment, articlet_detail_fraggment
ViewModels: ArticlesViewModel
Repository: ArticleRepository
Data Source: LocalDataSource, RemoteDataSource
Activity/Fragment
- Modiier l'activité principale pour afficher le fragment ArticlesFragment par défaut.
Layouts
- home_activity.xml doit contenir un FrameLayout dans lequel vous placerez les fragments.
- articles_list_fragment.xml contient un RecyclerView
- articlet_detail_fraggment contient: un Textview pour le titre, un TextView pour la description, une ImageView pour la photo de l'auteur
Repository
Modifier le Repository en y ajoutant une méthode permettant de récupérer la liste des articles via le web service
a. Créer une data class (Article) modélisant les articles
.....
b. Ajouter les dépendances de Retroit
//dependances retrofit
implementation "com.squareup.retrofit2:retrofit:2.6.2"
//dependances okhttp
implementation "com.squareup.okhttp3:okhttp:4.2.0"
//dependances gson
implementation 'com.google.code.gson:gson:2.8.5'
//dependances converter gson
implementation "com.squareup.retrofit2:converter-gson:2.5.0"
c. Créer une d'interface pour modéliser les actions du web service (contenant les actions du web service)
interface ArticleService {
@GET("/articles")
fun getArticles(): Response<List<Article>>
}
d. Créer une instance de Retroit
Modifier la classe RemoteDataSource
class RemoteDataSource {
private val service: ArticleService
init {
val retrofit = Retrofit.Builder().apply {
//Ajouter un converter pour JSON
//Ici on utilise gson
addConverterFactory(GsonConverterFactory.create())
//Ajouter l'url de base du web service
baseUrl("https://newsapi.org/")
}.build()
//Créer une instance du service
service = retrofit.create(ArticleService::class.java)
}
fun getRemoteArticles(): List<Article> {
val result = service.getArticles()
return if(result.isSuccessful) {
result.body() ?: emptyList()
}else {
emptyList()
}
}
}
e. Modifier le Repository
class Repository {
private val online = RemoteDataSource()
fun getArticles(): List<Article> {
return online.getRemoteArticles()
}
}
f. Modifier le ViewModel pour récupérer la liste des articles
class MyViewModel : ViewModel() {
private val repository: Repository = Repository()
private val _listArticles = MutableLiveData<List<Article>>()
val listArticles: LiveData<List<Article>>
get() = _listArticles
fun loadData() {
val result = repository.getArticles()
_listArticles.value = result
}
}
g. Modifier le fragment ArticlesFragment pour charger la liste des articles et observer les changements sur la liste des articles.
class ArticlesListFragment: Fragment() {
lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
viewModel.loadData()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.listArticles.observe(viewLifecycleOwner, Observer {
})
}
}
h. Pour l'instant, afficher la liste des articles dans la console.
Lancer l'application et vérifier que la liste des articles est affichée dans la console.
Si vous avez suivi à la lettre ce qui est décrit dans le TP, l'application crash au runtime; bon courage pour fixer cette erreur :)
Kidding, il manque la permission Internet, il suffit de l'ajouter dans le Manifest.
Etape 3: Afficher la liste des articles dans un RecyclerView
a. Créer un layout modélisant l'affichage des items dans le recycler view
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
... ...
</androidx.constraintlayout.widget.ConstraintLayout>
b. Créer un Adapter
class ArticleAdapter : RecyclerView.Adapter<ArticleAdapter.ViewHolder>() {
private val dataset: MutableList<Article> = mutableListOf()
class ViewHolder(val root: View) : RecyclerView.ViewHolder(root) {
fun bind(item: Article) {
val txtTitle = root.findViewById<TextView>(R.id.article_title)
val txtDesc = root.findViewById<TextView>(R.id.article_description)
txtTitle.text = item.title
txtDesc.text = item.description
}
}
fun updateData(list: List<Article>) {
dataset.clear()
dataset.addAll(list)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val rootView = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ViewHolder(rootView)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(dataset[position])
}
override fun getItemCount() = dataset.size
}
c. Afficher les données dans le RecyclerView
..... override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//définir l'orientation des élements (vertical)
recyclerView.layoutManager = LinearLayoutManager(context)
//associer l'adapter à la recyclerview
recyclerView.adapter = adapterRecycler
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.listArticles.observe(viewLifecycleOwner, Observer {
adapterRecycler.updateData(it)
})
}
d. Compiler et tester !