Search code examples
androidkotlin

problem with api using kotlin | data dont show in the app


this's first app for me , i tried to use api from my website into my app , when i open the app it say field to connect and it's dont show any data from website

note that : i use kotlin + android studio last version

i have checked my website and api via Postman and it's work perfect , so i think the problem in my app

here's my full code

AdMobHelper.kt

package com.khm.jobstest

import android.app.Activity
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.MobileAds

object AdMobHelper {
    fun initializeAdMob(activity: Activity) {
        MobileAds.initialize(activity) {}
    }

    fun loadBannerAd(adView: AdView) {
        val adRequest = AdRequest.Builder().build()
        adView.loadAd(adRequest)
    }
}

ApiService.kt

package com.khm.jobstest

import retrofit2.Call
import retrofit2.http.GET

interface ApiService {
    @GET("jobs/") // Use the correct endpoint
    fun getJobs(): Call<List<JobModel>>
}

JobAdapter.kt

package com.khm.jobstest

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide

class JobAdapter(private val jobs: List<JobModel>) :
    RecyclerView.Adapter<JobAdapter.JobViewHolder>() {

    class JobViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val jobImage: ImageView = view.findViewById(R.id.jobImage)
        val jobName: TextView = view.findViewById(R.id.jobName)
        val jobDetails: TextView = view.findViewById(R.id.jobDetails)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JobViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_job, parent, false)
        return JobViewHolder(view)
    }

    override fun onBindViewHolder(holder: JobViewHolder, position: Int) {
        val job = jobs[position]
        holder.jobName.text = job.name
        holder.jobDetails.text = job.app_contect
        Glide.with(holder.itemView.context).load(job.app_image).into(holder.jobImage)
    }

    override fun getItemCount(): Int = jobs.size
}

JobModel.kt

package com.khm.jobstest

data class JobModel(
    val name: String,
    val app_contect: String,
    val app_image: String
)

MainActivity.kt

package com.khm.jobstest

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.MobileAds
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class MainActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var adView: AdView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Initialize RecyclerView
        recyclerView = findViewById(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)

        // Initialize AdMob
        MobileAds.initialize(this) {}
        adView = findViewById(R.id.adView)
        adView.loadAd(AdRequest.Builder().build())

        // Check internet connection
        if (!NetworkUtils.isOnline(this)) {
            Toast.makeText(this, "يجب أن تستخدم الإنترنت للتصفح، حاول لاحقًا.", Toast.LENGTH_LONG).show()
            return
        }

        // Fetch data from API
        val retrofit = Retrofit.Builder()
            .baseUrl("https://trainermods.net/api/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        val apiService = retrofit.create(ApiService::class.java)
        apiService.getJobs().enqueue(object : Callback<List<JobModel>> {
            override fun onResponse(call: Call<List<JobModel>>, response: Response<List<JobModel>>) {
                if (response.isSuccessful && response.body() != null) {
                    recyclerView.adapter = JobAdapter(response.body()!!)
                } else {
                    Toast.makeText(this@MainActivity, "البيانات غير صالحة", Toast.LENGTH_SHORT).show()
                }
            }

            override fun onFailure(call: Call<List<JobModel>>, t: Throwable) {
                Toast.makeText(this@MainActivity, "فشل تحميل البيانات: ${t.message}", Toast.LENGTH_SHORT).show()
            }
        })
    }
}

NetworkUtils.kt

package com.khm.jobstest
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities

object NetworkUtils {
    fun isOnline(context: Context): Boolean {
        val connectivityManager =
            context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val network = connectivityManager.activeNetwork ?: return false
        val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
        return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
    }
}

RetrofitInstance.kt

package com.khm.jobstest

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitInstance {
    private const val BASE_URL = "https://trainermods.net/api/"

    val retrofit: Retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    fun getRetrofitInstance(): Retrofit {
        return retrofit
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- إذن الوصول إلى الإنترنت -->
    <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/Theme.JobTest"
        tools:targetApi="31">

        <!-- إضافة App ID لإعلانات AdMob -->
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-3940256099942544~3347511713"/>

        <!-- تعريف MainActivity مع تحديد android:exported -->
        <activity android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.google.android.gms.ads.AdView
        android:id="@+id/adView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ads:adSize="BANNER"
        ads:adUnitId="ca-app-pub-3940256099942544/6300978111" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

item_job.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="8dp">

    <ImageView
        android:id="@+id/jobImage"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/jobName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="اسم الوظيفة"
        android:textSize="18sp"
        android:textStyle="bold"
        android:paddingTop="8dp" />

    <TextView
        android:id="@+id/jobDetails"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="وصف الوظيفة"
        android:textSize="14sp"
        android:paddingTop="4dp" />
</LinearLayout>

so please any idea, i need help


Solution

  • I think the problem is not in your Kotlin code, but in your API itself

    As I can see your api is not returning pure JSON code. It's returning some html code and below it the Json string. This will make Kotlin code unable to parse the data properly.