How to add methods from SQLite DB class in fragment of Kotlin? - kotlin

I have an insert,update,read method in helperclass,how can I use in the following class?
Im not very used to kotlin but id like to now how can we insert the DB methods and integrate it with the code below
After adding a checkfield method ive been receiving an error when i add it in the onclicklistner
package com.google.samples.apps.topeka.fragment
import android.annotation.TargetApi
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.v4.app.ActivityOptionsCompat
import android.support.v4.app.Fragment
import android.support.v4.util.Pair
import android.support.v4.view.ViewCompat
import android.support.v4.view.animation.FastOutSlowInInterpolator
import android.text.Editable
import android.text.TextWatcher
import android.transition.Transition
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import android.widget.Toast.LENGTH_LONG
import com.google.samples.apps.topeka.adapter.AvatarAdapter
import com.google.samples.apps.topeka.base.R
import com.google.samples.apps.topeka.helper.ActivityLaunchHelper
import com.google.samples.apps.topeka.helper.ApiLevelHelper
import com.google.samples.apps.topeka.helper.DefaultLogin
import com.google.samples.apps.topeka.helper.TAG
import com.google.samples.apps.topeka.helper.TransitionHelper
import com.google.samples.apps.topeka.helper.isLoggedIn
import com.google.samples.apps.topeka.helper.login
import com.google.samples.apps.topeka.helper.onLayoutChange
import com.google.samples.apps.topeka.helper.onSmartLockResult
import com.google.samples.apps.topeka.model.Avatar
import com.google.samples.apps.topeka.model.Player
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper
import com.google.samples.apps.topeka.widget.TextWatcherAdapter
import com.google.samples.apps.topeka.widget.TransitionListenerAdapter
/**
* Enable selection of an [Avatar] and user name.
*/
class SignInFragment : Fragment() {
private var firstNameView: EditText? = null
private var lastInitialView: EditText? = null
private var doneFab: FloatingActionButton? = null
private var avatarGrid: GridView? = null
private val edit by lazy { arguments?.getBoolean(ARG_EDIT, false) ?: false }
private var selectedAvatarView: View? = null
private var player: Player? = null
private var selectedAvatar: Avatar? = null
var a = TopekaDatabaseHelper.getInstance(this.requireContext())
override fun onCreate(savedInstanceState: Bundle?) {
if (savedInstanceState != null) {
val avatarIndex = savedInstanceState.getInt(KEY_SELECTED_AVATAR_INDEX)
if (avatarIndex != GridView.INVALID_POSITION) {
selectedAvatar = Avatar.values()[avatarIndex]
}
}
activity?.run {
if (isLoggedIn()) {
navigateToCategoryActivity()
} else {
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
super.onCreate(savedInstanceState)
}
/**
* Called when logged in successfully.
*/
private fun onSuccessfulLogin(player: Player) {
if (login != DefaultLogin) return
this.player = player
if (edit) {
with(player) {
firstNameView?.setText(player.firstName)
lastInitialView?.run {
setText(player.lastInitial)
requestFocus()
setSelection(length())
}
this#SignInFragment.player = player.also {
if (activity != null)
login.savePlayer(activity!!, this, { selectAvatar(it.avatar!!) })
}
}
} else {
navigateToCategoryActivity()
}
}
private fun navigateToCategoryActivity() {
activity?.run {
ActivityLaunchHelper.launchCategorySelection(this)
supportFinishAfterTransition()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
activity?.onSmartLockResult(
requestCode,
resultCode,
data,
success = {
player = it
initContents()
navigateToCategoryActivity()
},
failure = {
activity?.run {
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
)
super.onActivityResult(requestCode, resultCode, data)
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val contentView = inflater.inflate(R.layout.fragment_sign_in, container, false)
val Button =
contentView.onLayoutChange {
avatarGrid?.apply {
adapter = AvatarAdapter(activity!!)
onItemClickListener = AdapterView.OnItemClickListener { _, view, position, _ ->
selectedAvatarView = view
selectedAvatar = Avatar.values()[position]
// showing the floating action button if input data is valid
showFab()
}
numColumns = calculateSpanCount()
selectedAvatar?.run { selectAvatar(this) }
}
}
return contentView
}
/**
* Calculates spans for avatars dynamically.
* #return The recommended amount of columns.
*/
private fun calculateSpanCount(): Int {
val avatarSize = resources.getDimensionPixelSize(R.dimen.size_fab)
val avatarPadding = resources.getDimensionPixelSize(R.dimen.spacing_double)
return (avatarGrid?.width ?: 0) / (avatarSize + avatarPadding)
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(KEY_SELECTED_AVATAR_INDEX, (avatarGrid?.checkedItemPosition ?: 0))
super.onSaveInstanceState(outState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
firstNameView = view.findViewById<EditText>(R.id.first_name)
lastInitialView = view.findViewById<EditText>(R.id.last_initial)
doneFab = view.findViewById<FloatingActionButton>(R.id.done)
avatarGrid = view.findViewById<GridView>(R.id.avatars)
if (edit || (player != null && player!!.valid())) {
initContentViews()
initContents()
}
hideEmptyView()
super.onViewCreated(view, savedInstanceState)
}
private fun hideEmptyView() {
view?.run {
findViewById<View>(R.id.empty).visibility = View.GONE
findViewById<View>(R.id.content).visibility = View.VISIBLE
}
}
private fun initContentViews() {
val textWatcher = object : TextWatcher by TextWatcherAdapter {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
// hiding the floating action button if text is empty
if (s.isEmpty()) {
doneFab?.hide()
}
}
// showing the floating action button if avatar is selected and input data is valid
override fun afterTextChanged(s: Editable) {
if (isAvatarSelected() && isInputDataValid()) doneFab?.show()
}
}
firstNameView?.addTextChangedListener(textWatcher)
lastInitialView?.addTextChangedListener(textWatcher)
doneFab?.setOnClickListener {
if (it.id == R.id.done) {
var first = firstNameView?.text?.toString()
var last = lastInitialView?.text?.toString()
//
try {
a.adduser(first,last,"string")
}
catch (e:Exception) {
// handler
}
activity?.run {
val toSave = player?.apply {
// either update the existing player object
firstName = first
lastInitial = last
avatar = selectedAvatar
a.adduser(first,last,avatar.toString())
} ?: Player(first, last, selectedAvatar) /* or create a new one */
login.savePlayer(this, toSave) {
Log.d(TAG, "Saving login info successful.")
}
}
}
removeDoneFab {
performSignInWithTransition(selectedAvatarView
?: avatarGrid?.getChildAt(selectedAvatar!!.ordinal))
}
}
}
private fun removeDoneFab(endAction: () -> Unit) {
ViewCompat.animate(doneFab)
.scaleX(0f)
.scaleY(0f)
.setInterpolator(FastOutSlowInInterpolator())
.withEndAction(endAction)
.start()
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun performSignInWithTransition(v: View? = null) {
if (v == null || ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) {
// Don't run a transition if the passed view is null
activity?.run {
navigateToCategoryActivity()
}
return
}
if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
activity?.run {
window.sharedElementExitTransition.addListener(object :
Transition.TransitionListener by TransitionListenerAdapter {
override fun onTransitionEnd(transition: Transition) {
finish()
}
})
val pairs = TransitionHelper.createSafeTransitionParticipants(this, true,
Pair(v, getString(R.string.transition_avatar)))
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, *pairs)
ActivityLaunchHelper.launchCategorySelection(this, options)
}
}
}
private fun initContents() {
player?.run {
valid().let {
firstNameView?.setText(firstName)
lastInitialView?.setText(lastInitial)
avatar?.run { selectAvatar(this) }
}
}
}
private fun isAvatarSelected() = selectedAvatarView != null || selectedAvatar != null
private fun selectAvatar(avatar: Avatar) {
selectedAvatar = avatar
avatarGrid?.run {
requestFocusFromTouch()
setItemChecked(avatar.ordinal, true)
}
showFab()
}
private fun showFab() {
if (isInputDataValid()) doneFab?.show()
}
private fun isInputDataValid() =
firstNameView?.text?.isNotEmpty() == true &&
lastInitialView?.text?.isNotEmpty() == true &&
selectedAvatar != null
companion object {
private const val ARG_EDIT = "EDIT"
private const val KEY_SELECTED_AVATAR_INDEX = "selectedAvatarIndex"
fun newInstance(edit: Boolean = false): SignInFragment {
return SignInFragment().apply {
arguments = Bundle().apply {
putBoolean(ARG_EDIT, edit)
}
}
}
}
}

Related

how to update Textview in main activity with button in adapter?

i want to update the value of my textview that is in the PosActivity when the button in MyAdapter is click ( to increase/decrease the quantity and to delete the card from recycler view). and i can't find anything on how to do it.
here is what i tried.
in MyAdapter :
package com.mycodlabs.pos.ui.sale.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.mycodlabs.pos.R
import com.mycodlabs.pos.domain.inventory.ProductModel
import kotlinx.android.synthetic.main.pos_item_card.view.*
import java.math.BigDecimal
class MyAdapter(mUx: Context, var selectedItems: ArrayList<ProductModel>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
val mUx = mUx
// var quantity = 1
var totalPrice = BigDecimal.ZERO
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var pclose = itemView.removeItempos
var pname = itemView.pos_name
var pprice = itemView.pos_price
var pqty = itemView.pos_qty
var pminus = itemView.cart_minus_img
var pplus = itemView.cart_plus_img
// val pimage = itemView.pos_image
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.pos_item_card, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val pos: ProductModel = selectedItems[position]
holder.pname.text = pos.name
holder.pprice.text = pos.unitPrice.toString()
holder.pqty.text = pos.quantity.toString()
// holder.pimage.= pos.image
holder.pclose.setOnClickListener {
val username = pos.name
var price = pos.unitPrice
totalPrice -= price
selectedItems.removeAt(position)
notifyDataSetChanged()
notifyItemRangeChanged(position, selectedItems.size)
// Toast.makeText(mUx, "User $username Deleted", Toast.LENGTH_SHORT).show()
}
holder.pminus.setOnClickListener {
if(pos.quantity == 1 ){
// Toast.makeText(mUx,"Can't go any lower", Toast.LENGTH_SHORT).show()
}else {
pos.quantity -= 1
notifyItemChanged(position)
}
}
holder.pplus.setOnClickListener {
pos.quantity += 1
notifyItemChanged(position)
}
}
fun grandTotal(items: ArrayList<ProductModel>): BigDecimal {
totalPrice = BigDecimal.ZERO
for (i in items.indices) {
totalPrice += items[i].unitPrice.multiply(items[i].quantity.toBigDecimal())
}
return totalPrice
}
fun clearData() {
selectedItems.clear()
notifyDataSetChanged()
}
override fun getItemCount() = selectedItems.size
}
and in the Activity:
package com.mycodlabs.pos.ui
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.mycodlabs.pos.R
import com.mycodlabs.pos.db.AndroidDatabase
import com.mycodlabs.pos.db.DatabaseTables
import com.mycodlabs.pos.db.inventory.InventoryDbo
import com.mycodlabs.pos.db.sale.SalesLinesDao
import com.mycodlabs.pos.domain.inventory.ProductModel
import com.mycodlabs.pos.ui.sale.adapter.MyAdapter
import kotlinx.android.synthetic.main.activity_pos.*
import kotlinx.android.synthetic.main.adapter_available_promotions.*
import kotlinx.android.synthetic.main.dialog_paymentsuccession.view.*
import kotlinx.android.synthetic.main.dialog_saleedit.*
import kotlinx.android.synthetic.main.layout_addcategory.*
import kotlinx.android.synthetic.main.layout_sale.*
import kotlinx.android.synthetic.main.listview_stock.*
import kotlinx.android.synthetic.main.pos_bottom_sheet.*
import kotlinx.android.synthetic.main.pos_item_card.*
class PosActivity : AppCompatActivity() {
private lateinit var bottomSheetBehavior: BottomSheetBehavior<LinearLayout>
private lateinit var productNames: ArrayList<String>
private lateinit var recyclerView: RecyclerView
private lateinit var db: SalesLinesDao
//// Create an empty list to store the selected items
var selectedItems = ArrayList<ProductModel>()
//// Create an adapter for the RecyclerView
val adapter = MyAdapter(this,selectedItems)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pos)
// for Back button
back.setOnClickListener {
finish()
}
check_out_Pos.setOnClickListener{
// val pos = ProductModel()
//
// db = SalesLinesDbo(this)
//
// pos.name = pos_name.text.toString()
//
// db.addLineItem(pos.id, LineItemModel())
adapter.clearData()
}
// val autoCompleteTextView = findViewById<AutoCompleteTextView>(R.id.searchBoxPos)
// autoCompleteTextView.threshold = 0
// val suggestions =InventoryDbo.getInstance(applicationContext).allProduct
// var NameArray=suggestions.toList().filter { t -> t.name.contains(autoCompleteTextView)}.toList().map { m->m.name }
// val arrayAdapter = ArrayAdapter(this, android.R.layout.simple_expandable_list_item_2 ,NameArray)
// autoCompleteTextView.setAdapter(arrayAdapter)
// Auto Complete Textview filtering from Product table colm "productName"
val autoCompleteTextView = findViewById<AutoCompleteTextView>(R.id.searchBoxPos)
val productNames = ArrayList<String>()
val dbHelper = AndroidDatabase(this)
val db = dbHelper.readableDatabase
val cursor = db.rawQuery(
"SELECT DISTINCT ${InventoryDbo.colm_productName} FROM ${DatabaseTables.TABLE_PRODUCT} WHERE ${InventoryDbo.colm_productName} like '%%'",
null
)
if (cursor.moveToFirst()) {
do {
productNames.add(cursor.getString(cursor.getColumnIndex(InventoryDbo.colm_productName)))
} while (cursor.moveToNext())
}
cursor.close()
db.close()
val adapterr = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, productNames)
autoCompleteTextView.setAdapter(adapterr)
// //// Auto Complete suggestion item display in recyclerview on select
// // Create the RecyclerView
val recyclerView = findViewById<RecyclerView>(R.id.sale_List_Pos)
//// Create a layout manager for the RecyclerView
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
recyclerView.adapter = adapter
// Set an item click listener for the AutoCompleteTextView
searchBoxPos.setOnItemClickListener { _, _, position, _ ->
// Get the selected product name and product from the list
val selectedItem = autoCompleteTextView.adapter.getItem(position).toString()
// val selectedProductName = productNames[position]
val selectedProduct = InventoryDbo.getInstance(applicationContext).getPosProductByName(selectedItem).first()
//InventoryDbo.getProductByName(selectedProductName)
// Add the selected product to the selected items list
selectedItems.add(selectedProduct)
// Notify the adapter that the data has changed
adapter.notifyDataSetChanged()
// Clear the focus and text from the AutoCompleteTextView
searchBoxPos.clearFocus()
searchBoxPos.setText("")
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
//for the bottomsheet
bottomSheetBehavior = BottomSheetBehavior.from<LinearLayout>(std_btm_sht)
bottomSheetBehavior.setBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, state: Int) {
print(state)
when (state) {
BottomSheetBehavior.STATE_HIDDEN -> {
}
BottomSheetBehavior.STATE_EXPANDED -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_COLLAPSED -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_DRAGGING -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_SETTLING -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
BottomSheetBehavior.STATE_HALF_EXPANDED -> {
total_items_Pos.text = adapter.grandTotal(selectedItems).toString()
}
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
})
}
}
i hope you can help me solve this because it was bugging me all day and i couldn't find anything about it
I'll post the changes for the plus button, you can then repeat it for the others. Mind that this is just an example, as I don't know in what way you'd like to update the text or what's the actual name of your TextView.
class MyAdapter(
mUx: Context,
var selectedItems: ArrayList<ProductModel>,
val plusLambda: (String) -> Unit // <------
) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
...
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val pos: ProductModel = selectedItems[position]
...
holder.pplus.setOnClickListener {
pos.quantity += 1
plusLambda("The new quantity is: ${ pos.quantity }") // <------
notifyItemChanged(position)
}
...
class PosActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pos)
...
val adapterr = ArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line,
productNames) {
someTextView.text = it // <------
}
autoCompleteTextView.setAdapter(adapterr)
...
Of course, you can use just one lambda for all buttons if all you want to do is to change the text of the TextView.

Observing live data from an API is not updating ui when data changes

I am trying to develop a football app demo. Data comes from an API from the api
It loads data as expected when app started, but when score of match changes, ui is not updating for scores by itself. I am using DiffUtil getChangePayload() to detect changes in score and status fields of Match objects which comes from the response. But it is not triggering when live match data changes. What am i missing?
P.S. I put layout in SwipeRefreshLayout and when i refresh, it gets scores and update the ui. But i want to see the match status and scores updating by itself.
Here is my code:
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday: MutableLiveData<List<Matche>> = MutableLiveData()
init {
getMatchesToday()
}
fun getMatchesToday() = viewModelScope.launch {
safeMatchesToday()
}
private suspend fun safeMatchesToday() {
if (Constants.checkConnection(this)) {
val response = repository.getMatchesToday()
if (response.isSuccessful) {
response.body()?.let {
matchesToday.postValue(it.matches)
}
}
}
}
}
class MatchesTodayFragment : Fragment() {
private var _binding: FragmentMatchesTodayBinding? =null
private val binding get() = _binding!!
private lateinit var mMatchesAdapter: MatchesAdapter
private val viewModel: MatchesViewModel by viewModels {
MatchesViewModelFactory(requireActivity().application, (requireActivity().application as MatchesApplication).repository)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
viewModel.matchesToday.observe(viewLifecycleOwner) { matches ->
mMatchesAdapter.differ.submitList(matches)
}
binding.srlMatchesToday.setOnRefreshListener {
viewModel.getMatchesToday()
binding.srlMatchesToday.isRefreshing = false
}
}
}
class MatchesAdapter(val fragment: Fragment): RecyclerView.Adapter<MatchesAdapter.ViewHolder>() {
private val differCallback = object: DiffUtil.ItemCallback<Matche>() {
override fun areItemsTheSame(oldItem: Matche, newItem: Matche): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Matche, newItem: Matche): Boolean {
return oldItem.status == newItem.status &&
oldItem.score.fullTime.home == newItem.score.fullTime.home &&
oldItem.score.fullTime.away == newItem.score.fullTime.away &&
oldItem == newItem
}
override fun getChangePayload(oldItem: Matche, newItem: Matche): Any? {
val bundle: Bundle = bundleOf()
if (oldItem.status != newItem.status) {
bundle.apply {
putString(Constants.MATCH_STATUS, newItem.status)
}
}
if (oldItem.score.fullTime.home != newItem.score.fullTime.home) {
bundle.apply {
putInt(Constants.HOME_SCORE, newItem.score.fullTime.home)
}
}
if (oldItem.score.fullTime.away != newItem.score.fullTime.away) {
bundle.apply {
putInt(Constants.AWAY_SCORE, newItem.score.fullTime.away)
}
}
if (bundle.size() == 0) {
return null
}
return bundle
}
}
val differ = AsyncListDiffer(this, differCallback)
#SuppressLint("UseCompatLoadingForDrawables")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val match = differ.currentList[position]
holder.apply {
Glide.with(fragment)
.load(match.homeTeam.crest)
.placeholder(fragment.resources.getDrawable(R.drawable.ic_ball))
.into(ivHomeTeamImage)
Glide.with(fragment)
.load(match.awayTeam.crest)
.placeholder(fragment.resources.getDrawable(R.drawable.ic_ball))
.into(ivAwayTeamImage)
tvHomeTeamName.text = match.homeTeam.name
tvAwayTeamName.text = match.awayTeam.name
when (match.status) {
Constants.TIMED -> {
tvMatchTime.text = Constants.toTimeForTR(match.utcDate)
tvHomeTeamScore.text = "-"
tvAwayTeamScore.text = "-"
}
Constants.PAUSED -> {
tvMatchTime.text = Constants.FIRST_HALF
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
Constants.FINISHED -> {
tvMatchTime.text = Constants.FINISHED
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
else -> {
tvMatchTime.text = Constants.IN_PLAY
tvHomeTeamScore.text = match.score.fullTime.home.toString()
tvAwayTeamScore.text = match.score.fullTime.away.toString()
}
}
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>) {
if (payloads.isNotEmpty()) {
val item = payloads[0] as Bundle
val status = item.getString(Constants.MATCH_STATUS)
val homeScore = item.getInt(Constants.HOME_SCORE)
val awayScore = item.getInt(Constants.AWAY_SCORE)
holder.apply {
tvMatchTime.text = status
tvHomeTeamScore.text = homeScore.toString()
tvAwayTeamScore.text = awayScore.toString()
Log.e("fuck", status.toString())
}
}
super.onBindViewHolder(holder, position, payloads)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
}
LiveData only pushes new values if you command it to. Since you want to do it repeatedly, you need to create a loop. This is very easy to do using the liveData coroutine builder.
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday = liveData {
while (true) {
if (Constants.checkConnection(this)) {
val response = repository.getMatchesToday()
if (response.isSuccessful) {
response.body()?.let {
emit(it.matches)
}
}
}
delay(5000) // however many ms you want between fetches
}
}
}
If this is a Retrofit response, I think checking isSuccessful is redundant because body() will be non-null if and only if isSuccessful is true. So it could be simplified a bit from what you have:
class MatchesViewModel(
app: Application,
private val repository: MatchesRepository
): AndroidViewModel(app) {
val matchesToday = liveData {
while (true) {
if (Constants.checkConnection(this)) {
repository.getMatchesToday()?.body()?.matches?.let(::emit)
}
delay(5000) // however many ms you want between fetches
}
}
}

BLE RSSI real time value update Kotlin

I need help with this project, i use BLE and connect it to smartphone and i can get the RSSI value by "ScanResult" in the ScannerFragment but its a static value in the recyclerview, i dont know what to do to make the RSSI value change in real time as i move my phone away/ closer to the BLE device, so it would jump for example from -50dBm to -60dBm as i move the smartphone away from the BLE device
ScannerFragment
import android.Manifest
import android.app.AlertDialog
import android.bluetooth.*
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.support.annotation.RequiresApi
import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import java.util.*
import kotlin.collections.HashSet
class ScannerFragment : Fragment() {
private lateinit var startButton: Button
private lateinit var stopButton: Button
private lateinit var multilateration: TextView
private lateinit var recyclerView: RecyclerView
private lateinit var linearLayoutManager: LinearLayoutManager
private var btManager: BluetoothManager? = null
private var btAdapter: BluetoothAdapter? = null
private var btScanner: BluetoothLeScanner? = null
var beaconSet: HashSet<Beacon> = HashSet()
var beaconAdapter: BeaconsAdapter? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_scanner, container, false)
initViews(view)
setUpBluetoothManager()
return view
}
companion object {
private const val REQUEST_ENABLE_BT = 1
private const val PERMISSION_REQUEST_COARSE_LOCATION = 1
}
private fun initViews(view: View) {
startButton = view.findViewById(R.id.startButton)
stopButton = view.findViewById(R.id.stopButton)
recyclerView = view.findViewById(R.id.recyclerView)
startButton.setOnClickListener { onStartScannerButtonClick() }
stopButton.setOnClickListener { onStopScannerButtonClick() }
linearLayoutManager = LinearLayoutManager(context)
recyclerView.layoutManager = linearLayoutManager
beaconAdapter = BeaconsAdapter(beaconSet.toList())
recyclerView.adapter = beaconAdapter
multilateration = view.findViewById(R.id.multilateration)
}
private fun onStartScannerButtonClick() {
startButton.setBackgroundColor(Color.GREEN)
startButton.visibility = View.GONE
stopButton.visibility = View.VISIBLE
beaconSet.clear()
btScanner?.startScan(leScanCallback)
}
private fun onStopScannerButtonClick() {
stopButton.setBackgroundColor(Color.RED)
stopButton.visibility = View.GONE
startButton.visibility = View.VISIBLE
//beaconAdapter?.beaconList?.clear()
beaconSet.clear()
btScanner?.stopScan(leScanCallback)
}
private fun setUpBluetoothManager() {
btManager = activity?.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
btAdapter = btManager!!.adapter
btScanner = btAdapter?.bluetoothLeScanner
if (btAdapter != null && !btAdapter!!.isEnabled) {
val enableIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableIntent, REQUEST_ENABLE_BT)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkForLocationPermission()
}
}
#RequiresApi(Build.VERSION_CODES.M)
private fun checkForLocationPermission() {
// Make sure we have access coarse location enabled, if not, prompt the user to enable it
if (requireActivity().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
val builder = AlertDialog.Builder(activity)
builder.setTitle("This app needs location access")
builder.setMessage("Please grant location access so this app can detect the BLE.")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener {
requestPermissions(
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
PERMISSION_REQUEST_COARSE_LOCATION
)
}
builder.show()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>, grantResults: IntArray
) {
when (requestCode) {
PERMISSION_REQUEST_COARSE_LOCATION -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
println("coarse location permission granted")
} else {
val builder = AlertDialog.Builder(activity)
builder.setTitle("Functionality limited")
builder.setMessage("Since location access has not been granted, this app will not be able to discover BLE beacons")
builder.setPositiveButton(android.R.string.ok, null)
builder.setOnDismissListener { }
builder.show()
}
return
}
}
}
private val leScanCallback: ScanCallback = object : ScanCallback() {
#RequiresApi(Build.VERSION_CODES.O)
override fun onScanResult(callbackType: Int, result: ScanResult) {
val scanRecord = result.scanRecord
val beacon = Beacon(result.rssi)
beacon.manufacturer = result.device.name
beacon.macAddress = result.device.address
beacon.rssi = result.rssi
if (scanRecord != null) {
val iBeaconManufactureData = scanRecord.getManufacturerSpecificData(0X004c)
if (iBeaconManufactureData != null && iBeaconManufactureData.size >= 23) {
val iBeaconUUID = Utility.toHexString(iBeaconManufactureData.copyOfRange(2, 18))
val major = Integer.parseInt(
Utility.toHexString(
iBeaconManufactureData.copyOfRange(
18,
20
)
), 16
)
val minor = Integer.parseInt(
Utility.toHexString(
iBeaconManufactureData.copyOfRange(
20,
22
)
), 16
)
beacon.type = Beacon.BeaconType.iBeacon
beacon.name = beacon.manufacturer
beacon.uuid = iBeaconUUID
beacon.major = major
beacon.txPower = result.txPower
beacon.minor = minor
Log.e("BeaconID", "iBeaconUUID:$iBeaconUUID major:$major minor:$minor")
}
if(beacon.name == "Beacon_1" || beacon.name == "Beacon_2" || beacon.name == "Beacon_3" || beacon.name == "Beacon_4" ) {
beaconSet.add(beacon)
}
(recyclerView.adapter as BeaconsAdapter).updateData(beaconSet.toList())
}
}
override fun onScanFailed(errorCode: Int) {
Log.e("Failed", errorCode.toString())
}
}
}
BeaconsAdapter
import android.os.Build
import android.support.annotation.RequiresApi
import android.support.v4.content.ContextCompat
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import java.util.*
class BeaconsAdapter(beacons: List<Beacon>) :
RecyclerView.Adapter<BeaconsAdapter.BeaconHolder>() {
var beaconList: MutableList<Beacon> = beacons.toMutableList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BeaconHolder {
val inflater = LayoutInflater.from(parent.context)
return BeaconHolder(inflater, parent)
}
override fun onBindViewHolder(holder: BeaconHolder, pos: Int) {
val beacon: Beacon = beaconList[pos]
holder.bind(beacon)
}
override fun getItemCount() = beaconList.size
#RequiresApi(Build.VERSION_CODES.N)
fun updateData(data: List<Beacon>) {
beaconList.clear()
beaconList.addAll(data)
notifyDataSetChanged()
}
class BeaconHolder(inflater: LayoutInflater, parent: ViewGroup) :
RecyclerView.ViewHolder(inflater.inflate(R.layout.scan_result_items, parent, false)) {
private var image: ImageView? = null
private var mac: TextView? = null
private var name: TextView? = null
private var instanceMajorMinor: TextView? = null
private var namespaceUUID: TextView? = null
private var beaconRSSI: TextView? = null
private val context = parent.context
init {
image = itemView.findViewById(R.id.beacon_image)
mac = itemView.findViewById(R.id.beacon_mac)
name = itemView.findViewById(R.id.beacon_name)
instanceMajorMinor = itemView.findViewById(R.id.beacon_instance_major_minor)
beaconRSSI = itemView.findViewById(R.id.beacon_rssi)
}
fun bind(beacon: Beacon) {
mac?.text = String.format(
context.getString(R.string.mac),
beacon.macAddress
)
beaconRSSI?.text = String.format(
context.getString(R.string.rssi),
beacon.rssi
)
if (beacon.type == Beacon.BeaconType.iBeacon) {
namespaceUUID?.text = String.format(context.getString(R.string.uuid), beacon.uuid)
name?.text = String.format(context.getString(R.string.name), beacon.name)
//namespace
instanceMajorMinor?.text = String.format(
context.getString(R.string.major_minor),
beacon.major,
beacon.minor
)
image?.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ibeacon))
instanceMajorMinor?.visibility = View.VISIBLE
namespaceUUID?.visibility = View.VISIBLE
}
}
}
}
Beacon
class Beacon(rssi: Int?) {
enum class BeaconType {
iBeacon
}
var macAddress : String? = null
var manufacturer: String? = null
var type: BeaconType = BeaconType.iBeacon
var uuid: String? = null
var name: String? = null
var major: Int? = null
var minor: Int? = null
var txPower: Int? = null
var rssi = rssi
override fun equals(other: Any?): Boolean{
if(this === other) return true
if(other !is Beacon) return false
if(macAddress != other.macAddress) return false
return true
}
override fun hashCode(): Int {
return macAddress?.hashCode() ?:0
}
}

Recycler not inflated with VideoPlayerRecyclerView

I have been trying to implement a ExpoPlayer subclass on RecyclerView based on this link: https://codingwithmitch.com/blog/playing-video-recyclerview-exoplayer-android/.
I have converted the code to Kotlin and am using the Androidx libraries.
The problem is that although there are no exceptions, my code can not find the subclassed RecyclerView in the layout. Not sure if this is a real clue but when tracing the LayoutInflater, I see that it can't find android.widget.view, android.app.view, or android.webkit.view related to the recyclerview/PlayerView (It looks like the the LayoutInflater sequentially tries to find these view types dring this process)
build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'kotlin-android-extensions'
apply plugin: "androidx.navigation.safeargs.kotlin"
android {
compileSdkVersion 28
defaultConfig {
applicationId "org.video"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// to use any vector drawables
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildFeatures{
dataBinding = true
// for view binding :
//viewBinding = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
dependencies {
def glideVersion = "4.9.0"
def exoPlayerVersion = "2.8.4"
def androidxSupportVersion="1.1.0"
def nav_version = "2.3.0"
implementation fileTree(dir: 'libs', include: ['*.jar'])
// takes over from com.android.support:design
implementation "com.google.android.material:material:1.1.0"
implementation "androidx.recyclerview:recyclerview:$androidxSupportVersion"
// ExoPlayer - playing videos
implementation "com.google.android.exoplayer:exoplayer:$exoPlayerVersion"
// Glide - thumbnails images
implementation "com.github.bumptech.glide:glide:$glideVersion"
kapt "com.github.bumptech.glide:compiler:$glideVersion"
implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
// implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.activity:activity:1.1.0"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0"
// Kotlin
implementation "androidx.core:core-ktx:1.3.0"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// following https://dev.to/anesabml/dagger-hilt-basics-23g8
//Hilt Dependency Injection
kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
kapt "androidx.hilt:hilt-compiler:1.0.0-alpha01"
implementation "com.google.dagger:hilt-android:2.28-alpha"
// For injecting ViewModel
implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01"
// For injecting WorkManager
implementation "androidx.hilt:hilt-work:1.0.0-alpha01"
// ExoPlayer - playing videos
implementation "com.google.android.exoplayer:exoplayer:$exoPlayerVersion"
// Glide - thumbnails images
implementation "com.github.bumptech.glide:glide:$glideVersion"
kapt "com.github.bumptech.glide:compiler:$glideVersion"
// Navigation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Dynamic Feature Module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
// Testing Navigation
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// testImplementation 'junit:junit:4.12'
// androidTestImplementation 'androidx.test.ext:junit:1.1.1'
// androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
repositories {
mavenCentral()
}
watch_videos_layout.xml file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data class="WatchVideosBinding">
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f2f2f2"
tools:context="org.video.start.StartOptionsActivity">
<org.video.VideoPlayerRecyclerView
android:id="#+id/video_player_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
VideoPlayerRecyclerView.kt
package org.video
import android.content.Context
import android.graphics.Point
import android.net.Uri
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.RequestManager
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.*
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.PlayerView
import com.google.android.exoplayer2.upstream.BandwidthMeter
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
import org.video.R
// from https://codingwithmitch.com/blog/playing-video-recyclerview-exoplayer-android/ converted to Kotlin
class VideoPlayerRecyclerView #JvmOverloads constructor(context: Context, attrs: AttributeSet) : RecyclerView(context) {
private val TAG = "VideoPlayerRecyclerView"
private enum class VolumeState {
ON, OFF
}
// ui
private var thumbnail: ImageView? = null
private var volumeControl: ImageView? = null
private var progressBar: ProgressBar? = null
private var viewHolderParent: View? = null
private var frameLayout: FrameLayout? = null
private var videoSurfaceView: PlayerView? = null
private var videoPlayer: SimpleExoPlayer? = null
// vars
private var mediaObjects: ArrayList<MediaObject> = ArrayList()
private var videoSurfaceDefaultHeight = 0
private var screenDefaultHeight = 0
private var playPosition = -1
private var isVideoViewAdded = false
private var requestManager: RequestManager? = null
// controlling playback state
private var volumeState: VolumeState? = null
init {
// context = context.applicationContext
val display = (getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
val point = Point()
display.getSize(point)
videoSurfaceDefaultHeight = point.x
screenDefaultHeight = point.y
videoSurfaceView = PlayerView(context)
videoSurfaceView?.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
val bandwidthMeter: BandwidthMeter = DefaultBandwidthMeter()
val videoTrackSelectionFactory: TrackSelection.Factory = AdaptiveTrackSelection.Factory(bandwidthMeter)
val trackSelector: TrackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
// 2. Create the player
videoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector)
// Bind the player to the view.
videoSurfaceView?.setUseController(false)
videoSurfaceView?.setPlayer(videoPlayer)
setVolumeControl(VolumeState.ON)
addOnScrollListener(object : OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == SCROLL_STATE_IDLE) {
Log.d(TAG, "onScrollStateChanged: called.")
if (thumbnail != null) { // show the old thumbnail
thumbnail!!.visibility = View.VISIBLE
}
// There's a special case when the end of the list has been reached.
// Need to handle that with this bit of logic
if (!recyclerView.canScrollVertically(1)) {
playVideo(true)
} else {
playVideo(false)
}
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
}
})
addOnChildAttachStateChangeListener(object : OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {}
override fun onChildViewDetachedFromWindow(view: View) {
if (viewHolderParent != null && viewHolderParent == view) {
resetVideoView()
}
}
})
this.videoPlayer?.addListener(object : Player.EventListener {
// override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {
}
override fun onTracksChanged(trackGroups: TrackGroupArray, trackSelections: TrackSelectionArray) {}
override fun onLoadingChanged(isLoading: Boolean) {}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
when (playbackState) {
Player.STATE_BUFFERING -> {
Log.e(TAG, "onPlayerStateChanged: Buffering video.")
if (progressBar != null) {
progressBar!!.visibility = View.VISIBLE
}
}
Player.STATE_ENDED -> {
Log.d(TAG, "onPlayerStateChanged: Video ended.")
videoPlayer?.seekTo(0)
}
Player.STATE_IDLE -> {
}
Player.STATE_READY -> {
Log.e(TAG, "onPlayerStateChanged: Ready to play.")
if (progressBar != null) {
progressBar!!.visibility = View.GONE
}
if (!isVideoViewAdded) {
addVideoView()
}
}
else -> {
}
}
}
override fun onRepeatModeChanged(repeatMode: Int) {}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {}
override fun onPlayerError(error: ExoPlaybackException) {}
override fun onPositionDiscontinuity(reason: Int) {}
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {}
override fun onSeekProcessed() {}
})
}
fun playVideo(isEndOfList: Boolean) {
var targetPosition: Int
if (!isEndOfList) {
var startPosition = (getLayoutManager() as LinearLayoutManager).findFirstVisibleItemPosition()
var endPosition = (getLayoutManager() as LinearLayoutManager).findLastVisibleItemPosition()
// if there is more than 2 list-items on the screen, set the difference to be 1
if (endPosition - startPosition > 1) {
endPosition = startPosition + 1
}
// something is wrong. return.
if (startPosition < 0 || endPosition < 0) {
return
}
// if there is more than 1 list-item on the screen
if (startPosition != endPosition) {
val startPositionVideoHeight = getVisibleVideoSurfaceHeight(startPosition)
val endPositionVideoHeight = getVisibleVideoSurfaceHeight(endPosition)
if (startPositionVideoHeight > endPositionVideoHeight) {
targetPosition = startPosition
} else {
targetPosition = endPosition
}
} else {
targetPosition = startPosition
}
} else {
targetPosition = mediaObjects.size - 1
}
Log.d(TAG, "playVideo: target position: " + targetPosition)
// video is already playing so return
if (targetPosition == playPosition) {
return
}
// set the position of the list-item that is to be played
this.playPosition = targetPosition
if (videoSurfaceView == null) {
return
}
// remove any old surface views from previously playing videos
videoSurfaceView?.setVisibility(INVISIBLE)
removeVideoView(videoSurfaceView!!)
val currentPosition: Int = targetPosition - (getLayoutManager() as LinearLayoutManager).findFirstVisibleItemPosition()
val child: View = getChildAt(currentPosition) ?: return
val holder = child.getTag() as VideoPlayerRecyclerAdapter.VideoPlayerViewHolder?
if (holder == null) {
playPosition = -1
return
}
this.thumbnail = holder.thumbnail
this.progressBar = holder.progressBar
this.volumeControl = holder.volumeControl
this.viewHolderParent = holder.itemView
this.requestManager = holder.requestManager
this.frameLayout = holder.media_container
videoSurfaceView!!.setPlayer(videoPlayer)
viewHolderParent!!.setOnClickListener(videoViewClickListener)
val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(
context, Util.getUserAgent(context, "RecyclerView VideoPlayer"))
val mediaUrl: String? = mediaObjects.get(targetPosition).media_url
if (mediaUrl != null) {
val videoSource: MediaSource = ExtractorMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(mediaUrl))
videoPlayer?.prepare(videoSource)
videoPlayer?.setPlayWhenReady(true)
}
}
private val videoViewClickListener = OnClickListener { toggleVolume() }
/**
* Returns the visible region of the video surface on the screen.
* if some is cut off, it will return less than the #videoSurfaceDefaultHeight
* #param playPosition
* #return
*/
private fun getVisibleVideoSurfaceHeight(playPosition: Int): Int {
val at = playPosition - (layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
Log.d(TAG, "getVisibleVideoSurfaceHeight: at: $at")
val child = getChildAt(at) ?: return 0
val location = IntArray(2)
child.getLocationInWindow(location)
return if (location[1] < 0) {
location[1] + videoSurfaceDefaultHeight
} else {
screenDefaultHeight - location[1]
}
}
// Remove the old player
private fun removeVideoView(videoView: PlayerView) {
val parent: ViewGroup? = videoView.parent as ViewGroup
if (parent == null){
return;
}
val index: Int = parent.indexOfChild(videoView)
if (index >= 0) {
parent.removeViewAt(index)
isVideoViewAdded = false
viewHolderParent!!.setOnClickListener(null)
}
}
private fun addVideoView() {
frameLayout!!.addView(videoSurfaceView)
isVideoViewAdded = true
videoSurfaceView!!.requestFocus()
videoSurfaceView!!.visibility = View.VISIBLE
videoSurfaceView!!.alpha = 1f
thumbnail!!.visibility = View.GONE
}
private fun resetVideoView() {
if (isVideoViewAdded) {
removeVideoView(videoSurfaceView!!)
playPosition = -1
videoSurfaceView!!.visibility = View.INVISIBLE
thumbnail!!.visibility = View.VISIBLE
}
}
fun releasePlayer() {
if (videoPlayer != null) {
videoPlayer!!.release()
videoPlayer = null
}
viewHolderParent = null
}
private fun toggleVolume() {
if (videoPlayer != null) {
if (volumeState === VolumeState.OFF) {
Log.d(TAG, "togglePlaybackState: enabling volume.")
setVolumeControl(VolumeState.ON)
} else if (volumeState === VolumeState.ON) {
Log.d(TAG, "togglePlaybackState: disabling volume.")
setVolumeControl(VolumeState.OFF)
}
}
}
private fun setVolumeControl(state: VolumeState) {
volumeState = state
if (state === VolumeState.OFF) {
videoPlayer!!.volume = 0f
animateVolumeControl()
} else if (state === VolumeState.ON) {
videoPlayer!!.volume = 1f
animateVolumeControl()
}
}
private fun animateVolumeControl() {
if (volumeControl != null) {
volumeControl!!.bringToFront()
if (volumeState === VolumeState.OFF) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
requestManager?.load(getResources().getDrawable(R.drawable.ic_volume_off_gray_24dp, null))
?.into(volumeControl!!)
}
} else if (volumeState === VolumeState.ON) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
requestManager?.load(getResources().getDrawable(R.drawable.ic_volume_up_grey_24dp, null))
?.into(volumeControl!!)
}
}
volumeControl!!.animate().cancel()
volumeControl!!.alpha = 1f
volumeControl!!.animate()
.alpha(0f)
.setDuration(600).startDelay = 1000
}
}
fun setMediaObjects(mediaObjects: ArrayList<MediaObject>) {
this.mediaObjects = mediaObjects
}
}
Fragment
package org.video
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestManager
import com.bumptech.glide.request.RequestOptions
import dagger.hilt.android.AndroidEntryPoint
import org.video.R
import org.video.databinding.WatchVideosBinding
import java.util.*
import kotlin.collections.ArrayList
// from https://codingwithmitch.com/blog/playing-video-recyclerview-exoplayer-android/
// Was from MainActivity but logic moved to Fragment
#AndroidEntryPoint
class WatchVideosFragment : Fragment() {
private val videoViewModel: VideoViewModel by viewModels()
lateinit var binding: WatchVideosBinding
var recyclerView: VideoPlayerRecyclerView? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(
inflater,
R.layout.watch_videos_layout,
container,
false
)
this.recyclerView = binding.videoPlayerRecyclerView <<< comes back null
initRecyclerView(this.recyclerView)
return binding.root
}
private fun initRecyclerView(recyclerView: VideoPlayerRecyclerView?) {
recyclerView?.layoutManager = LinearLayoutManager(context)
recyclerView?.addItemDecoration(VerticalSpacingItemDecorator(10))
val mediaObjects: ArrayList<MediaObject> = videoViewModel.getWatchMediaObjects()
recyclerView?.setMediaObjects(mediaObjects)
recyclerView?.adapter = VideoPlayerRecyclerAdapter(mediaObjects, initGlide())
}
private fun initGlide(): RequestManager {
val options: RequestOptions = RequestOptions()
.placeholder(R.drawable.white_background)
.error(R.drawable.white_background)
return Glide.with(this)
.setDefaultRequestOptions(options)
}
override fun onDestroy() {
if (recyclerView != null) {
recyclerView?.releasePlayer()
}
super.onDestroy()
}
}
Found the problem. When I converted the code to Kotlin there was a reference to Context that I thought was redundant and deleted. My bad! Just for reference my new VideoPlayerRecyclerView is below.
The code also includes some view name changes and I found I needed to include a reference to the resource file because if I didn't I kept getting compile errors saying the R.id.(view names) could not be found. Not sure why that is.
package org.video
import android.content.Context
import android.graphics.Point
import android.net.Uri
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.ProgressBar
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.RequestManager
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.*
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.PlayerView
import com.google.android.exoplayer2.upstream.BandwidthMeter
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
import org.video.R
import java.util.*
class VideoPlayerRecyclerView : RecyclerView {
private enum class VolumeState {
ON, OFF
}
// ui
private var thumbnail: ImageView? = null
private var volumeControl: ImageView? = null
private var progressBar: ProgressBar? = null
private var viewHolderParent: View? = null
private var frameLayout: FrameLayout? = null
private var videoSurfaceView: PlayerView? = null
private var videoPlayer: SimpleExoPlayer? = null
// vars
private var mediaObjects = ArrayList<MediaObject>()
private var videoSurfaceDefaultHeight = 0
private var screenDefaultHeight = 0
private var viewContext: Context? = null //<< Need this. Renamed to avoid name conflict with constructor context name
private var playPosition = -1
private var isVideoViewAdded = false
private var requestManager: RequestManager? = null
// controlling playback state
private var volumeState: VolumeState? = null
constructor(context: Context) : super(context) {
init(context)
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context)
}
private fun init(context: Context) {
this.viewContext = context.applicationContext
val display = (getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
val point = Point()
display.getSize(point)
videoSurfaceDefaultHeight = point.x
screenDefaultHeight = point.y
videoSurfaceView = PlayerView(this.viewContext)
videoSurfaceView!!.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM
val bandwidthMeter: BandwidthMeter = DefaultBandwidthMeter()
val videoTrackSelectionFactory: TrackSelection.Factory = AdaptiveTrackSelection.Factory(bandwidthMeter)
val trackSelector: TrackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
// 2. Create the player
videoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector)
// Bind the player to the view.
videoSurfaceView!!.useController = false
videoSurfaceView!!.player = videoPlayer
setVolumeControl(VolumeState.ON)
addOnScrollListener(object : OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == SCROLL_STATE_IDLE) {
Log.d(TAG, "onScrollStateChanged: called.")
if (thumbnail != null) { // show the old thumbnail
thumbnail!!.visibility = View.VISIBLE
}
// There's a special case when the end of the list has been reached.
// Need to handle that with this bit of logic
if (!recyclerView.canScrollVertically(1)) {
playVideo(true)
} else {
playVideo(false)
}
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
}
})
addOnChildAttachStateChangeListener(object : OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {}
override fun onChildViewDetachedFromWindow(view: View) {
if (viewHolderParent != null && viewHolderParent == view) {
resetVideoView()
}
}
})
this.videoPlayer?.addListener(object : Player.EventListener {
override fun onTimelineChanged(timeline: Timeline, manifest: Any?, reason: Int) {}
override fun onTracksChanged(trackGroups: TrackGroupArray, trackSelections: TrackSelectionArray) {}
override fun onLoadingChanged(isLoading: Boolean) {}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
when (playbackState) {
Player.STATE_BUFFERING -> {
Log.e(TAG, "onPlayerStateChanged: Buffering video.")
if (progressBar != null) {
progressBar!!.visibility = View.VISIBLE
}
}
Player.STATE_ENDED -> {
Log.d(TAG, "onPlayerStateChanged: Video ended.")
videoPlayer?.seekTo(0)
}
Player.STATE_IDLE -> {
}
Player.STATE_READY -> {
Log.e(TAG, "onPlayerStateChanged: Ready to play.")
if (progressBar != null) {
progressBar!!.visibility = View.GONE
}
if (!isVideoViewAdded) {
addVideoView()
}
}
else -> {
}
}
}
override fun onRepeatModeChanged(repeatMode: Int) {}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {}
override fun onPlayerError(error: ExoPlaybackException) {}
override fun onPositionDiscontinuity(reason: Int) {}
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {}
override fun onSeekProcessed() {}
})
}
fun playVideo(isEndOfList: Boolean) {
val targetPosition: Int
if (!isEndOfList) {
val startPosition = (layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
var endPosition = (layoutManager as LinearLayoutManager?)!!.findLastVisibleItemPosition()
// if there is more than 2 list-items on the screen, set the difference to be 1
if (endPosition - startPosition > 1) {
endPosition = startPosition + 1
}
// something is wrong. return.
if (startPosition < 0 || endPosition < 0) {
return
}
// if there is more than 1 list-item on the screen
targetPosition = if (startPosition != endPosition) {
val startPositionVideoHeight = getVisibleVideoSurfaceHeight(startPosition)
val endPositionVideoHeight = getVisibleVideoSurfaceHeight(endPosition)
if (startPositionVideoHeight > endPositionVideoHeight) startPosition else endPosition
} else {
startPosition
}
} else {
targetPosition = mediaObjects.size - 1
}
Log.d(TAG, "playVideo: target position: $targetPosition")
// video is already playing so return
if (targetPosition == playPosition) {
return
}
// set the position of the list-item that is to be played
playPosition = targetPosition
if (videoSurfaceView == null) {
return
}
// remove any old surface views from previously playing videos
videoSurfaceView!!.visibility = View.INVISIBLE
removeVideoView(videoSurfaceView)
val currentPosition = targetPosition - (layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
val child = getChildAt(currentPosition) ?: return
val holder = child.tag as VideoPlayerViewHolder?
if (holder == null) {
playPosition = -1
return
}
thumbnail = holder.thumbnail
progressBar = holder.progressBar
volumeControl = holder.volumeControl
viewHolderParent = holder.itemView
requestManager = holder.requestManager
frameLayout = holder.itemView.findViewById(R.id.watch_video_media_container)
videoSurfaceView!!.player = videoPlayer
viewHolderParent!!.setOnClickListener(videoViewClickListener)
val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(
viewContext, Util.getUserAgent(viewContext, "RecyclerView VideoPlayer"))
val mediaUrl = mediaObjects[targetPosition].media_url
if (mediaUrl != null) {
val videoSource: MediaSource = ExtractorMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(mediaUrl))
videoPlayer!!.prepare(videoSource)
videoPlayer!!.playWhenReady = true
}
}
private val videoViewClickListener = OnClickListener { toggleVolume() }
/**
* Returns the visible region of the video surface on the screen.
* if some is cut off, it will return less than the #videoSurfaceDefaultHeight
* #param playPosition
* #return
*/
private fun getVisibleVideoSurfaceHeight(playPosition: Int): Int {
val at = playPosition - (layoutManager as LinearLayoutManager?)!!.findFirstVisibleItemPosition()
Log.d(TAG, "getVisibleVideoSurfaceHeight: at: $at")
val child = getChildAt(at) ?: return 0
val location = IntArray(2)
child.getLocationInWindow(location)
return if (location[1] < 0) {
location[1] + videoSurfaceDefaultHeight
} else {
screenDefaultHeight - location[1]
}
}
// Remove the old player
private fun removeVideoView(videoView: PlayerView?) {
if (videoView?.parent == null) {
return
}
val parent = videoView?.parent as ViewGroup
val index = parent.indexOfChild(videoView)
if (index >= 0) {
parent.removeViewAt(index)
isVideoViewAdded = false
viewHolderParent!!.setOnClickListener(null)
}
}
private fun addVideoView() {
frameLayout!!.addView(videoSurfaceView)
isVideoViewAdded = true
videoSurfaceView!!.requestFocus()
videoSurfaceView!!.visibility = View.VISIBLE
videoSurfaceView!!.alpha = 1f
thumbnail!!.visibility = View.GONE
}
private fun resetVideoView() {
if (isVideoViewAdded) {
removeVideoView(videoSurfaceView)
playPosition = -1
videoSurfaceView!!.visibility = View.INVISIBLE
thumbnail!!.visibility = View.VISIBLE
}
}
fun releasePlayer() {
if (videoPlayer != null) {
videoPlayer!!.release()
videoPlayer = null
}
viewHolderParent = null
}
private fun toggleVolume() {
if (videoPlayer != null) {
if (volumeState == VolumeState.OFF) {
Log.d(TAG, "togglePlaybackState: enabling volume.")
setVolumeControl(VolumeState.ON)
} else if (volumeState == VolumeState.ON) {
Log.d(TAG, "togglePlaybackState: disabling volume.")
setVolumeControl(VolumeState.OFF)
}
}
}
private fun setVolumeControl(state: VolumeState) {
volumeState = state
if (state == VolumeState.OFF) {
videoPlayer!!.volume = 0f
animateVolumeControl()
} else if (state == VolumeState.ON) {
videoPlayer!!.volume = 1f
animateVolumeControl()
}
}
private fun animateVolumeControl() {
if (volumeControl != null) {
volumeControl!!.bringToFront()
if (volumeState == VolumeState.OFF) {
requestManager!!.load(R.drawable.ic_volume_off_grey_24dp)
.into(volumeControl!!)
} else if (volumeState == VolumeState.ON) {
requestManager!!.load(R.drawable.ic_volume_up_grey_24dp)
.into(volumeControl!!)
}
volumeControl!!.animate().cancel()
volumeControl!!.alpha = 1f
volumeControl!!.animate()
.alpha(0f)
.setDuration(600).startDelay = 1000
}
}
fun setMediaObjects(mediaObjects: ArrayList<MediaObject>) {
this.mediaObjects = mediaObjects
}
companion object {
private const val TAG = "VideoPlayerRecyclerView"
}
}

fatel error check internet connection in kotlin

my app working fine any without problem , i used AsyncTask to get data json and every thing is fine . i want to add code to check internet connection in my app and i put code under onCreate in main activity .
val cm = baseContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = cm.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnected){
if (networkInfo.type == ConnectivityManager.TYPE_WIFI){
Toast.makeText(baseContext,"wifi",Toast.LENGTH_SHORT).show()
}
if (networkInfo.type == ConnectivityManager.TYPE_MOBILE){
Toast.makeText(baseContext,"MOBILE",Toast.LENGTH_SHORT).show()
}
}else {
Toast.makeText(baseContext,"MOBILE",Toast.LENGTH_SHORT).show()
this.finish()
}
when l put the phone on airplan mode and launching app he is stop working . and crash .
console log
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.iraqairoirt.iraqairports, PID: 10868
main activity
package com.iraqairoirt.iraqairports
import android.annotation.SuppressLint
import android.content.Context
import android.content.DialogInterface
import android.os.AsyncTask
import android.os.Bundle
import android.support.design.widget.NavigationView
import android.support.v4.view.GravityCompat
import android.support.v7.app.ActionBarDrawerToggle
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import android.widget.TextView
import com.iraqairoirt.iraqairports.BaghdadAirport.ListAdapteArr
import com.iraqairoirt.iraqairports.BaghdadAirport.ListAdapteDep
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*
import kotlinx.android.synthetic.main.fragment_baghdada_arrivel.*
import kotlinx.android.synthetic.main.fragment_baghdada_dep.*
import org.json.JSONArray
import org.json.JSONObject
import java.net.HttpURLConnection
import java.net.URL
import android.widget.Toast
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.support.design.widget.Snackbar
import com.iraqairoirt.iraqairports.BaghdadAirport.FlightsArrivelBeforBGW
import com.iraqairoirt.iraqairports.BaghdadAirport.FlightsDepBeforBGW
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val url = "airport.json"
Arr().execute(url)
setSupportActionBar(toolbar)
val fragmentAdapter = MyPagerAdapter(supportFragmentManager)
viewpager_main.adapter = fragmentAdapter
sliding_tabs.setupWithViewPager(viewpager_main)
val toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close
)
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
nav_view.setNavigationItemSelectedListener(this)
val cm = baseContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = cm.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnected){
if (networkInfo.type == ConnectivityManager.TYPE_WIFI){
Toast.makeText(baseContext,"wifi",Toast.LENGTH_SHORT).show()
}
if (networkInfo.type == ConnectivityManager.TYPE_MOBILE){
Toast.makeText(baseContext,"MOBILE",Toast.LENGTH_SHORT).show()
}
}else {
Toast.makeText(baseContext,"MOBILE",Toast.LENGTH_SHORT).show()
this.finish()
}
}
// full class for json api
inner class Arr : AsyncTask<String, String, String>() {
val progressDialog = AlertDialog.Builder(this#MainActivity)
val dialogView = layoutInflater.inflate(R.layout.progress_dialog, null)
val message = dialogView.findViewById<TextView>(R.id.message_id)
val dialog = progressDialog.create()
override fun onPreExecute() {
super.onPreExecute()
dialog.setMessage("يرجى الانتظار")
dialog.setCancelable(false)
dialog.show()
}
// for build connection
override fun doInBackground(vararg url: String?): String {
var text: String
val connection = URL(url[0]).openConnection() as HttpURLConnection
try {
connection.connect()
text = connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
} finally {
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson(result)
dialog.dismiss();
}
override fun onProgressUpdate(vararg text: String?) {
}
#SuppressLint("WrongViewCast")
private fun handleJson(jsonString: String?) {
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("response")
val airport = response.getJSONObject("airport")
val pluginData = airport.getJSONObject("pluginData")
val schedule = pluginData.getJSONObject("schedule")
val arrivals = schedule.getJSONObject("arrivals")
// weather data
val weather = pluginData.getJSONObject("weather")
val mater = weather.getString("metar")
// MaterText.text=mater
// val data = arrivals.getJSONObject("data")
val jsonArray = JSONArray(arrivals.get("data").toString())
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
FlightShdu(
jsonObject.getJSONObject("flight").getJSONObject("identification").getJSONObject("number").getString(
"default"
),
jsonObject.getJSONObject("flight").getJSONObject("airline").getString("short"),
jsonObject.getJSONObject("flight").getJSONObject("status").getJSONObject("generic").getJSONObject(
"status"
).getString("text"),
jsonObject.getJSONObject("flight").getJSONObject("airline").getJSONObject("code").getString("icao"),
jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("scheduled").getString("arrival"),
jsonObject.getJSONObject("flight").getJSONObject("airport").getJSONObject("origin").getJSONObject(
"code"
).getString("iata"),
jsonObject.getJSONObject("flight").getJSONObject("aircraft").getJSONObject("model").getString("code"),
// for more information
jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("real").getString("departure"),
jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("estimated").getString("arrival"),
// jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("estimated").getString("arrival"),
jsonObject.getJSONObject("flight").getJSONObject("aircraft").getString("registration"),
jsonObject.getJSONObject("flight").getJSONObject("status").getJSONObject("generic").getJSONObject(
"status"
).getString("diverted"),
arrivals.getString("timestamp"),
jsonObject.getJSONObject("flight").getJSONObject("status").getString("icon")
)
)
x++
}
list.forEach(::println)
var adapter = ListAdapteArr(this#MainActivity, list)
flight_arrivel_list.adapter = adapter
}
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
//noinspection SimplifiableIfStatement
if (id == R.id.flightarrbeforbgw) {
val intent = Intent(this, FlightsArrivelBeforBGW::class.java)
this.startActivity(intent)
return true
}
if (id == R.id.flightdepbefrobgw) {
val intent = Intent(this, FlightsDepBeforBGW::class.java)
this.startActivity(intent)
return true
}
//
// if (id == R.id.searchflights) {
// Toast.makeText(this, "Android Menu is Clicked", Toast.LENGTH_LONG).show()
// return true
// }
return super.onOptionsItemSelected(item)
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.nav_camera -> {
// Handle the camera action
}
R.id.nav_gallery -> {
}
R.id.nav_slideshow -> {
}
R.id.nav_manage -> {
}
R.id.nav_share -> {
}
R.id.nav_send -> {
}
}
drawer_layout.closeDrawer(GravityCompat.START)
return true
}
}
to avoid fatal error and crash when there is not internet connection ,my mistake is i should put execute() url inside code of check internet connection
val cm = baseContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = cm.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnected){
if (networkInfo.type == ConnectivityManager.TYPE_WIFI){
val url = "airport.json"
Arr().execute(url)
}
if (networkInfo.type == ConnectivityManager.TYPE_MOBILE){
val url = "airport.json"
Arr().execute(url)
}
}else {
val builder = AlertDialog.Builder(this)
builder.setTitle("No internet Connection")
builder.setMessage("Please turn on internet connection to continue")
builder.setNegativeButton(
"close"
) { dialog, button -> this.finish() }
val alertDialog = builder.create()
alertDialog.show()
}
now my app working fine =)