- 15 Mar 2018
- 1,109
- 25
Merhaba Sayın THT üyeleri, bu gün Retrofit ve RxJava kullanarak internetten nasıl veri çekebiliriz onu göreceğiz. Bunu yaparken MVVM yapısını kullanmayı ihmal etmeyeceğiz.
Diyelim ki bir APImız var ve bizim bu APIdaki verileri almamız gerekiyor. Bu örnek için https://ctftime.org/api/v1/events/?limit=50&start=1600470626&finish=1611011426 'yi kullanacağız.
Şimdi Android Studioda yeni bir proje oluşturalım.
MVVM yapısını kullanmak ve en iyi şekilde yararlanmak için bir tane fragment oluşturalım
Daha sonra oluşturduğumuz Fragmentı MainActivitye ekliyoruz. Şimdi verileri çekerken kullanacağımız Retrofit ve RxJavayı import edelim. build.gradle dosyamız bu şekilde olmalı.
Şimdi kodlarımızı yazmaya başlayabiliriz, ilk olarak Modelimizi yazalım. CTFModel adlı bir sınıf oluşturalım ve bu sınıfı aşağıda da görüldüğü gibi bir data class'a çevirelim.
Gördüğünüz gibi API'de bizle paylaşılan propertylerin isimlerini aynen girerek onları belirtiyoruz.
Şimdi API bağlantısı için bir Interface oluşturalım, ismine CTFApi diyorum.
Gördüğünüz gibi API urlmizin BASE dediğimiz baş kısmını yazmadık, şimdi oluşturacağımız CTFService'de de orayı halledeceğiz. CTFService isimli bir sınıf oluşturalım
Gördüğünüz gibi burda Retrofit Builder ile CallAdapter ve Converterımızı belirtiyoruz.
Şimdi RecyclerView ile verilerimizin sıralı bir şekilde gelmesini sağlayalım. Recycleri View'ı oluşturalım;
Daha sonra alacağımız veriler için şu layoutu kullanalım;
Buradaki drawable/line sizde çıkmayacaktır. Her bir sırayı birbirinden ayırmak için bir çizgi çizdim ve onu res -> drawable'ın içine attım.
Layout ve API & Service & Model işlemlerimiz bittiğine göre şimdi Bir Adapter yazıp verileri RecyclerView'a aktaralım.
CTFAdapter isimli bir sınıf oluşturalım;
Buradaki override edilen fonksyionları tek tek açıklayalım.
getItemCount = Bu fonksiyon RecyclerView'da kaç tane item yani row olacağını söyler burada CTF Listesinin büyüklüğünü verdik.
updateCtfEventList = Bu fonksiyon bütün listeyi temizleyip yeniden alır.
onBindViewHolder = Gelen verileri RecyclerView'daki alanlarla eşitler. Verileri bağladığımız kısım budur.
onCreateViewHolder = ViewHolder yani RecyclerView'ı tutan Holder başladığında ne olacağını söyler, buradaki örnekte görüntüyü eşitliyoruz.
Canlı olarak verilerin takibini yapabilmek için ViewModel da ekliyoruz
CtfViewModel isimli bir sınıf oluşturalım;
Canlı veri tutmanın olayı asıl burada başlıyor. Gördüğünüz gibi Events, Error ve Loading isimli üç durumumuz var. Veriler çekilme kullanıcı istek attığı an Loading true oluyor. onSuccess yani başarılı olduğunda diğerleri false bu sefer events true oluyor. onError'da ise error true oluyor. Bunlar her daim canlı tutabilmemiz için çok önemli ve kullanışlılar.
onCleared() metodu ise disposable yani kullan atılabilir olarak belirttiğimiz işlemi temizliyor ve sonlandırıyor.
Fragment'ımızın içi biraz daha karışık ona isterseniz tane tane bakalım.
Öncelikle fragment layoutumuzun içine bunları yazıyoruz.
Gördüğünüz gibi layoutumuzu Swipe ******* Layout yani üstten çekince yenileyen layout olarak değiştirdik ve ek olarak bir recycler view bir textview bir de progress bar ekledik
RecyclerView veriler gelirse gösterilecek, TextView hata olursa gösterilecek, ProgressBar ise yüklenirken gösterilecek
Şimdi fragmentımızı yazmaya başlayabiliriz ama fragment biraz karışık o yüzden açıklayarak ve part part gideceğim.
Az önce kodladığımı CTF View Model'i tanımladık ve onCreateView() altında layoutumuzu eşitledik.
onViewCreated altında öncelikle verilerimizi yeniledik daha sonra layoutumuzun LinearLayoutManager olduğunu söyledik adapter'ımızı da ctfEventAdapter olarak tanımladık.
Ve bir setOn*******Listener koyduk. Bunun içinde liste ve hata mesajının gitmesini progress barın görünmesini ayarladık ve daha sonra verileri yeniledik. yenileme kodu çalıştıktan sonra layout *******ini false olarak ayarladık.
Listener'ın dışında ise observeLiveData dedik ve canlı olarak verileri gözlemlemeye başladık.
Şimdi observeLiveData'nın kodlarına bakalım
Burada kısaca teker teker hepsine bir gözlemleyeci atayıp veri geldi mi yükleniyor mu ve hata var mı şeklinde kontroller yapıyoruz eğer biri olduysa diğerleriNİ görünmez yapıp güncel olanı görünür hale getiriyoruz.
Ve tabi ki AndroidManifest'in altında internet iznini ekliyoruz
API'den veri çekerken herhangi bir sorunla karşı karşıya kalırsanız bana her zaman yazabilirsiniz, İyi forumlar
Dostlar yeni farkettim ******* yazan yerlerde R efresh yazıyor
Diyelim ki bir APImız var ve bizim bu APIdaki verileri almamız gerekiyor. Bu örnek için https://ctftime.org/api/v1/events/?limit=50&start=1600470626&finish=1611011426 'yi kullanacağız.
Şimdi Android Studioda yeni bir proje oluşturalım.
MVVM yapısını kullanmak ve en iyi şekilde yararlanmak için bir tane fragment oluşturalım
Daha sonra oluşturduğumuz Fragmentı MainActivitye ekliyoruz. Şimdi verileri çekerken kullanacağımız Retrofit ve RxJavayı import edelim. build.gradle dosyamız bu şekilde olmalı.
Kod:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.ego1st.apideneme"
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
def retrofitVersion = '2.9.0'
def rxJavaVersion = '2.1.1'
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxJavaVersion"
}
Şimdi kodlarımızı yazmaya başlayabiliriz, ilk olarak Modelimizi yazalım. CTFModel adlı bir sınıf oluşturalım ve bu sınıfı aşağıda da görüldüğü gibi bir data class'a çevirelim.
Kod:
package com.ego1st.apideneme
data class CTFModel (
val url: String?,
val hours: String?,
val days: String?,
val start: String?,
val finish: String?,
val title: String?,
val description: String?,
val name: String?
)
Gördüğünüz gibi API'de bizle paylaşılan propertylerin isimlerini aynen girerek onları belirtiyoruz.
Şimdi API bağlantısı için bir Interface oluşturalım, ismine CTFApi diyorum.
Kod:
package com.ego1st.apideneme
import io.reactivex.Single
import retrofit2.http.GET
interface CTFApi {
//https://ctftime.org/api/v1/events/?limit=50&start=1600470626&finish=1611011426
[USER=675520]Get[/USER]("events/?limit=50&start=1600470626&finish=1611011426")
fun getCtfEvents(): Single<List<CTFModel>>
}
Gördüğünüz gibi API urlmizin BASE dediğimiz baş kısmını yazmadık, şimdi oluşturacağımız CTFService'de de orayı halledeceğiz. CTFService isimli bir sınıf oluşturalım
Kod:
package com.ego1st.apideneme
import io.reactivex.Single
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
class CTFService {
private val BASE_URL = "https://ctftime.org/api/v1/"
private val api = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
.create(CTFApi::class.java)
fun getCtfEventData() : Single<List<CTFModel>> {
return api.getCtfEvents()
}
}
Gördüğünüz gibi burda Retrofit Builder ile CallAdapter ve Converterımızı belirtiyoruz.
Şimdi RecyclerView ile verilerimizin sıralı bir şekilde gelmesini sağlayalım. Recycleri View'ı oluşturalım;
Daha sonra alacağımız veriler için şu layoutu kullanalım;
Kod:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="@+id/event_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingBottom="10dp"
android:text="Title"
android:textColor="@color/colorPrimary"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/event_organizer_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingBottom="10dp"
android:text="Organizer Name"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/event_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingTop="10dp"
android:text="Description"
android:textColor="#02D2D2"
android:textSize="14sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone">
<TextView
android:id="@+id/event_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingBottom="10dp"
android:text="Start"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/event_finish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingBottom="10dp"
android:text="Finish"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone">
<TextView
android:id="@+id/event_hours"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingBottom="10dp"
android:text="Hours"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/event_days"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingBottom="10dp"
android:text="Days"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/event_url"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="web"
android:fontFamily="sans-serif-light"
android:padding="10dp"
android:paddingStart="10dp"
android:paddingBottom="10dp"
android:text="url"
android:textSize="14sp"
android:textStyle="bold"
android:visibility="gone" />
<ImageView
android:id="@+id/imageView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat= [USER=252003]draw[/USER]able/line" />
</LinearLayout>
</LinearLayout>
</layout>
Buradaki drawable/line sizde çıkmayacaktır. Her bir sırayı birbirinden ayırmak için bir çizgi çizdim ve onu res -> drawable'ın içine attım.
Layout ve API & Service & Model işlemlerimiz bittiğine göre şimdi Bir Adapter yazıp verileri RecyclerView'a aktaralım.
CTFAdapter isimli bir sınıf oluşturalım;
Kod:
package com.ego1st.apideneme
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.ctf_row.view.*
class CTFAdapter (private val ctfEventList : ArrayList<CTFModel>) : RecyclerView.Adapter<CTFAdapter.CtfEventHolder> () {
class CtfEventHolder(val view: View) : RecyclerView.ViewHolder(view)
private var sit = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CtfEventHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.ctf_row, parent, false)
return CtfEventHolder(view)
}
override fun onBindViewHolder(holder: CtfEventHolder, position: Int) {
holder.view.event_title.text = ctfEventList[position].title
holder.view.event_organizer_name.text = ctfEventList[position].name
holder.view.event_description.text = ctfEventList[position].description
holder.view.setOnClickListener {
if(!sit) {
holder.view.event_start.visibility = View.VISIBLE
holder.view.event_finish.visibility = View.VISIBLE
holder.view.event_hours.visibility = View.VISIBLE
holder.view.event_days.visibility = View.VISIBLE
holder.view.event_url.visibility = View.VISIBLE
sit = true
} else if(sit) {
holder.view.event_start.visibility = View.GONE
holder.view.event_finish.visibility = View.GONE
holder.view.event_hours.visibility = View.GONE
holder.view.event_days.visibility = View.GONE
holder.view.event_url.visibility = View.GONE
sit = false
}
}
holder.view.event_start.text = ctfEventList[position].start
holder.view.event_finish.text = ctfEventList[position].finish
holder.view.event_hours.text = ctfEventList[position].hours
holder.view.event_days.text = ctfEventList[position].days
holder.view.event_url.text = ctfEventList[position].url
}
override fun getItemCount(): Int {
return ctfEventList.size
}
fun updateCtfEventList(newCtfEventList: List<CTFModel>){
ctfEventList.clear()
ctfEventList.addAll(newCtfEventList)
notifyDataSetChanged()
}
}
Buradaki override edilen fonksyionları tek tek açıklayalım.
getItemCount = Bu fonksiyon RecyclerView'da kaç tane item yani row olacağını söyler burada CTF Listesinin büyüklüğünü verdik.
updateCtfEventList = Bu fonksiyon bütün listeyi temizleyip yeniden alır.
onBindViewHolder = Gelen verileri RecyclerView'daki alanlarla eşitler. Verileri bağladığımız kısım budur.
onCreateViewHolder = ViewHolder yani RecyclerView'ı tutan Holder başladığında ne olacağını söyler, buradaki örnekte görüntüyü eşitliyoruz.
Canlı olarak verilerin takibini yapabilmek için ViewModel da ekliyoruz
CtfViewModel isimli bir sınıf oluşturalım;
Kod:
package com.ego1st.apideneme
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.observers.DisposableSingleObserver
import io.reactivex.schedulers.Schedulers
class CtfViewModel(): ViewModel {
private val ctfService = CTFService()
private val diposable = CompositeDisposable()
val ctfEvents = MutableLiveData<List<CTFModel>>()
val ctfError = MutableLiveData<Boolean>()
val ctfLoading = MutableLiveData<Boolean>()
fun *******Data(){
getDataFromAPI()
}
private fun getDataFromAPI(){
ctfLoading.value = true
diposable.add(
ctfService.getCtfEventData()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object : DisposableSingleObserver<List<CTFModel>>() {
override fun onSuccess(t: List<CTFModel>) {
ctfEvents.value = t
ctfError.value = false
ctfLoading.value = false
}
override fun onError(e: Throwable) {
ctfError.value = true
ctfLoading.value = false
println(e)
}
}
)
)
}
override fun onCleared() {
super.onCleared()
diposable.clear()
}
}
Canlı veri tutmanın olayı asıl burada başlıyor. Gördüğünüz gibi Events, Error ve Loading isimli üç durumumuz var. Veriler çekilme kullanıcı istek attığı an Loading true oluyor. onSuccess yani başarılı olduğunda diğerleri false bu sefer events true oluyor. onError'da ise error true oluyor. Bunlar her daim canlı tutabilmemiz için çok önemli ve kullanışlılar.
onCleared() metodu ise disposable yani kullan atılabilir olarak belirttiğimiz işlemi temizliyor ve sonlandırıyor.
Fragment'ımızın içi biraz daha karışık ona isterseniz tane tane bakalım.
Öncelikle fragment layoutumuzun içine bunları yazıyoruz.
Kod:
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.swipe*******layout.widget.Swipe*******Layout
android:id="@+id/swipe*******Ctf"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ShowFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ctfEventList"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/errorTextCtf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hata! Tekrar dene"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="invisible"/>
<ProgressBar
android:id="@+id/mainProgressBarCtf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="invisible"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swipe*******layout.widget.Swipe*******Layout>
</layout>
Gördüğünüz gibi layoutumuzu Swipe ******* Layout yani üstten çekince yenileyen layout olarak değiştirdik ve ek olarak bir recycler view bir textview bir de progress bar ekledik
RecyclerView veriler gelirse gösterilecek, TextView hata olursa gösterilecek, ProgressBar ise yüklenirken gösterilecek
Şimdi fragmentımızı yazmaya başlayabiliriz ama fragment biraz karışık o yüzden açıklayarak ve part part gideceğim.
Kod:
class ShowFragment : Fragment() {
private lateinit var ctfViewModel: CtfViewModel
private val ctfEventAdapter = CTFAdapter(arrayListOf())
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
ctfViewModel = ViewModelProviders.of(this).get(CtfViewModel::class.java)
return inflater.inflate(R.layout.fragment_show, container, false)
}
Az önce kodladığımı CTF View Model'i tanımladık ve onCreateView() altında layoutumuzu eşitledik.
Kod:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ctfViewModel.*******Data()
ctfEventList.layoutManager = LinearLayoutManager(context)
ctfEventList.adapter = ctfEventAdapter
swipe*******Ctf.setOn*******Listener {
ctfEventList.visibility = View.GONE
errorTextCtf.visibility = View.GONE
mainProgressBarCtf.visibility = View.VISIBLE
ctfViewModel.*******Data()
swipe*******Ctf.is*******ing = false
}
observeLiveData()
}
onViewCreated altında öncelikle verilerimizi yeniledik daha sonra layoutumuzun LinearLayoutManager olduğunu söyledik adapter'ımızı da ctfEventAdapter olarak tanımladık.
Ve bir setOn*******Listener koyduk. Bunun içinde liste ve hata mesajının gitmesini progress barın görünmesini ayarladık ve daha sonra verileri yeniledik. yenileme kodu çalıştıktan sonra layout *******ini false olarak ayarladık.
Listener'ın dışında ise observeLiveData dedik ve canlı olarak verileri gözlemlemeye başladık.
Şimdi observeLiveData'nın kodlarına bakalım
Kod:
private fun observeLiveData() {
ctfViewModel.ctfEvents.observe(viewLifecycleOwner, Observer {ctfEvents ->
ctfEvents?.let {
ctfEventList.visibility = View.VISIBLE
errorTextCtf.visibility = View.GONE
mainProgressBarCtf.visibility = View.GONE
ctfEventAdapter.updateCtfEventList(ctfEvents)
}
})
ctfViewModel.ctfError.observe(viewLifecycleOwner, Observer { e ->
e?.let {
if(it){
ctfEventList.visibility = View.GONE
errorTextCtf.visibility = View.VISIBLE
mainProgressBarCtf.visibility = View.GONE
} else {
ctfEventList.visibility = View.VISIBLE
errorTextCtf.visibility = View.GONE
mainProgressBarCtf.visibility = View.VISIBLE
}
}
})
ctfViewModel.ctfLoading.observe(viewLifecycleOwner, Observer { loading ->
loading?.let {
if(it){
ctfEventList.visibility = View.GONE
errorTextCtf.visibility = View.GONE
mainProgressBarCtf.visibility = View.VISIBLE
} else {
mainProgressBarCtf.visibility = View.GONE
}
}
})
}
Burada kısaca teker teker hepsine bir gözlemleyeci atayıp veri geldi mi yükleniyor mu ve hata var mı şeklinde kontroller yapıyoruz eğer biri olduysa diğerleriNİ görünmez yapıp güncel olanı görünür hale getiriyoruz.
Ve tabi ki AndroidManifest'in altında internet iznini ekliyoruz
Kod:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ego1st.apideneme">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
API'den veri çekerken herhangi bir sorunla karşı karşıya kalırsanız bana her zaman yazabilirsiniz, İyi forumlar
Dostlar yeni farkettim ******* yazan yerlerde R efresh yazıyor
Son düzenleme: