Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am a newbie at develop android app.
I want to use "Droid Speech" but I can't use it, because "Droid Speech" is made of AppCompatActivity.
I want to how to change AppCompatActivity into Fragment.
this is my code
class DroidSpeechActivity : AppCompatActivity(), View.OnClickListener,
OnDSListener,
OnDSPermissionsListener {
val TAG = "Activity_DroidSpeech"
private var droidSpeech: DroidSpeech? = null
private var finalSpeechResult: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_droid_speech)
droidSpeech =
DroidSpeech(this, fragmentManager)
droidSpeech!!.setOnDroidSpeechListener(this)
droidSpeech!!.setShowRecognitionProgressView(false)
droidSpeech!!.setOneStepResultVerify(true)
droidSpeech!!.setRecognitionProgressMsgColor(Color.WHITE)
droidSpeech!!.setOneStepVerifyConfirmTextColor(Color.WHITE)
droidSpeech!!.setOneStepVerifyRetryTextColor(Color.WHITE)
droidSpeech!!.setPreferredLanguage("ko-KR")
finalSpeechResult = findViewById(R.id.finalSpeechResult)
start.setOnClickListener(this)
stop.setOnClickListener(this)
}
override fun onPause() {
super.onPause()
if (stop!!.visibility == View.VISIBLE) {
stop!!.performClick()
}
}
override fun onDestroy() {
super.onDestroy()
if (stop!!.visibility == View.VISIBLE) {
stop!!.performClick()
}
}
override fun onClick(view: View) {
when (view.id) {
R.id.start -> {
// Starting droid speech
droidSpeech!!.startDroidSpeechRecognition()
// Setting the view visibilities when droid speech is running
start!!.visibility = View.GONE
stop!!.visibility = View.VISIBLE
}
R.id.stop -> {
// Closing droid speech
droidSpeech!!.closeDroidSpeechOperations()
stop!!.visibility = View.GONE
start!!.visibility = View.VISIBLE
}
}
}
// MARK: DroidSpeechListener Methods
override fun onDroidSpeechSupportedLanguages(currentSpeechLanguage: String, supportedSpeechLanguages: List<String>) {
Log.i(TAG, "Current speech language = $currentSpeechLanguage")
Log.i(TAG, "Supported speech languages = $supportedSpeechLanguages")
if (supportedSpeechLanguages.contains("ko-KR")) {
// Setting the droid speech preferred language as tamil if found
droidSpeech!!.setPreferredLanguage("ko-KR")
// Setting the confirm and retry text in tamil
droidSpeech!!.setOneStepVerifyConfirmText("check")
droidSpeech!!.setOneStepVerifyRetryText("no")
}
}
override fun onDroidSpeechRmsChanged(rmsChangedValue: Float) {
}
override fun onDroidSpeechLiveResult(liveSpeechResult: String) {
Log.i(TAG, "Live speech result = $liveSpeechResult")
}
override fun onDroidSpeechFinalResult(finalSpeechResult: String) {
this.finalSpeechResult!!.text = finalSpeechResult
println("test$finalSpeechResult")
if (droidSpeech!!.continuousSpeechRecognition) {
val colorPallets1 = intArrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.CYAN, Color.MAGENTA)
val colorPallets2 = intArrayOf(Color.YELLOW, Color.RED, Color.CYAN, Color.BLUE, Color.GREEN)
// Setting random color pallets to the recognition progress view
droidSpeech!!.setRecognitionProgressViewColors(if (Random().nextInt(2) == 0) colorPallets1 else colorPallets2)
} else {
stop!!.visibility = View.GONE
start!!.visibility = View.VISIBLE
}
}
override fun onDroidSpeechClosedByUser() {
stop!!.visibility = View.GONE
start!!.visibility = View.VISIBLE
}
override fun onDroidSpeechError(errorMsg: String) {
Toast.makeText(this, errorMsg, Toast.LENGTH_LONG).show()
stop!!.post {
stop!!.performClick()
}
}
// MARK: DroidSpeechPermissionsListener Method
override fun onDroidSpeechAudioPermissionStatus(audioPermissionGiven: Boolean, errorMsgIfAny: String) {
if (audioPermissionGiven) {
start!!.post {
start!!.performClick()
}
} else {
if (errorMsgIfAny != null) {
Toast.makeText(this, errorMsgIfAny, Toast.LENGTH_LONG).show()
}
stop!!.post {
stop!!.performClick()
}
}
}
}
this is try to change code...but err
class DroidSpeechActivity : Fragment(), View.OnClickListener,
OnDSListener,
OnDSPermissionsListener {
val TAG = "Activity_DroidSpeech"
private var droidSpeech: DroidSpeech? = null
private var finalSpeechResult: TextView? = null
// MARK: Activity Methods
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Setting the layout;[.
// Initializing the droid speech and setting the listener
droidSpeech =
DroidSpeech(activity?.applicationContext, activity?.getFragmentManager())
droidSpeech!!.setOnDroidSpeechListener(this)
droidSpeech!!.setShowRecognitionProgressView(false)
droidSpeech!!.setOneStepResultVerify(true)
droidSpeech!!.setRecognitionProgressMsgColor(Color.WHITE)
droidSpeech!!.setOneStepVerifyConfirmTextColor(Color.WHITE)
droidSpeech!!.setOneStepVerifyRetryTextColor(Color.WHITE)
droidSpeech!!.setPreferredLanguage("ko-KR")
start.setOnClickListener(this)
stop.setOnClickListener(this)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.activity_droid_speech, container, false)
}
override fun onPause() {
super.onPause()
if (stop!!.visibility == View.VISIBLE) {
stop!!.performClick()
}
}
override fun onDestroy() {
super.onDestroy()
if (stop!!.visibility == View.VISIBLE) {
stop!!.performClick()
}
}
// MARK: OnClickListener Method
override fun onClick(view: View) {
when (view.id) {
R.id.start -> {
// Starting droid speech
droidSpeech!!.startDroidSpeechRecognition()
// Setting the view visibilities when droid speech is running
start!!.visibility = View.GONE
stop!!.visibility = View.VISIBLE
}
R.id.stop -> {
// Closing droid speech
droidSpeech!!.closeDroidSpeechOperations()
stop!!.visibility = View.GONE
start!!.visibility = View.VISIBLE
}
}
}
// MARK: DroidSpeechListener Methods
override fun onDroidSpeechSupportedLanguages(currentSpeechLanguage: String, supportedSpeechLanguages: List<String>) {
Log.i(TAG, "Current speech language = $currentSpeechLanguage")
Log.i(TAG, "Supported speech languages = $supportedSpeechLanguages")
if (supportedSpeechLanguages.contains("ko-KR")) {
// Setting the droid speech preferred language as tamil if found
droidSpeech!!.setPreferredLanguage("ko-KR")
// Setting the confirm and retry text in tamil
droidSpeech!!.setOneStepVerifyConfirmText("check")
droidSpeech!!.setOneStepVerifyRetryText("no")
}
}
override fun onDroidSpeechRmsChanged(rmsChangedValue: Float) {
// Log.i(TAG, "Rms change value = " + rmsChangedValue);
}
override fun onDroidSpeechLiveResult(liveSpeechResult: String) {
Log.i(TAG, "Live speech result = $liveSpeechResult")
}
override fun onDroidSpeechFinalResult(finalSpeechResult: String) {
// Setting the final speech result
this.finalSpeechResult!!.text = finalSpeechResult
println("test$finalSpeechResult")
if (droidSpeech!!.continuousSpeechRecognition) {
val colorPallets1 = intArrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.CYAN, Color.MAGENTA)
val colorPallets2 = intArrayOf(Color.YELLOW, Color.RED, Color.CYAN, Color.BLUE, Color.GREEN)
// Setting random color pallets to the recognition progress view
droidSpeech!!.setRecognitionProgressViewColors(if (Random().nextInt(2) == 0) colorPallets1 else colorPallets2)
} else {
stop!!.visibility = View.GONE
start!!.visibility = View.VISIBLE
}
}
override fun onDroidSpeechClosedByUser() {
stop!!.visibility = View.GONE
start!!.visibility = View.VISIBLE
}
override fun onDroidSpeechError(errorMsg: String) {
// Speech error
stop!!.post { // Stop listening
stop!!.performClick()
}
}
// MARK: DroidSpeechPermissionsListener Method
override fun onDroidSpeechAudioPermissionStatus(audioPermissionGiven: Boolean, errorMsgIfAny: String) {
if (audioPermissionGiven) {
start!!.post { // Start listening
start!!.performClick()
}
} else {
if (errorMsgIfAny != null) {
// Permissions error
}
stop!!.post { // Stop listening
stop!!.performClick()
}
}
}
}
this is err message
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.example.Jachi3kki.DroidSpeechActivity.onCreateView(DroidSpeechActivity.kt:49)
DroidSpeechActivity.kt:49 line is this
start.setOnClickListener(this)
how to convert my AppCompatActivity to fragment?
Your code has some problems:
It's usually better to use the optional ? operator and don't force the cast with !! to avoid a crash by NullPointerException
You need to initialize your views in the onCreateView method by referring to the view instance.
Unlike activities, fragments don't call the setContentView method, so you can't refer directly to the layout items.
In my code I used the inline method setOnClickListener and I assumed that start and stop are Buttons,
if it's not the case you just need to change the type of the two views in their declaration.
Try to change your fragment's code like this:
class DroidSpeechActivity : Fragment(),
OnDSListener,
OnDSPermissionsListener {
val TAG = "Activity_DroidSpeech"
private var droidSpeech: DroidSpeech? = null
private var finalSpeechResult: TextView? = null
private var start: Button? = null
private var stop: Button? = null
// MARK: Activity Methods
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initializing the droid speech and setting the listener
droidSpeech = DroidSpeech(requireActivity().applicationContext, requireActivity().getFragmentManager()).apply {
setOnDroidSpeechListener(this)
setShowRecognitionProgressView(false)
setOneStepResultVerify(true)
setRecognitionProgressMsgColor(Color.WHITE)
setOneStepVerifyConfirmTextColor(Color.WHITE)
setOneStepVerifyRetryTextColor(Color.WHITE)
setPreferredLanguage("ko-KR")
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.activity_droid_speech, container, false)
finalSpeechResult = view.findViewById<TextView>(R.id.finalSpeechResult)
start = view.findViewById<Button>(R.id.start).apply {
setOnClickListener { startClicked() }
}
stop = view.findViewById<Button>(R.id.start).apply {
setOnClickListener { stopClicked() }
}
return view
}
override fun onPause() {
super.onPause()
if (stop?.visibility == View.VISIBLE) {
stop?.performClick()
}
}
override fun onDestroy() {
super.onDestroy()
if (stop?.visibility == View.VISIBLE) {
stop?.performClick()
}
}
private fun startClicked() {
droidSpeech?.startDroidSpeechRecognition()
// Setting the view visibilities when droid speech is running
start?.visibility = View.GONE
stop?.visibility = View.VISIBLE
}
private fun stopClicked() {
droidSpeech?.closeDroidSpeechOperations()
stop?.visibility = View.GONE
start?.visibility = View.VISIBLE
}
// MARK: DroidSpeechListener Methods
override fun onDroidSpeechSupportedLanguages(currentSpeechLanguage: String, supportedSpeechLanguages: List<String>) {
Log.i(TAG, "Current speech language = $currentSpeechLanguage")
Log.i(TAG, "Supported speech languages = $supportedSpeechLanguages")
if (supportedSpeechLanguages.contains("ko-KR")) {
// Setting the droid speech preferred language as tamil if found
droidSpeech?.setPreferredLanguage("ko-KR")
// Setting the confirm and retry text in tamil
droidSpeech?.setOneStepVerifyConfirmText("check")
droidSpeech?.setOneStepVerifyRetryText("no")
}
}
override fun onDroidSpeechRmsChanged(rmsChangedValue: Float) {
// Log.i(TAG, "Rms change value = " + rmsChangedValue);
}
override fun onDroidSpeechLiveResult(liveSpeechResult: String) {
Log.i(TAG, "Live speech result = $liveSpeechResult")
}
override fun onDroidSpeechFinalResult(finalSpeechResult: String) {
// Setting the final speech result
finalSpeechResult?.text = finalSpeechResult
println("test$finalSpeechResult")
if (droidSpeech?.continuousSpeechRecognition == true) {
val colorPallets1 = intArrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.CYAN, Color.MAGENTA)
val colorPallets2 = intArrayOf(Color.YELLOW, Color.RED, Color.CYAN, Color.BLUE, Color.GREEN)
// Setting random color pallets to the recognition progress view
droidSpeech?.setRecognitionProgressViewColors(if (Random().nextInt(2) == 0) colorPallets1 else colorPallets2)
} else {
stop?.visibility = View.GONE
start?.visibility = View.VISIBLE
}
}
override fun onDroidSpeechClosedByUser() {
stop?.visibility = View.GONE
start?.visibility = View.VISIBLE
}
override fun onDroidSpeechError(errorMsg: String) {
// Speech error
stop?.post { // Stop listening
stop?.performClick()
}
}
// MARK: DroidSpeechPermissionsListener Method
override fun onDroidSpeechAudioPermissionStatus(audioPermissionGiven: Boolean, errorMsgIfAny: String) {
if (audioPermissionGiven) {
start?.post { // Start listening
start?.performClick()
}
} else {
if (errorMsgIfAny != null) {
// Permissions error
}
stop?.post { // Stop listening
stop?.performClick()
}
}
}
}
Related
I am able to disable/enable the button for only one field, but not for
How to disable button if two or more editText is empty using viewmodel and livedata?
I have tried this function fun disableButton() {
isButtonEnabled.value =
!(login.value?.isBlank() == true && name.value?.isBlank() == true && password.value?.isBlank() == true && repeatPassword.value?.isBlank() == true)
}
class RegistrationVM #Inject constructor() : ViewModel() {
val isButtonEnabled = MutableLiveData<Boolean>()
val login = MutableLiveData<String>()
val loginError = MutableLiveData<String?>()
val name = MutableLiveData<String>()
val nameError = MutableLiveData<String?>()
val password = MutableLiveData<String>()
val passwordError = MutableLiveData<String?>()
val repeatPassword = MutableLiveData<String>()
val repeatPasswordError = MutableLiveData<String?>()
fun loginValidation(input: String) {
login.value = input
loginError.value = if (input.length < 8) "Minimum 8 character" else null
}
fun nameValidation(input: String) {
name.value = input
}
fun passwordValidation(input: String) {
password.value = input
passwordError.value = if (input.length < 8) "Minimum 8 character" else null
}
fun repeatPasswordValidation(input: String) {
repeatPassword.value = input
repeatPasswordError.value = if (input.length < 8) "Minimum 8 character" else null
}
}
class RegistrationFragment : Fragment(R.layout.fragment_registration) {
private val vm by viewModels<RegistrationVM>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val binding = FragmentRegistrationBinding.bind(view)
binding.loginInput.doAfterTextChanged {
vm.loginValidation(it.toString())
}
vm.loginError.observe(viewLifecycleOwner) {
binding.loginField.error = it
}
binding.nameInput.doAfterTextChanged {
vm.nameValidation(it.toString())
}
vm.nameError.observe(viewLifecycleOwner) {
binding.nameField.error = it
}
binding.passwordInput.doAfterTextChanged {
vm.passwordValidation(it.toString())
}
vm.passwordError.observe(viewLifecycleOwner) {
binding.passwordField.error = it
}
binding.repeatPasswordInput.doAfterTextChanged {
vm.repeatPasswordValidation(it.toString())
}
vm.repeatPasswordError.observe(viewLifecycleOwner) {
binding.repeatPasswordField.error = it
}
vm.isButtonEnabled.observe(viewLifecycleOwner) {
binding.createAccount.isEnabled = it
}
binding.createAccount.setOnClickListener {
Toast.makeText(requireContext(), "Account created", Toast.LENGTH_SHORT).show()
}
}
}
how are you?
If your objective is to monitor all fields to enable the button just if all required fields are filled, there is a more straightforward way to do it that doesn’t have to use ViewModel/LiveData.
First, you define a listener that will monitor the EditText changes. This listener will receive some parameters, one of them is the count, which is the count of chars on the EditText. We can use it to disable the button if the char count is equal to zero and, if it's different from zero, we check if all the other EditText is filled, if true, we can enable the button. So, the implementation of this listener will be like this:
private val controlButtonEnabledWhenTextChanged = { _: CharSequence?, _: Int, _: Int, count: Int ->
binding.buttonFirst.isEnabled = areAllFieldsFilled()
}
private fun areAllFieldsFilled(): Boolean {
return binding.firstName.text.isNotBlank() && binding.lastName.text.isNotBlank()
}
Then, you need to add this listener to all EditText you want to monitor:
binding.firstName.addTextChangedListener(onTextChanged = controlButtonEnabledWhenTextChanged)
binding.lastName.addTextChangedListener(onTextChanged = controlButtonEnabledWhenTextChanged)
This implementation is simpler to understand and I believe that it solves your problem.
I am building a video player app for Android TV. I am using Exoplayer leanback dependency as explained in https://developer.android.com/training/tv/playback/transport-controls.
So far I've been able to display the video title, which is static, but I need to display a subtitle that is dynamic, it changes whenever the video playing changes. How can I do it?
The image below shows how the video player looks like. I've used a subtitle phrase as a placeholder on where it should appear.
I was able to solve the problem. I added a listener in the VideoSupportFragment class, Player.EventListener.
This way:
class VideoFragment(mediaItems: Map<String, Any>) : VideoSupportFragment(), Player.EventListener {
private var playerAdapter: ExoPlayerAdapter? = null
private var _mediaItems: Map<String, Any>? = null
private lateinit var mMediaPlayerGlue: VideoMediaPlayerGlue<ExoPlayerAdapter>
private var mItems: List<*>? = null
init {
_mediaItems = mediaItems
}
private val mHost: VideoSupportFragmentGlueHost = VideoSupportFragmentGlueHost(this)
private fun playWhenReady(glue: PlaybackGlue) {
if (glue.isPrepared) {
glue.play()
} else {
glue.addPlayerCallback(object : PlaybackGlue.PlayerCallback() {
override fun onPreparedStateChanged(glue: PlaybackGlue) {
if (glue.isPrepared) {
glue.removePlayerCallback(this);
glue.play()
}
}
})
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val mediaSource = _mediaItems?.get("media_source") as Map<*, *>
playerAdapter = ExoPlayerAdapter(activity!!, _mediaItems!!)
mMediaPlayerGlue =
VideoMediaPlayerGlue(activity, playerAdapter!!)
mMediaPlayerGlue.host = mHost;
mMediaPlayerGlue.isControlsOverlayAutoHideEnabled = true
mItems = mediaSource["media_items"] as List<*>
mMediaPlayerGlue.title = mediaSource["title"] as CharSequence?
mMediaPlayerGlue.playerAdapter.setDataSource()
mMediaPlayerGlue.isSeekEnabled = true
playerAdapter?.player?.addListener(this);
playWhenReady(mMediaPlayerGlue)
}
override fun onPause() {
super.onPause()
playerAdapter?.player?.pause()
}
override fun onResume() {
super.onResume()
playerAdapter?.player?.play()
}
override fun onDestroy() {
super.onDestroy()
playerAdapter?.player?.removeListener(this);
}
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
if (mItems?.size!! > 1){
val item : Map<*, *> = mItems!![playerAdapter?.player?.currentWindowIndex!!] as Map<*, *>
mMediaPlayerGlue.subtitle = item["subtitle"] as String
}
}
}
1.Whenever I am swiping for next picture in my app, app crashed and I don't know what's going wrong
2.This problem getting after update to Android 30 before its working fine
java.lang.NoSuchMethodError: No virtual method contains(I)Z in class Landroid/util/SparseArray; or its super classes (declaration of 'android.util.SparseArray' appears in /system/framework/framework.jar!classes2.dex)
class PostViewFragment : DialogFragment() {
private var player: SimpleExoPlayer? = null
private lateinit var mediaDataSourceFactory: DataSource.Factory
//var post: FeedNodeModel? = null
private val STORAGE_PERMISSION_CODE = 100
private var post: FeedNodeModel? = null
var currentPos = 0
var registeredFragments = SparseArray<SidecarPagerFragment>()
var isFirstLoad = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.FullScreenDialogStyle)
isCancelable = true
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
/*if (createdView != null) {
return createdView
}*/
val view = inflater.inflate(R.layout.fragment_post_view, container, false)
//post = arguments?.getSerializable("post") as FeedNodeModel?
when (post?.__typename) {
"GraphImage",
"GraphStoryImage" -> {
Picasso.get()
.load(post?.sourceUrl)
.into(view.img_post)
view.img_post.visibility = View.VISIBLE
view.playerView.visibility = View.GONE
view.viewpager.visibility = View.GONE
}
"GraphVideo",
"GraphStoryVideo" -> {
Glide.with(requireContext())
.load(post?.thumbnailUrl)
.into(object : CustomTarget<Drawable>() {
override fun onLoadCleared(p0: Drawable?) {
}
override fun onResourceReady(p0: Drawable, p1: Transition<in Drawable>?) {
initializePlayer(view.playerView,
post?.sourceUrl)
}
})
view.img_post.visibility = View.GONE
view.playerView.visibility = View.VISIBLE
view.viewpager.visibility = View.GONE
}
"GraphSidecar" -> {
val calHeight =
(resources.displayMetrics.widthPixels *
(post?.feedNodeModel?.get(0)?.dimenHeight!!)) /
post?.feedNodeModel?.get(0)?.dimenWidth!!
view.txt_pager_count.text = "1/${post?.feedNodeModel?.size}"
view.viewpager.layoutParams.height = calHeight
view.viewpager.adapter = object : FragmentPagerAdapter(childFragmentManager,
FragmentStatePagerAdapter.POSITION_NONE) {
override fun getItem(p0: Int): Fragment {
val fragment = SidecarPagerFragment.create(post?.feedNodeModel?.get(p0))
registeredFragments.put(p0, fragment)
if (isFirstLoad) {
fragment.isFirstLoad = true
isFirstLoad = false
}
return fragment
}
override fun getCount(): Int = post?.feedNodeModel?.size!!
}
view.viewpager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
#RequiresApi(Build.VERSION_CODES.R)
override fun onPageSelected(position: Int) {
if (post?.feedNodeModel?.get(currentPos)?.__typename == "GraphVideo") {
registeredFragments[currentPos]?.onPause()
}
currentPos = position
view.txt_pager_count.text = "${currentPos+1}/${post?.feedNodeModel?.size}"
if (registeredFragments.contains(position)) {
registeredFragments[position]?.loadVideo()
}
}
})
view.viewpager.visibility = View.VISIBLE
view.img_post.visibility = View.GONE
view.playerView.visibility = View.GONE
}
}
App Crash On This Line
if (registeredFragments.contains(position)) {
registeredFragments[position]?.loadVideo()
}
Use containsKey
/** Returns true if the collection contains [key]. */
inline fun <T> SparseArray<T>.containsKey(key: Int) = indexOfKey(key) >= 0
Insight by my team leader Mike
The intuitive method contains(int key) was actually introduced in API 30, so it will crash older API devices. Very new methods don't give you a handy warning like depreciated methods, making them considerably more hazardous. Even if you target below 30 Android Studio will still compile contains() without protest.
The reference gives the following:
public boolean contains (int key):
Returns true if the key exists in the array. This is equivalent to indexOfKey(int) >= 0
You could use the indexOfKey() test equivalent, although personally I prefer testing for null with get():
get(key) != null
I had same error, but with containtsKey() method. This was happening only for Huawei P30 Pro with Api 30. Looks like they don't support it. I couldn't use
get(key) != null
because null is one of possible values.
Also contains(key) has been added in Api 30 according to this:
https://developer.android.com/reference/android/util/SparseArray#contains(int)
In this case it is better to stick to
indexOfKey(int) >= 0
which is available since Api 1.
Please use below code it worked with me.
if (registeredFragments.containsKey(position)) {
registeredFragments[position]?.loadVideo()
}
hope it will work with you also
I have a viewPager with CubeTransformer, which is transforming every fragment. And inside every fragment is Image or Video view (with Exoplayer). And when you are trying to change a framgnet with transformation, exoplayer losses preview (I've got a black screen), even it's not playing. But after you changing condition to normal, preview is coming back
Ohterwise, if you will remove pageTransformer, review is not dissapears. How to keep preview always on screen?
CubeTransformer
class CubeTransformer : ViewPager.PageTransformer {
override fun transformPage(view: View, position: Float) {
if (view.visibility != View.VISIBLE) return
view.apply {
cameraDistance = (view.width * distanceMultiplier).toFloat()
pivotX = if (position < 0f) view.width.toFloat() else 0f
pivotY = view.height * 0.5f
rotationY = 90f * position
if (position < -1 || position > 1) {
alpha = 0f // item not visible
} else {
alpha = 1f
}
}
}
private companion object {
private const val distanceMultiplier: Int = 20
}
}
VideoView
class VideoView(context: Context) : ConstraintLayout(context, null) {
private val player = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector(), DefaultLoadControl())
private val dataSourceFactory = DefaultDataSourceFactory(context, "android")
private lateinit var model: Model
init {
inflate(context, R.layout.story_item_video, this)
video_view.player = player
video_view.keepScreenOn = true
video_view.setBackgroundColor(Color.TRANSPARENT)
video_view.setShutterBackgroundColor(Color.TRANSPARENT)
}
fun setData(model: Model?) {
if (model== null) return
this.model = model
val mediaSource = HlsMediaSource
.Factory(dataSourceFactory)
.setExtractorFactory(DefaultHlsExtractorFactory())
.createMediaSource(Uri.parse(model.streamLink))
player.playWhenReady = true
player.prepare(mediaSource)
player.addListener(object: Player.EventListener {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
}
override fun onSeekProcessed() {}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {
}
override fun onPlayerError(error: ExoPlaybackException?) {
}
override fun onLoadingChanged(isLoading: Boolean) {
}
override fun onPositionDiscontinuity(reason: Int) {
}
override fun onRepeatModeChanged(repeatMode: Int) {
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
}
})
}
}
After a day of searching, I've found an answer to my question. You just need to add app:surface_type="texture_view" to your PlayerView
In hopes to better understand MVVM I decided to redo one of my Android projects implementing the architecture.
One of the activities uses the Zxing library to scan a QR code. Using Zxing's event handler I would like to pass the scanned result to my viewModel to check for example if the result is a "product"(this is a QR code I generate following a product class) or not. If the the result is a product it will show a dialogue with the result asking the user if they want to continue scanning or save the product, if it is not a product then it shows a dialogue with the result and a cancel button.
Now the issue here is that I don't know how to properly pass the data from Zxing's handler to the viewModel. Below attached my activity.
class QRreader_Activity : AppCompatActivity(), ZXingScannerView.ResultHandler, IQRreader{
override fun isProduct(ProductDetail: String) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun isNotProduct(ScannedText: String) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
lateinit var mScannerView: ZXingScannerView
var data: String="test"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_qrreader)
val bReturn: ImageButton = findViewById(R.id.ic_return)
bReturn.setOnClickListener {
onBackPressed() }
ActivityCompat.requestPermissions(this#QRreader_Activity,
arrayOf(Manifest.permission.CAMERA),
1)
val flashlightCheckBox = findViewById<CheckBox>(R.id.flashlight_checkbox)
val contentFrame = findViewById<ViewGroup>(R.id.content_frame)
mScannerView = object : ZXingScannerView(this) {
override fun createViewFinderView(context: Context): IViewFinder {
return CustomViewFinderView(context)
}
}
contentFrame.addView(mScannerView)
flashlightCheckBox.setOnCheckedChangeListener { compoundButton, isChecked -> mScannerView.flash = isChecked }
}
public override fun onResume() {
super.onResume()
mScannerView.setResultHandler(this) // Register ourselves as a handler for scan results.
mScannerView.startCamera() // Start camera on resume
}
public override fun onPause() {
super.onPause()
mScannerView.stopCamera() // Stop camera on pause
}
override fun onBackPressed() {
super.onBackPressed()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
//This is where ZXing provides the result of the scan
override fun handleResult(rawResult: Result) {
Toast.makeText(this,""+rawResult.text,Toast.LENGTH_LONG).show()
}
private class CustomViewFinderView : ViewFinderView {
val PAINT = Paint()
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init()
}
private fun init() {
PAINT.color = Color.WHITE
PAINT.isAntiAlias = true
val textPixelSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
TRADE_MARK_TEXT_SIZE_SP.toFloat(), resources.displayMetrics)
PAINT.textSize = textPixelSize
setSquareViewFinder(true)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
drawTradeMark(canvas)
}
private fun drawTradeMark(canvas: Canvas) {
val framingRect = framingRect
val tradeMarkTop: Float
val tradeMarkLeft: Float
if (framingRect != null) {
tradeMarkTop = framingRect.bottom.toFloat() + PAINT.textSize + 10f
tradeMarkLeft = framingRect.left.toFloat()
} else {
tradeMarkTop = 10f
tradeMarkLeft = canvas.height.toFloat() - PAINT.textSize - 10f
}
canvas.drawText(TRADE_MARK_TEXT, tradeMarkLeft, tradeMarkTop, PAINT)
}
companion object {
val TRADE_MARK_TEXT = ""
val TRADE_MARK_TEXT_SIZE_SP = 40
}
}
}
The solution I found was to have the view model implement "ZXingScannerView.ResultHandler" interface. I don't know if this is the optimal solution though.