Home > Back-end >  RecyclerView isn't showing after doing Minify true
RecyclerView isn't showing after doing Minify true

Time:09-23

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

  • Related