When I enabled the Minify, the data is coming from the API but the recyclerview is not showing, And I have never used Proguard, that's why I have no idea, And there is no error in logcat.
ProGuard-rules.pro
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
#-keepattributes *Annotation*
-keep class com.example.mvilaa.ends**{*; }
# Retrofit2
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-keepclassmembernames interface * {
@retrofit2.http.* <methods>;
}
# GSON Annotations
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
Retro Module
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideGsonBuilder(): Gson = GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create()
@Singleton
@Provides
fun provideOkHttpClient() = if (BuildConfig.DEBUG) {
val loggingInterceptor = HttpLoggingInterceptor()
val interceptor = OAuthInterceptor(
"Bearer", AK.apiKey
)
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.addInterceptor(loggingInterceptor)
.build()
} else {
OkHttpClient
.Builder()
.build()
}
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient, gson: Gson): Retrofit = Retrofit.Builder()
.baseUrl(AK.baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
@Provides
@Singleton
fun provideNetworkService(retrofit: Retrofit): Ends = retrofit.create(Ends::class.java)
}
Ends
interface Ends {
@GET("test/feature_slider")
suspend fun getHFS(
@Query("page") page: Int = 1
): Response<EndsResponse>
@GET("test/latest")
suspend fun getRec(
@Query("page") page: Int = 1
): Response<EndsResponse>
}
EndsMeta
@Parcelize
@Keep data class Movie(
val id: Int?,
val title: String?,
val s: String?,
val language: String?,
val tr: String?,
val test: Double?,
val link: List<Links>? = null
) : Parcelable
EndsResponse
@Keep
data class EndsResponse(
// @Expose val page: Int,
val data: List<Movie>
)
handleCommonResponse
fun handleCommonResponse(response: Response<EndsResponse>): NR<EndsResponse> {
when {
response.message().toString().contains("timeout") -> {
return NR.Error(message = "Timeout!!!")
}
response.code() == 402 -> {
return NR.Error(message = "Quota Exceeded!!")
}
response.body()!!.data.isNullOrEmpty() -> {
return NR.Error(message = "Test not found.")
}
response.isSuccessful -> {
val test = response.body()
return NR.Success(test!!)
}
else -> {
return NR.Error(message = response.message())
}
}
}
Resource
sealed class NR<T>(
val data: T? = null,
val message: String? = null
) {
class Success<T>(data: T) : NR<T>(data)
class Error<T>(data: T? = null, message: String?) : NR<T>(data, message)
class Loading<T> : NR<T>()
Rds
class Rds @Inject constructor(
private val ends: Ends
) {
suspend fun getHFS(): Response<EndsResponse> {
return ends.getHFS()
}
}
ViewModel
@HiltViewModel
class HmViewModel @Inject constructor(
private val remote: Rds
) : ViewModel() {
var hfsRes: MutableLiveData<NR<EndsResponse>> =
MutableLiveData()
fun hfs() = viewModelScope.launch {
getHfsSafeCall()
}
private suspend fun getHfsSafeCall() {
hfsRes.value = NR.Loading()
try {
val response = remote.getHFS()
hfsRes.value = handleCommonResponse(response)
} catch (e: Exception) {
hfsRes.value = NR.Error(message = "Test Not Found!!")
}
}
Adapter
class HMAdapter : RecyclerView.Adapter<HMAdapter.MovieViewHolder>() {
private var testList = emptyList<Movie>()
class MovieViewHolder(val binding: ItemMvBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bindData(movie: Movie) {
binding.apply {
Glide.with(itemView)
.asBitmap()
.load(test.poster)
.centerCrop()
.into(ps)
}
}
companion object {
fun from(parent: ViewGroup): MovieViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = ItemMvBinding.inflate(layoutInflater, parent, false)
return MovieViewHolder(binding)
}
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): MovieViewHolder {
return MovieViewHolder.from(parent)
}
override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
val currentMovie = testList[position]
holder.bindData(currentMovie)
holder.itemView.setOnClickListener { mView ->
val direction = LndFragmentDirections.actionLndFragmentToMvDetailFragment(currentMovie)
mView.findNavController().safeNavigate(direction)
}
}
override fun getItemCount(): Int {
return testList.size
}
fun setCommonData(newData: EndsResponse) {
val movieDiffUtil = LndDiffUtil(testList, newData.data)
val diffUtilResult = DiffUtil.calculateDiff(movieDiffUtil)
testList = newData.data
diffUtilResult.dispatchUpdatesTo(this)
}
fun clearList() {
testList = emptyList()
}
}
Fragment
@AndroidEntryPoint
class HmFragment : Fragment(R.layout.hm_fragment), View.OnClickListener {
private var _binding: HmFragmentBinding? = null
private val binding get() = _binding!!
private val hfsAdapter by lazy { HFSAdapter() }
private val recAdapter by lazy { HMAdapter() }
private val viewModel: HmViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = HmFragmentBinding.bind(view)
initFetch()
initAdapters()
}
private fun initAdapters() {
binding.apply {
recyclerViewSlider.apply {
adapter = hfsAdapter
isNestedScrollingEnabled = false
ViewCompat.setNestedScrollingEnabled(recyclerViewSlider, false)
PagerSnapHelper().attachToRecyclerView(this)
}
recyclerRec.apply {
adapter = recdAdapter
isNestedScrollingEnabled = false
ViewCompat.setNestedScrollingEnabled(recyclerViewRec, false)
}
}
}
private fun initFetch() {
viewModel.hfs()
viewModel.hfsRes.observe(viewLifecycleOwner, { response ->
when (response) {
is NR.Success -> {
response.data?.let {
hfsAdapter.setCommonData(it)
}
Toast.makeText(activity, "${response.data}", Toast.LENGTH_SHORT).show()
}
is NR.Error -> {
Toast.makeText(
activity,
"in hfs error" response.message.toString(),
Toast.LENGTH_SHORT
).show()
}
is NR.Loading -> {
}
}
})
}
This is my code, you just tell me that my mistake is happening, because data was fetched from rest api, but viewmodel [ test not found!! ] Error is being thrown.
CodePudding user response:
When we use minify = true then progaurd change your model name & variable in random name like(a.b.d.c.k).
So after getting response our model not recognise which key get value. So we get all time null/empty in our Livedata on ViewModel.
You can write keep class progaurd rules in your progaurd-rules.pro Like this.
-keep class com.example.data.model**{*; } //data class package
if not work then also put this lines.
# Retrofit2
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-keepclassmembernames interface * {
@retrofit2.http.* <methods>;
}
# GSON Annotations
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
Note : Put your all data class (Pojo class) in one package.
If you have any issue Let me Know.
CodePudding user response:
Since you have not posted any logs its tough to comment what went wrong.
Try to include log statement from data to presentation layer to see what's happening.
I would strongly recommend to check below proguard rules for retrofit as well. https://github.com/square/retrofit/blob/master/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro