Hitham
Hitham

Reputation: 33

I'm trying to check internet connectivity but there might be something wrong with my code and I can't figure it out?

So i'm working in this simple android app where I want to check internet connectivity (and based on that I want to either show cached data or just grab the stuff from the API) but it doesn't work as expected and sometimes through this error (java.lang.RuntimeException: Canvas: trying to draw too large(161907360bytes) bitmap. android picasso) i don't know whether it's just an image loading issue or from trying to implement the internet connection Another issue is that it doesn't tell you that it is not connected to the internet unless I try to connect to internet first and then after disconnecting it tells me that there's no internet, I want to check immediately when after the startup And here's the MainActivity code

    package com.example.hema.presentation

import android.content.Intent
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.hema.databinding.ActivityMainBinding
import com.example.hema.domain.model.News
import com.example.hema.presentation.viewmodel.NewsViewModel
import com.example.hema.util.InternetConnection
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity(),RecyclerAdapter.MyViewHolder.OnClickListener {
    @Inject
    lateinit var connectivityManager: com.example.hema.util.ConnectivityManager
    private lateinit var internetConnection: InternetConnection
    lateinit var viewModel: NewsViewModel
    lateinit var recyclerView: RecyclerView
    lateinit var recyclerAdapter: RecyclerAdapter
    private lateinit var binding: ActivityMainBinding
    override fun onStart() {
        super.onStart()
        connectivityManager.registerConnectionObserver(this)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        recyclerView = binding.recyclerView
        recyclerAdapter = RecyclerAdapter(this,this)
        recyclerView.adapter = recyclerAdapter
        recyclerView.setHasFixedSize(true)
        recyclerView.layoutManager = LinearLayoutManager(this)
        viewModel = ViewModelProvider(this).get(NewsViewModel::class.java)
        internetConnection= InternetConnection(this)
        internetConnection.observe(this, { isNetworkAvailable ->
            if (isNetworkAvailable) {
                viewModel.getNews()
                viewModel.newsList.observe(this, {
                    recyclerAdapter.setList(it as MutableList<News>)
                })
            } else {
                Toast.makeText(this, "no internet facka", Toast.LENGTH_SHORT).show()
                Log.d("TAG", "onCreate: no inetrnet ")
            }
        })
    }
    override fun onDestroy() {
        viewModel.onDestroy()
        connectivityManager.unregisterConnectionObserver(this)
        super.onDestroy()
    }

    override fun onItemClicked(news: News) {
        val intent = Intent(this, DetailsActivity::class.java)
        intent.putExtra("news",news)
        startActivity(intent)
    }
}

And the internetConnection class code

package com.example.hema.util
import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkRequest
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.lifecycle.LiveData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

val TAG = "C-Manager"

/**
 * Save all available networks with an internet connection to a set (@validNetworks).
 * As long as the size of the set > 0, this LiveData emits true.
 * MinSdk = 21.
 *
 * Inspired by:
 * https://github.com/AlexSheva-mason/Rick-Morty-Database/blob/master/app/src/main/java/com/shevaalex/android/rickmortydatabase/utils/networking/ConnectionLiveData.kt
 */
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class InternetConnection(context: Context) : LiveData<Boolean>() {
    private lateinit var networkCallback: ConnectivityManager.NetworkCallback
    private val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    private val validNetworks: MutableSet<Network> = HashSet()

    private fun checkValidNetworks() {
        postValue(validNetworks.size > 0)
    }

    override fun onActive() {
        networkCallback = createNetworkCallback()
        val networkRequest = NetworkRequest.Builder()
                .addCapability(NET_CAPABILITY_INTERNET)
                .build()
        cm.registerNetworkCallback(networkRequest, networkCallback)
    }

    override fun onInactive() {
        cm.unregisterNetworkCallback(networkCallback)
    }

    private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {
            /*
              Called when a network is detected. If that network has internet, save it in the Set.
              Source: https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onAvailable(android.net.Network)
             */
            override fun onAvailable(network: Network) {
                Log.d(TAG, "onAvailable: ${network}")
                val networkCapabilities = cm.getNetworkCapabilities(network)
                val hasInternetCapability = networkCapabilities?.hasCapability(NET_CAPABILITY_INTERNET)
                Log.d(TAG, "onAvailable: ${network}, $hasInternetCapability")
                if (hasInternetCapability == true) {
                    // check if this network actually has internet
                    CoroutineScope(Dispatchers.IO).launch {
                        val hasInternet = DoesNetworkHaveInternet.execute(network.socketFactory)
                        if(hasInternet){
                            withContext(Dispatchers.Main){
                                Log.d(TAG, "onAvailable: adding network. ${network}")
                                validNetworks.add(network)
                                checkValidNetworks()
                            }
                        }
                    }
                }
            }

            /*
              If the callback was registered with registerNetworkCallback() it will be called for each network which no longer satisfies the criteria of the callback.
              Source: https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onLost(android.net.Network)
             */
            override fun onLost(network: Network) {
                Log.d(TAG, "onLost: ${network}")
                validNetworks.remove(network)
                checkValidNetworks()
            }

        }
}

And the ConnectivityManager code


    package com.example.hema.util

import android.app.Application
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.LifecycleOwner
import javax.inject.Inject
import javax.inject.Singleton

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
@Singleton
class ConnectivityManager
@Inject
constructor(
    application: Application,
) {
    private val connectionLiveData = InternetConnection(application)

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun registerConnectionObserver(lifecycleOwner: LifecycleOwner){
        connectionLiveData.observe(lifecycleOwner, { isConnected ->
        })
    }

    fun unregisterConnectionObserver(lifecycleOwner: LifecycleOwner){
        connectionLiveData.removeObservers(lifecycleOwner)
    }
}

and also DoesNetworkHaveInternet

 package com.example.hema.util

import android.util.Log
import java.io.IOException
import java.net.InetSocketAddress
import javax.net.SocketFactory

object DoesNetworkHaveInternet {

    // Make sure to execute this on a background thread.
    fun execute(socketFactory: SocketFactory): Boolean {
        return try{
            Log.d(TAG, "PINGING google.")
            val socket = socketFactory.createSocket() ?: throw IOException("Socket is null.")
            socket.connect(InetSocketAddress("8.8.8.8", 53), 1500)
            socket.close()
            Log.d(TAG, "PING success.")
            true
        }catch (e: IOException){
            Log.e(TAG, "No internet connection. ${e}")
            false
        }
    }
}

And finally the project on Github Hema

Upvotes: 0

Views: 344

Answers (0)

Related Questions