I have been following a tutorial on how to get a camera preview on a fragment to show on my app, I am new to kotlin but have been programming in Swift for 2 years. Is there a way to get an image from the preview and show it in another image view.
I created an image view called imageGotCont and this is where I want to place the images I have a button in my main activity so when I press it I need a function that gets an image fromt the preview and places it in the image view.
Below is the fragment.
class FragmentCameraPreview : Fragment() {
private val MAX_DISPLAY_WIDTH = 1280
private val MAX_DISPLAY_HEIGHT = 720
private lateinit var captureSession: CameraCaptureSession
private lateinit var captureRequestBuilder: CaptureRequest.Builder
private lateinit var imageSize: Size
private lateinit var cameraDevice: CameraDevice
private val deviceStateCallback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice?) {
Log.d(TAG, "camera device opened")
if (camera != null) {
cameraDevice = camera
previewSession()
}
}
override fun onDisconnected(camera: CameraDevice?) {
Log.d(TAG, "camera device disconnected")
camera?.close()
}
override fun onError(camera: CameraDevice?, error: Int) {
Log.d(TAG, "camera device error")
this#FragmentCameraPreview.activity?.finish()
}
}
private lateinit var backgroundThread: HandlerThread
private lateinit var backgroundHandler: Handler
private val cameraManager by lazy {
activity?.getSystemService(Context.CAMERA_SERVICE) as CameraManager
}
companion object {
private val TAG = FragmentCameraPreview::class.qualifiedName
const val REQUEST_CAMERA_PERMISSION = 100
#JvmStatic
fun newInstance() = FragmentCameraPreview()
}
private val surfaceListner = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) = Unit
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean = true
override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
Log.d(TAG, "Tony texture surface width: $width height: $height")
openCamera()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
#AfterPermissionGranted(REQUEST_CAMERA_PERMISSION)
private fun checkCameraPermission() {
if (EasyPermissions.hasPermissions(activity!!, android.Manifest.permission.CAMERA)) {
Log.d(TAG, "APP has camera permission")
connectCamera()
} else {
EasyPermissions.requestPermissions(
activity!!,
getString(R.string.camera_request_rationale),
REQUEST_CAMERA_PERMISSION,
android.Manifest.permission.CAMERA
)
}
}
override fun onResume() {
super.onResume()
startBackgroundThread()
if (previewTextureView.isAvailable)
openCamera()
else
previewTextureView.surfaceTextureListener = surfaceListner
}
override fun onPause() {
closeCamera()
stopBackgroundThread()
super.onPause()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val myInflatedView = inflater.inflate(R.layout.fragment_camera_preview, container, false)
return myInflatedView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}
private fun openCamera() {
checkCameraPermission()
}
private fun <T> cameraCharacteristics(cameraId: String, key: CameraCharacteristics.Key<T>): T {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
return when (key) {
CameraCharacteristics.LENS_FACING -> characteristics.get(key)
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP -> characteristics.get(key)
else -> throw IllegalArgumentException("Key not recognized")
}
}
private fun cameraId(lens: Int): String {
var deviceId = listOf<String>()
try {
val cameraIdList = cameraManager.cameraIdList
deviceId = cameraIdList.filter { lens == cameraCharacteristics(it, CameraCharacteristics.LENS_FACING) }
} catch (e: CameraAccessException) {
Log.e(TAG, e.toString())
}
return deviceId[0]
}
private fun connectCamera() {
val deviceID = cameraId(CameraCharacteristics.LENS_FACING_BACK)
Log.d(TAG, "deviceID: $deviceID")
try {
cameraManager.openCamera(deviceID, deviceStateCallback, backgroundHandler)
} catch (e: CameraAccessException) {
Log.e(TAG, e.toString())
} catch (e: InterruptedException) {
Log.e(TAG, "Open camera device interrupted while opening")
}
}
private fun startBackgroundThread() {
backgroundThread = HandlerThread("CameraKotlin").also { it.start() }
backgroundHandler = Handler(backgroundThread.looper)
}
private fun stopBackgroundThread() {
backgroundThread.quitSafely()
try {
backgroundThread.join()
} catch (e: InterruptedException) {
Log.e(TAG, e.toString())
}
}
private fun previewSession() {
val surfaceTexture = previewTextureView.surfaceTexture
surfaceTexture.setDefaultBufferSize(MAX_DISPLAY_WIDTH, MAX_DISPLAY_HEIGHT)
val surface = Surface(surfaceTexture)
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
captureRequestBuilder.addTarget(surface)
cameraDevice.createCaptureSession(
Arrays.asList(surface),
object : CameraCaptureSession.StateCallback() {
override fun onConfigureFailed(session: CameraCaptureSession?) {
Log.e(TAG, "creating capture session failed")
}
override fun onConfigured(session: CameraCaptureSession?) {
if (session != null) {
captureSession = session
captureRequestBuilder.set(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
)
captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null)
}
}
}, null
)
}
private fun closeCamera() {
if (this::captureSession.isInitialized)
captureSession.close()
if (this::cameraDevice.isInitialized)
cameraDevice.close()
}
}
Related
class ScanScopeFragment : Fragment() {
private val TAG: String = "ScanScopeFragment"
private lateinit var binding: FragmentScanScopeBinding
private lateinit var mainContext: Context
private lateinit var mainActivity: Activity
private lateinit var surfaceView: SurfaceView
private val REQUEST_CAMERA_PERMISSION = 201
//private val requestCodeCameraPermission = 1001
private lateinit var cameraSource: CameraSource
private lateinit var barcodeDetector: BarcodeDetector
private lateinit var barcodeText: TextView
private var scannedValue = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentScanScopeBinding.inflate(inflater, container, false)
mainContext = requireContext()
mainActivity = requireActivity()
surfaceView = binding.cameraSurfaceView
barcodeText = binding.barcodeText
initialiseDetectorsAndSources()
return binding.root
}
private fun initialiseDetectorsAndSources() {
//Toast.makeText(getApplicationContext(), "Barcode scanner started", Toast.LENGTH_SHORT).show();
barcodeDetector = BarcodeDetector.Builder(mainContext)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build()
cameraSource = CameraSource.Builder(mainContext, barcodeDetector)
.setRequestedPreviewSize(1920, 1080)
.setAutoFocusEnabled(true) //you should add this feature
.build()
surfaceView.getHolder().addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
try {
if (ActivityCompat.checkSelfPermission(
mainContext,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
) {
cameraSource.start(surfaceView.getHolder())
} else {
ActivityCompat.requestPermissions(
mainActivity,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_PERMISSION
)
}
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
cameraSource.stop()
}
})
barcodeDetector.setProcessor(object : Detector.Processor<Barcode> {
override fun release() {
// Toast.makeText(getApplicationContext(), "To prevent memory leaks barcode scanner has been stopped", Toast.LENGTH_SHORT).show();
}
override fun receiveDetections(detections: Detector.Detections<Barcode>) {
val barcodes = detections.detectedItems
if (barcodes.size() != 0) {
barcodeText.post(Runnable {
scannedValue = barcodes.valueAt(0).displayValue
barcodeText.setText(scannedValue)
})
}
}
})
}
/*
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CAMERA_PERMISSION && grantResults.isNotEmpty()) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initialiseDetectorsAndSources()
} else {
// Toast.makeText(applicationContext, "Permission Denied", Toast.LENGTH_SHORT).show()
}
}
}
*/
override fun onPause() {
super.onPause()
cameraSource.release()
}
override fun onResume() {
super.onResume()
initialiseDetectorsAndSources()
}
}
I am hoping once the permission is given the camera will open on the surfaceView
I am working on a kotlin application that contains fragments. I am converting an app I created using activity to fragments but I am having an issue. I get an error when running the app that the property fragmentHomeBinding has not been initialized and the app closes.
Here's the fragment Home.kt
class Home : Fragment() {
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private lateinit var fragmentHomeBinding: FragmentHomeBinding
#SuppressLint("WrongViewCast")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
getCurrentLocation()
fragmentHomeBinding.etGetCityName.setOnEditorActionListener { v, actionId, keyEvent ->
if(actionId == EditorInfo.IME_ACTION_SEARCH)
{
getCityWeather(fragmentHomeBinding.etGetCityName.text.toString())
val view = activity?.currentFocus
if(view!=null)
{
val imm:InputMethodManager=
activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
fragmentHomeBinding.etGetCityName.clearFocus()
}
true
}
else false
}
}
private fun getCityWeather(cityName:String)
{
fragmentHomeBinding.pbLoading.visibility = View.VISIBLE
ApiUtilities.getApiInterface()?.getCityWeatherData(cityName, API_KEY)?.enqueue(
object:Callback<ModelClass>{
override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
setDataOnViews((response.body()))
}
override fun onFailure(call: Call<ModelClass>, t: Throwable) {
Toast.makeText(activity?.applicationContext, "Wrong City", Toast.LENGTH_SHORT).show()
}
})
}
private fun getCurrentLocation()
{
if(checkPermission())
{
if(isLocationEnabled())
{
if(ActivityCompat.checkSelfPermission(
requireActivity(), android.Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireActivity(),
android.Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
){
requestPermission()
return
}
fusedLocationProviderClient.lastLocation.addOnCompleteListener(requireActivity()){ task->
val location: Location?=task.result
if(location==null)
{
fetchCurrentLocationWeather(23.76137119142536.toString(), 90.35059989467042.toString())
}
else
{
fetchCurrentLocationWeather(location.latitude.toString(),location.longitude.toString())
}
}
}
else
{
Toast.makeText(activity?.applicationContext, "Turn on Location", Toast.LENGTH_SHORT).show()
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(intent)
}
}
}
private fun fetchCurrentLocationWeather(latitude: String, longitude:String)
{
fragmentHomeBinding.pbLoading.visibility = View.VISIBLE
ApiUtilities.getApiInterface()?.getCurrentWeatherData(latitude, longitude, API_KEY)?.enqueue(
object : Callback<ModelClass> {
override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
if(response.isSuccessful)
{
setDataOnViews(response.body())
}
}
override fun onFailure(call: Call<ModelClass>, t: Throwable) {
Toast.makeText(activity?.applicationContext, "ERROR", Toast.LENGTH_SHORT).show()
}
})
}
private fun setDataOnViews(body: ModelClass?) {
val sdf = SimpleDateFormat("dd/MM/yyyy hh:mm")
val currentDate = sdf.format(Date())
fragmentHomeBinding.tvDateTime.text = currentDate
fragmentHomeBinding.tvDayMaxTemp.text = ""+kelvinToCelsius(body!!.main.temp_max) + "°"
fragmentHomeBinding.tvDayMinTemp.text = ""+kelvinToCelsius(body!!.main.temp_min) + "°"
fragmentHomeBinding.tvTemp.text = ""+kelvinToCelsius(body!!.main.temp)
fragmentHomeBinding.tvFeelsLike.text = "Feels like: "+kelvinToCelsius(body!!.main.feels_like) + "°"
fragmentHomeBinding.tvWeatherType.text = body.weather[0].main
fragmentHomeBinding.tvPressure.text = body.main.pressure.toString()
fragmentHomeBinding.tvHumidity.text = body.main.humidity.toString() + " %"
fragmentHomeBinding.tvWindSpeed.text = body.wind.speed.toString() + " m/s"
fragmentHomeBinding.tvCityName.text = body.name
updateUI(body.weather[0].id)
}
private fun updateUI(id: Int) {
fragmentHomeBinding.pbLoading.visibility = View.GONE
fragmentHomeBinding.mainLayout.visibility = View.VISIBLE
}
private fun kelvinToCelsius(temp: Double): Double
{
var intTemp = temp
intTemp = intTemp.minus(273)
return intTemp.toBigDecimal().setScale(1, RoundingMode.UP).toDouble()
}
companion object
{
const val PERMISSION_REQUEST_ACCESS_LOCATION = 100
const val API_KEY = "3c709ccaf2730aa1c263925f75db631a"
}
private fun isLocationEnabled():Boolean{
val locationManager:LocationManager=activity?.getSystemService(Context.LOCATION_SERVICE) as LocationManager
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
LocationManager.NETWORK_PROVIDER
)
}
private fun requestPermission(){
ActivityCompat.requestPermissions(
requireActivity(), arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_REQUEST_ACCESS_LOCATION
)
}
private fun checkPermission():Boolean{
if(ActivityCompat.checkSelfPermission(requireActivity(),
android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(requireActivity(),
android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
{
return true
}
return false
}
#Suppress("DEPRECATION")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode== PERMISSION_REQUEST_ACCESS_LOCATION)
{
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(activity?.applicationContext, "Granted", Toast.LENGTH_SHORT).show()
getCurrentLocation()
}
else{
Toast.makeText(activity?.applicationContext, "Denied", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
fragmentHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
// Inflate the layout for this fragment
return fragmentHomeBinding.root
}
}
Here's the error that shows up on logcat:
2022-05-20 17:45:20.582 22026-22048/com.example.weather D/EGL_emulation: app_time_stats: avg=30.74ms min=18.05ms max=34.54ms count=33
2022-05-20 17:45:21.416 22026-22026/com.example.weather D/AndroidRuntime: Shutting down VM
2022-05-20 17:45:21.417 22026-22026/com.example.weather E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.weather, PID: 22026
kotlin.UninitializedPropertyAccessException: lateinit property fragmentHomeBinding has not been initialized
at com.example.weather.Home.onCreate(Home.kt:58)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2949)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1455)
at android.app.Activity.performStart(Activity.java:8076)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3660)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
2022-05-20 17:45:21.435 22026-22026/com.example.weather I/Process: Sending signal. PID: 22026 SIG: 9
Help's appreciated, thanks.
Your Fragment viewbinding instance fragmentHomeBinding is initialised at onCreateView() life cycle method. But you are accessing at onCreate() lifecycle method. In Fragment lifecycle, onCreate() will be called before onCreatedView().
As a result you are accessing an object which is not initialised.
To resolve the issue, move your viewbinding reference code in onCreate() to onCreateView() as below.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
fragmentHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
fragmentHomeBinding.etGetCityName.setOnEditorActionListener { v, actionId, keyEvent ->
if(actionId == EditorInfo.IME_ACTION_SEARCH)
{
getCityWeather(fragmentHomeBinding.etGetCityName.text.toString())
val view = activity?.currentFocus
if(view!=null)
{
val imm:InputMethodManager=
activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
fragmentHomeBinding.etGetCityName.clearFocus()
}
true
}
else false
}
// Inflate the layout for this fragment
return fragmentHomeBinding.root
}
Like title I can't get correct item data, now imagine I have 2 recycler view list on my main fragment, one recycler view is vertical, other horizontal. If I use only one recycler everything is working fine. But when I add other one it's opening items randomly, but that random data openings only random both recyclers positions. Like my first recycler have [a,b,c,d] , other recycler have [e,f,g,h]. When I click first item of first recycler its go to other fragment which shows detail, its opening e instead of a, if I go back and retry it, its opening e again, retry and its a !! so its opening randomly, why this is happening why can't I open correct data? I put Log.d on my adapters and when I click recycler items, adapters log says u clicked "a" but my detail fragment shows me data of "e". What I am doing wrong? Here is my codes:(I have lots of codes so I share what we need)
my databases TvDAO:
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import com.bt.filmdenemesi.model.Result
#Dao
interface TVDAO {
//Veri erişim nesnesi
#Insert
suspend fun insertAll(vararg movie: Result) : List<Long>
#Query("SELECT * FROM Result")
suspend fun getAllTV() : List<Result>
#Query("SELECT * FROM Result WHERE uuid2=:diziId")
suspend fun getTV(diziId:Int) : Result
#Query("DELETE FROM Result")
suspend fun deleteAllTV(
)
}
Tv Database:
#Database(entities = arrayOf(Result::class), version = 1)
abstract class TvDatabase: RoomDatabase() {
abstract fun tvDao(): TVDAO
companion object{
#Volatile
private var INSTANCE: TvDatabase?=null
fun databaseOlustur2(context: Context): TvDatabase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(context.applicationContext,TvDatabase::class.java, "tvdatabase").fallbackToDestructiveMigration().build()
INSTANCE=instance
instance
}
}
}
}
movie Dao:
#Dao
interface MovieDAO {
//Veri erişim nesnesi
#Insert
suspend fun insertAll(vararg movie: Movie) : List<Long>
#Query("SELECT * FROM Movie")
suspend fun getAllMovie() : List<Movie>
#Query("Select * from Movie where uuid=:movieId")
suspend fun getMovie(movieId:Int) : Movie
#Query("Delete from Movie")
suspend fun deleteAllMovie(
)
}
movie database:
#Database(entities = arrayOf(Movie::class ), version = 1)
abstract class MovieDatabase:RoomDatabase() {
abstract fun movieDao(): MovieDAO
//singleton
companion object{
#Volatile private var instance: MovieDatabase? = null
private val lock = Any()
operator fun invoke(context: Context) = instance ?: synchronized(lock){
instance?: databaseOlustur(context).also {
instance = it
}
}
private fun databaseOlustur(context: Context)= Room.databaseBuilder(
context.applicationContext,
MovieDatabase::class.java,"moviedatabase").build()
}
}
my adapters:
class vizyonrecycleradapter(val diziListesi: ArrayList<Result>):RecyclerView.Adapter<vizyonrecycleradapter.DiziViewHolder>() {
class DiziViewHolder(itemview: View) : RecyclerView.ViewHolder(itemview)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DiziViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.now_playing_recycler_row, parent, false)
return DiziViewHolder(view)
}
override fun onBindViewHolder(holder: DiziViewHolder, konum: Int) {
holder.itemView.tv_ismi.text=diziListesi.get(konum).name
val fotoDenemeleri = "https://image.tmdb.org/t/p/w500"
val fotobirlestirme: String = "${fotoDenemeleri}"+ diziListesi.get(konum).posterPath
holder.itemView.vizyon.gorselIndir(fotobirlestirme, placeHolderYap(holder.itemView.context))
holder.itemView.setOnClickListener {
val action2 = AnaSayfaDirections.actionAnaSayfaToDetaySayfasi(diziListesi[konum].uuid2)
Log.d("movie-title","${diziListesi.get(konum).originalName}")
Navigation.findNavController(it).navigate(action2)
}
}
override fun getItemCount(): Int {
return diziListesi.size
}
fun diziListesiniGuncelle(yeniDiziListesi: List<Result>) {
diziListesi.clear()
diziListesi.addAll(yeniDiziListesi)
notifyDataSetChanged()
}
}
other adapter:
class MovieRecyclerAdapter(val movieListesi: ArrayList<Movie>):RecyclerView.Adapter<MovieRecyclerAdapter.MovieViewHolder>() {
class MovieViewHolder(itemview: View) :RecyclerView.ViewHolder(itemview)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.movie_recycler_row,parent,false)
return MovieViewHolder(view)
}
override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
holder.itemView.movieId.text= movieListesi.get(position).title
val fotoDenemeleri = "https://image.tmdb.org/t/p/w500"
val fotobirlestirme: String = "${fotoDenemeleri}"+movieListesi.get(position).backdropPath
holder.itemView.ana_foto.gorselIndir(fotobirlestirme, placeHolderYap(holder.itemView.context))
holder.itemView.setOnClickListener {
val action = AnaSayfaDirections.actionAnaSayfaToDetaySayfasi(movieListesi.get(position).uuid)
Log.d("movie-title","${movieListesi.get(position).title}")
Navigation.findNavController(it).navigate(action)
}
}
override fun getItemCount(): Int {
return movieListesi.size
}
fun movieListesiniGuncelle(yeniMovieListesi: List<Movie>){
movieListesi.clear()
movieListesi.addAll(yeniMovieListesi)
notifyDataSetChanged()
}
}
my base ViewModel:
open class BaseViewModel(application: Application) : AndroidViewModel(application),CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
detail ViewModel:
class MovieDetayiViewModel(application: Application): BaseViewModel(application) {
val diziLiveData = MutableLiveData<Result>()
val movieLiveData = MutableLiveData<Movie>()
val aramaLiveData = MutableLiveData<ResultX>()
fun roomVerisiniAl2(uuid2: Int){
launch {
val dao2=TvDatabase.databaseOlustur2(getApplication()).tvDao().getTV(uuid2)
//val dizi = dao.getTV(uuid2)
diziLiveData.value=dao2
}
}
fun roomVerisiniAl(uuid: Int){
launch {
val dao= MovieDatabase(getApplication()).movieDao().getMovie(uuid)
// val film = dao.getMovie(uuid)
movieLiveData.value=dao
}
}
fun roomVerisiniAl3(uuid3: Int){
launch {
val dao= AramaDatabase(getApplication()).aramaDao()
val arama = dao.getMovie(uuid3)
aramaLiveData.value=arama
}
}
}
movielistviewmvdel:
class MovieListesiViewModel(application: Application): BaseViewModel(application){
val filmler = MutableLiveData<List<Movie>>()
val dizi = MutableLiveData<List<Result>>()
val arama = MutableLiveData<List<ResultX>>()
val filmHataMesaji = MutableLiveData<Boolean>()
val filmYukleniyor = MutableLiveData<Boolean>()
private var guncellemeZamani = 1 * 60 * 1000 * 1000 * 1000L
private val filmApiServis = FilmAPIServis()
private val disposable = CompositeDisposable()
private val disposable2 = CompositeDisposable()
private val disposable3 = CompositeDisposable()//kullan at
private val ozelSharedPrefences = OzelSharedPrefences(getApplication())
fun refreshData(){
val kaydedilmeZamani = ozelSharedPrefences.zamaniAl()
if(kaydedilmeZamani != null && kaydedilmeZamani !=0L && System.nanoTime()-kaydedilmeZamani < guncellemeZamani){
verileriSQLitedenAl()
}else{
verileriInternettenAl()
}
}
fun refreshFromInternet(){
verileriInternettenAl()
}
private fun verileriSQLitedenAl(){
filmYukleniyor.value = true
launch {
val movieListesi = MovieDatabase(getApplication()).movieDao().getAllMovie()
movieleriGoster(movieListesi)
val diziListesi = TvDatabase.databaseOlustur2(getApplication()).tvDao().getAllTV()
tvleriGoster(diziListesi)
}
launch {
val aramaListesi = AramaDatabase(getApplication()).aramaDao().getAllMovie()
aramalariGoster(aramaListesi)
}
}
private fun verileriInternettenAl(){
filmYukleniyor.value = true
disposable.add(
filmApiServis.getData()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<GetMoviesResponse>(){
override fun onSuccess(t: GetMoviesResponse) {
filmler.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
sqliteSakla(t.results)
// Toast.makeText(getApplication(),"Filmler internetten yüklendi",Toast.LENGTH_LONG).show()
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
disposable2.add(
filmApiServis.getVizyondakiler()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<NowPlaying>(){
override fun onSuccess(t: NowPlaying) {
dizi.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
diziSqLiteSakla(t.results)
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
}
fun aramayiInternettenAl(denemeText:String){
disposable3.add(
filmApiServis.getArama(denemeText)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<search>(){
override fun onSuccess(t: search) {
arama.value= t.results
aramaSqliteSakla(t.results)
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
})
)
}
private fun movieleriGoster(filmlerListesi : List<Movie>?){
filmler.value= filmlerListesi
filmHataMesaji.value=false
filmYukleniyor.value=false
}
private fun tvleriGoster(tvListesi: List<Result>?){
dizi.value= tvListesi
filmHataMesaji.value=false
filmYukleniyor.value=false
}
private fun aramalariGoster(aramaListesi: List<ResultX>){
arama.value= aramaListesi
}
private fun sqliteSakla(filmListesi : List<Movie>){
launch {
val dao = MovieDatabase(getApplication()).movieDao()//dao içerisindeki fonksiyonlara ulaşmak için
dao.deleteAllMovie()
val uuidListesi = dao.insertAll(*filmListesi.toTypedArray())//tek tek movie haline getirmek için typed array. (*) koymak lazım
var i = 0
while (i < filmListesi.size){
filmListesi[i].uuid = uuidListesi[i].toInt()//uuid ye ulaştık modemdeki idleri eşledik
i = i + 1
}
movieleriGoster(filmListesi)
}
ozelSharedPrefences.zamaniKaydet(System.nanoTime())
}
private fun diziSqLiteSakla(diziListesi : List<Result>){
launch {
val dao2 = TvDatabase.databaseOlustur2(getApplication()).tvDao()//dao içerisindeki fonksiyonlara ulaşmak için
dao2.deleteAllTV()
val uuidListesi2 = dao2.insertAll(*diziListesi.toTypedArray())//tek tek movie haline getirmek için typed array. (*) koymak lazım
var i = 0
while (i < diziListesi.size){
diziListesi[i].uuid2 = uuidListesi2[i].toInt()//uuid ye ulaştık modemdeki idleri eşledik
i = i + 1
}
tvleriGoster(diziListesi)
}
ozelSharedPrefences.zamaniKaydet(System.nanoTime())
}
private fun aramaSqliteSakla(aramaListesi : List<ResultX>){
launch {
val dao = AramaDatabase(getApplication()).aramaDao()//dao içerisindeki fonksiyonlara ulaşmak için
dao.deleteAllMovie()
val uuidListesi3 = dao.insertAll(*aramaListesi.toTypedArray())//tek tek movie haline getirmek için typed array. (*) koymak lazım
var i = 0
while (i < aramaListesi.size){
aramaListesi[i].uuid3 = uuidListesi3[i].toInt()//uuid ye ulaştık modemdeki idleri eşledik
i = i + 1
}
arama.value?.let { aramalariGoster(it) }
}
ozelSharedPrefences.zamaniKaydet(System.nanoTime())
}
}
and this is my detail page fragment codes:
class DetaySayfasi : Fragment() {
private lateinit var viewModel : MovieDetayiViewModel
private lateinit var viewModel2: MovieListesiViewModel
var movieId : Int = 0
var getId : String =""
var listeIdAlma : Int = 0
private val ozelSharedPrefences2 = OzelSharedPrefences()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detay_sayfa, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel2 = ViewModelProviders.of(this).get(MovieListesiViewModel::class.java)
viewModel2.refreshData()
arguments?.let {
movieId = DetaySayfasiArgs.fromBundle(it).movieID
}
viewModel = ViewModelProviders.of(this).get(MovieDetayiViewModel::class.java)
viewModel.roomVerisiniAl(movieId)
observeLiveData2()
viewModel.roomVerisiniAl2(movieId)
observeLiveData()
viewModel.roomVerisiniAl3(movieId)
dislike.setOnClickListener {
like()
}
like.setOnClickListener {
dislike()
}
observeLiveData3()
geri()
uygulamaPaylas()
}
fun observeLiveData(){
viewModel.movieLiveData.observe(viewLifecycleOwner, Observer { movie->
movie?.let {
getId = "movie/"+"${it.id}"
listeIdAlma= it.id
movie_title.text=it.title
movie_overview.text= it.overview
movie_rating_text.text=it.voteAverage.toFloat().toString()
movie_rating.rating = it.voteAverage.toFloat()/2
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${movie.backdropPath}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${movie.posterPath}", placeHolderYap(it))
}
if (!(listeIdAlma in ozelSharedPrefences2.korku())){
Log.d("ozelshared","${ozelSharedPrefences2.korku()}")
Log.d("listetaramaid","${listeIdAlma}")
like.visibility=View.GONE
dislike.visibility=View.VISIBLE
}else{
like.visibility=View.VISIBLE
dislike.visibility=View.GONE
Log.d("else","like kapalı olması lazım")
}
}
})
}
fun observeLiveData2(){
viewModel.diziLiveData.observe(viewLifecycleOwner, Observer { tv->
tv?.let {
getId = "tv/"+"${it.id}"
listeIdAlma = it.id
movie_title.text=it.name
movie_overview.text= it.overview
movie_rating_text.text= it.voteAverage?.toFloat().toString()
movie_rating.rating = it.voteAverage!!.toFloat()/2
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.backdropPath}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.posterPath}", placeHolderYap(it))
}
if (!(listeIdAlma in ozelSharedPrefences2.korku())){
Log.d("ozelshared","${ozelSharedPrefences2.korku()}")
Log.d("listetaramaid","${listeIdAlma}")
like.visibility=View.GONE
dislike.visibility=View.VISIBLE
}else{
like.visibility=View.VISIBLE
dislike.visibility=View.GONE
Log.d("else","like kapalı olması lazım")
}
}
})
}
fun observeLiveData3(){
viewModel.aramaLiveData.observe(viewLifecycleOwner, Observer { tv->
tv?.let {
if (it.voteAverage!=null){
getId = "tv/"+"${it.id}"
listeIdAlma = it.id!!
movie_title.text=it.name
movie_overview.text= it.overview
movie_rating_text.text= it.voteAverage?.toFloat().toString()
movie_rating.rating = it.voteAverage?.toFloat()!!/2
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.backdropPath}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.posterPath}", placeHolderYap(it))
}
}else{
getId = "tv/"+"${it.id}"
listeIdAlma = it.id!!
movie_title.text=it.name
movie_overview.text= it.name
movie_rating_text.text= ""
movie_rating.rating = 10F
context?.let {
movie_backdrop.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.profile_path}", placeHolderYap(it))
movie_poster.gorselIndir("https://image.tmdb.org/t/p/w500"+"${tv.profile_path}", placeHolderYap(it))
}
}
if (!(listeIdAlma in ozelSharedPrefences2.korku())){
Log.d("ozelshared","${ozelSharedPrefences2.korku()}")
Log.d("listetaramaid","${listeIdAlma}")
like.visibility=View.GONE
dislike.visibility=View.VISIBLE
}else{
like.visibility=View.VISIBLE
dislike.visibility=View.GONE
Log.d("else","like kapalı olması lazım")
}
}
})
}
Like I said if I delete my one of recycler view its working perfect but if I use two recycler on same fragment I got wrong datas. Logs says I open correct data but it's not.
If u need my other codes to solve problem say it please I have lots of screens don't know which one I need to share to solve it.
i solved my problem but i don't know what i changed on background
i just seperate my one function to two function in MovieListesiViewmodel and gave a parameter and its worked like a miracle
private fun verileriInternettenAl(denemeInt: Int){
filmYukleniyor.value = true
disposable.add(
filmApiServis.getData(denemeInt)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<GetMoviesResponse>(){
override fun onSuccess(t: GetMoviesResponse) {
filmler.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
sqliteSakla(t.results)
// Toast.makeText(getApplication(),"Filmler internetten yüklendi",Toast.LENGTH_LONG).show()
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
}
fun verileriInternettenAl2(){
disposable2.add(
filmApiServis.getVizyondakiler()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object: DisposableSingleObserver<NowPlaying>(){
override fun onSuccess(t: NowPlaying) {
dizi.value= t.results
filmHataMesaji.value=false
filmYukleniyor.value=false
diziSqLiteSakla(t.results)
}
override fun onError(e: Throwable) {
filmHataMesaji.value=true
filmYukleniyor.value=false
e.printStackTrace()
}
})
)
}
I have seen many questions like this but they are not the same as my situation and I couldn't use those solutions.
I have a fragment (OrdersByStatusFragment.kt) and the method I want to call from the adapter is getOrderStatusList()
class OrdersByStatusFragment : BaseFragment() {
private lateinit var binding: OrderStatusLayoutBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_orders_by_status, container, false)
}
override fun onResume() {
super.onResume()
getOrderStatusList()
}
fun getOrderStatusList() {
showProgressDialog(resources.getString(R.string.please_wait))
FirestoreClass().getOrderStatusList(this#OrdersByStatusFragment)
}
fun successOrderStatusList(orderStatusList: ArrayList<OrderStatus>) {
hideProgressDialog()
if (orderStatusList.size > 0) {
rv_order_by_status.visibility = View.VISIBLE
tv_no_orders_by_status_found.visibility = View.GONE
rv_order_by_status.layoutManager = LinearLayoutManager(activity)
rv_order_by_status.setHasFixedSize(true)
val orderStatusListAdapter =
OrderStatusListAdapter(requireActivity(), orderStatusList)
rv_order_by_status.adapter = orderStatusListAdapter
} else {
rv_order_by_status.visibility = View.GONE
tv_no_orders_by_status_found.visibility = View.VISIBLE
}
}
fun successNewOrderStatus() {
Toast.makeText(requireContext(), "Success", Toast.LENGTH_SHORT).show()
}
}
Adapter OrderStatusListAdapter.kt
open class OrderStatusListAdapter(
private val context: Context,
private var list: ArrayList<OrderStatus>,
) : RecyclerView.Adapter<OrderStatusListAdapter.MyViewHolder>() {
class MyViewHolder(var binding: OrderStatusLayoutBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
OrderStatusLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val model = list[position]
if (true) {
GlideLoader(context).loadProductPicture(
model.image,
holder.itemView.iv_order_status_item_image
)
val dateFormat = "dd MMM yyyy HH:mm"
val formatter = SimpleDateFormat(dateFormat, Locale.getDefault())
val calendar: Calendar = Calendar.getInstance()
calendar.timeInMillis = model.order_datetime
val orderDateTime = formatter.format(calendar.time)
holder.itemView.tv_order_status_order_date.text = orderDateTime
holder.itemView.tv_order_status_item_name.text = model.items[0].title
holder.itemView.tv_order_status_item_price.text = "$${model.total_amount}"
holder.itemView.tv_order_status.text = model.order_status
holder.itemView.tv_order_status_order_id.text = model.id
holder.binding.spnOrderChangeStatus.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
holder.binding.tvSpinnerValue.text =
parent?.getItemAtPosition(position).toString()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
holder.binding.btnOrderStatusChangeStatus.setOnClickListener {
Toast.makeText(context, "Button Clicked", Toast.LENGTH_SHORT).show()
FirestoreClass().updateOrderStatus(
model.id,
holder.binding.tvSpinnerValue.text.toString()
)
Toast.makeText(context, "DB Updated", Toast.LENGTH_SHORT).show()
}
holder.itemView.ib_order_status_delete_product.visibility = View.GONE
holder.itemView.setOnClickListener {
val intent = Intent(context, SoldProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_SOLD_PRODUCT_DETAILS, model)
context.startActivity(intent)
}
}
}
}
As you can see the fun getOrderStatusList() in the OrdersByStatusFragment.kt is actually calling a method in the FirestoreClass.kt. Following is the getOrderStatusList() in the FirestoreClass.kt
fun getOrderStatusList(fragment: OrdersByStatusFragment) {
mFireStore.collection(Constants.ORDERS)
.whereIn("order_status", listOf("Pending", "In process"))
.get()
.addOnSuccessListener { document ->
val list: ArrayList<OrderStatus> = ArrayList()
for (i in document.documents) {
val orderStatus = i.toObject(OrderStatus::class.java)!!
orderStatus.id = i.id
list.add(orderStatus)
}
fragment.successOrderStatusList(list)
}
.addOnFailureListener {
fragment.hideProgressDialog()
}
}
The way I solved something like this is to pass a reference to the method into the adapter's constructor, then you can call the method in the adapter.
See kotlin-how-to-pass-a-function-as-parameter-to-another
In general, the link shows a class containing a method called buz.
Let's say your adapter has a constructor like:
class MyAdapter (private val context: Context, val buzz: () -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
then you can create the adapter like
MyAdapter(applicationContext, ::buz)
In the adapter the method can be called normally:
buzz()
I want to receive all avaiable wifi to a ResultList using broadcastReceiver override method onReceive(). Don't know why I cannot go into my override method ( Can't catch breakpoint at println("On receive active") )
After that I checked resultList by "If" statement but it occures that resultList is empty.
What am I doing wrong ?
My code below :
class AddNewDeviceFragment : Fragment() {
var resultList = ArrayList<ScanResult>()
private var adapter: NewDeviceAdapter = NewDeviceAdapter(arrayListOf())
private lateinit var model: NewDeviceViewModel
private lateinit var rootView: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
rootView = inflater.inflate(R.layout.fragment_addnewdevice, container, false)
return rootView
}
override fun onStart() {
super.onStart()
var newDevicesRecycledView = rootView.findViewById(R.id.newDevicesRecycledView) as RecyclerView
newDevicesRecycledView.layoutManager = LinearLayoutManager(activity)
newDevicesRecycledView.adapter = adapter
//ViewModel
model = ViewModelProviders.of(this).get(NewDeviceViewModel::class.java)
//LiveData
model.getNewDevices()
.observe(viewLifecycleOwner, Observer<MutableList<NewDevice>> { newDevices ->
adapter.addDevice(newDevices)
})
refreshButton.setOnClickListener { startScan() }
}
fun startScan() {
model.clearAllData()
val wifiManager = context?.getSystemService(Context.WIFI_SERVICE) as WifiManager
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
resultList = wifiManager.scanResults as ArrayList<ScanResult>
println("On receive active")
for (result in resultList) {
model.addNewDevice(NewDevice(result.SSID.toString()))
}
}
}
if (!wifiManager.isWifiEnabled) {
Toast.makeText(activity, "Wifi is disable... We need to enable it", Toast.LENGTH_LONG).show()
wifiManager.setWifiEnabled(true)
}
context?.registerReceiver(broadcastReceiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
if(resultList.isEmpty())
Toast.makeText(activity,"ResultList empty",Toast.LENGTH_LONG).show()
wifiManager.startScan()
Toast.makeText(activity,"Scanning Wifi",Toast.LENGTH_LONG).show()
}
}