-
Notifications
You must be signed in to change notification settings - Fork 12
change retrofit api complete #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
be0ded1
f373650
d4a3f81
14363d4
0f45662
8d9e832
84304da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package com.example.architecturebase | ||
|
||
import android.content.Context | ||
import android.net.ConnectivityManager | ||
import android.net.NetworkCapabilities | ||
import android.os.Build | ||
import android.os.Bundle | ||
import android.view.View | ||
import android.widget.Toast | ||
import androidx.fragment.app.Fragment | ||
import androidx.recyclerview.widget.LinearLayoutManager | ||
import com.example.architecturebase.adapter.MainAdapter | ||
import com.example.architecturebase.databinding.FragmentBinding | ||
|
||
|
||
class Fragment : Fragment(R.layout.fragment) { | ||
|
||
private val mvvmModelView: MvvmContract = ViewModelMvvm() | ||
private val connectivityManager: ConnectivityManager by lazy { | ||
val r = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) | ||
r as ConnectivityManager | ||
} | ||
|
||
private var _binding: FragmentBinding? = null | ||
private val binding get() = _binding!! | ||
|
||
private val mainAdapter = MainAdapter() | ||
|
||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
super.onViewCreated(view, savedInstanceState) | ||
_binding = FragmentBinding.bind(view) | ||
binding.mainRV.apply { | ||
layoutManager = LinearLayoutManager(activity) | ||
adapter = mainAdapter | ||
} | ||
|
||
binding.listSRL.isRefreshing = true | ||
loadDataFromInternet() | ||
|
||
mvvmModelView.listPosts.observe(viewLifecycleOwner) { | ||
mainAdapter.items = it | ||
binding.listSRL.isRefreshing = false | ||
} | ||
|
||
mvvmModelView.errorMessage.observe(viewLifecycleOwner) { t -> showFailureLoadDataDialog(t) } | ||
|
||
binding.listSRL.setOnRefreshListener { | ||
mainAdapter.items = emptyList() | ||
loadDataFromInternet() | ||
|
||
} | ||
} | ||
|
||
private fun showFailureLoadDataDialog(t: Throwable) { | ||
t.printStackTrace() | ||
binding.listSRL.isRefreshing = false | ||
Toast.makeText(activity, t.message, Toast.LENGTH_SHORT).show() | ||
} | ||
|
||
override fun onDestroyView() { | ||
super.onDestroyView() | ||
_binding = null | ||
} | ||
|
||
private fun checkInternet(): Boolean { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||
val nw = connectivityManager.activeNetwork ?: return false | ||
val actNw = connectivityManager.getNetworkCapabilities(nw) ?: return false | ||
return when { | ||
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true | ||
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true | ||
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true | ||
else -> false | ||
} | ||
} else { | ||
val nwInfo = connectivityManager.activeNetworkInfo ?: return false | ||
return nwInfo.isConnected | ||
} | ||
} | ||
|
||
private fun loadDataFromInternet() { | ||
if (checkInternet()) { | ||
mvvmModelView.getPosts() | ||
} else { | ||
binding.listSRL.isRefreshing = false | ||
Toast.makeText(activity, "connect internet needed", Toast.LENGTH_SHORT).show() | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.example.architecturebase | ||
|
||
import com.example.architecturebase.network.IPostApi | ||
|
||
interface IRepository { | ||
|
||
suspend fun getData(): IPostApi | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,113 +1,20 @@ | ||
package com.example.architecturebase | ||
|
||
import android.os.Bundle | ||
import android.widget.Toast | ||
import androidx.appcompat.app.AppCompatActivity | ||
import androidx.recyclerview.widget.LinearLayoutManager | ||
import com.example.architecturebase.adapter.MainAdapter | ||
import com.example.architecturebase.databinding.ActivityMainBinding | ||
import com.example.architecturebase.network.IPostApi | ||
import com.example.architecturebase.network.model.Post | ||
import okhttp3.OkHttpClient | ||
import okhttp3.logging.HttpLoggingInterceptor | ||
import retrofit2.Call | ||
import retrofit2.Callback | ||
import retrofit2.Response | ||
import retrofit2.Retrofit | ||
import retrofit2.converter.gson.GsonConverterFactory | ||
import java.util.concurrent.TimeUnit | ||
|
||
class MainActivity : AppCompatActivity() { | ||
|
||
companion object { | ||
private const val REQUEST_TIMEOUT_SECONDS = 5L | ||
} | ||
|
||
private val binding by lazy { | ||
val bind = ActivityMainBinding.inflate(layoutInflater) | ||
setContentView(bind.root) | ||
bind | ||
} | ||
|
||
private val mainAdapter = MainAdapter() | ||
|
||
private val okHttpClient = OkHttpClient.Builder() | ||
.addInterceptor(HttpLoggingInterceptor().apply { | ||
level = HttpLoggingInterceptor.Level.BODY | ||
}) | ||
.callTimeout(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS) | ||
.build() | ||
|
||
private val retrofit = Retrofit.Builder() | ||
.baseUrl("https://jsonplaceholder.typicode.com") | ||
.addConverterFactory(GsonConverterFactory.create()) | ||
.client(okHttpClient) | ||
.build() | ||
|
||
private val postApi = retrofit.create(IPostApi::class.java) | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
|
||
binding.mainRV.apply { | ||
layoutManager = LinearLayoutManager(this@MainActivity) | ||
adapter = mainAdapter | ||
} | ||
binding.listSRL.isRefreshing = true | ||
postApi.getPosts().enqueue(object : Callback<List<Post>> { | ||
override fun onResponse(call: Call<List<Post>>, response: Response<List<Post>>) { | ||
if (response.isSuccessful) { | ||
response.body()?.let { posts -> | ||
// logic starts | ||
val processedPosts = posts.filter { | ||
!it.title.startsWith("H") | ||
}.map { | ||
it.copy(title = it.title + "appendix") | ||
}.sortedBy { | ||
it.title | ||
}.subList(0, posts.size - 3) | ||
// logic ends | ||
mainAdapter.items = processedPosts | ||
binding.listSRL.isRefreshing = false | ||
} | ||
} | ||
} | ||
|
||
override fun onFailure(call: Call<List<Post>>, t: Throwable) { | ||
Toast.makeText(this@MainActivity, t.message, Toast.LENGTH_SHORT).show() | ||
t.printStackTrace() | ||
binding.listSRL.isRefreshing = false | ||
setContentView(R.layout.activity_main) | ||
val fragment = Fragment() | ||
if (savedInstanceState == null) { | ||
supportFragmentManager.beginTransaction().apply { | ||
setReorderingAllowed(true) | ||
add(R.id.fragmentContainerView, fragment) | ||
commit() | ||
} | ||
}) | ||
|
||
binding.listSRL.setOnRefreshListener { | ||
mainAdapter.items = emptyList() | ||
|
||
postApi.getPosts().enqueue(object : Callback<List<Post>> { | ||
override fun onResponse(call: Call<List<Post>>, response: Response<List<Post>>) { | ||
if (response.isSuccessful) { | ||
response.body()?.let { posts -> | ||
// logic starts | ||
val processedPosts = posts.filter { | ||
!it.title.startsWith("H") | ||
}.map { | ||
it.copy(title = it.title + "appendix") | ||
}.sortedBy { | ||
it.title | ||
}.subList(0, posts.size - 3) | ||
// logic ends | ||
mainAdapter.items = processedPosts | ||
binding.listSRL.isRefreshing = false | ||
} | ||
} | ||
} | ||
|
||
override fun onFailure(call: Call<List<Post>>, t: Throwable) { | ||
Toast.makeText(this@MainActivity, t.message, Toast.LENGTH_SHORT).show() | ||
t.printStackTrace() | ||
binding.listSRL.isRefreshing = false | ||
} | ||
}) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.architecturebase | ||
|
||
import androidx.lifecycle.LifecycleObserver | ||
import androidx.lifecycle.LiveData | ||
import com.example.architecturebase.network.model.Post | ||
|
||
interface MvvmContract { | ||
|
||
val listPosts: LiveData<List<Post>> | ||
val errorMessage: LiveData<Throwable> | ||
fun getPosts() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.example.architecturebase | ||
|
||
import com.example.architecturebase.network.IPostApi | ||
import okhttp3.OkHttpClient | ||
import okhttp3.logging.HttpLoggingInterceptor | ||
import retrofit2.Retrofit | ||
import retrofit2.converter.gson.GsonConverterFactory | ||
import java.util.concurrent.TimeUnit | ||
|
||
class Repository : IRepository { | ||
|
||
private val okHttpClient = OkHttpClient.Builder() | ||
.addInterceptor(HttpLoggingInterceptor().apply { | ||
level = HttpLoggingInterceptor.Level.BODY | ||
}) | ||
.callTimeout(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS) | ||
.build() | ||
|
||
private val retrofit = Retrofit.Builder() | ||
.baseUrl("https://api.dtf.ru/v1.8/") | ||
.addConverterFactory(GsonConverterFactory.create()) | ||
.client(okHttpClient) | ||
.build() | ||
|
||
private val postApi = retrofit.create(IPostApi::class.java) | ||
|
||
override suspend fun getData(): IPostApi { | ||
return postApi | ||
} | ||
|
||
companion object { | ||
private const val REQUEST_TIMEOUT_SECONDS = 5L | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.example.architecturebase | ||
|
||
import androidx.lifecycle.MutableLiveData | ||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import com.example.architecturebase.network.model.Post | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.launch | ||
|
||
class ViewModelMvvm : MvvmContract, ViewModel() { | ||
|
||
|
||
override val listPosts: MutableLiveData<List<Post>> = MutableLiveData() | ||
|
||
override val errorMessage: MutableLiveData<Throwable> = MutableLiveData() | ||
|
||
override fun getPosts() { | ||
viewModelScope.launch(Dispatchers.IO) { | ||
try { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. в качестве улучшения, можешь попробовать ловить ошибки глобальным обработчиком ошибок |
||
val r = Repository().getData().getPosts() | ||
listPosts.postValue(r.result) | ||
} catch (e: Exception) { | ||
errorMessage.postValue(e) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
По гайдлайнам писать саспенд функции надо таким образом, чтобы они не блокировали вызывающий поток. В Retrofit это реализовано, поэтому переключать на IO нет смысла