Kotlin:RecyclerView with SoundPool runtime error - android

I am getting a runtime error: No Value passed for parameter 'soundToInit'in my SecondAdapter class.
My SecondAdapter is an Adapter to a RecyclerView declared in SecondActivity.
SecondAdapter class:
class SecondAdapter(val content:Array<String>) : RecyclerView.Adapter<SecondCustomViewGolder>(){
//var lessons = arrayOf("Satu", "Dua", "Tiga", "Empat", "Lima", "Enam", "Tujuh",
// "Lapan", "Sembilan")
var soundList = arrayOf(R.raw.sound1, R.raw.sound2,R.raw.sound1, R.raw.sound2,
R.raw.sound1, R.raw.sound2,R.raw.sound1, R.raw.sound2,
R.raw.sound1)
override fun getItemCount(): Int {
return content.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SecondCustomViewGolder {
var layoutInflater = LayoutInflater.from(parent.context)
var cellForRow = layoutInflater.inflate(R.layout.lesson_row, parent, false)
return SecondCustomViewGolder(cellForRow)
}
override fun onBindViewHolder(holder: SecondCustomViewGolder, position: Int) {
var soundToLoad = SoundEngine()
holder.soundToInit = soundToLoad.load(SecondViewActivity(), soundList.get(position), 1)
}
}
class SecondCustomViewGolder(var viewTwo : View, var soundToInit:Int) : RecyclerView.ViewHolder(viewTwo){
init {
var soundToPlay = SoundEngine()
soundToPlay.play(soundToInit, 1F, 1F,1,0, 1F)
}
}
SoundEngine:
class SoundEngine {
private var soundPool: SoundPool
init {
soundPool = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val audioAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
SoundPool.Builder()
.setMaxStreams(1)
.setAudioAttributes(audioAttributes)
.build()
} else {
SoundPool(1, AudioManager.STREAM_MUSIC, 0)
}
}
fun load(context: Context, rawId: Int, priority: Int):Int {
return soundPool.load(context, rawId, priority)
}
fun play(soundID: Int, leftVolume: Float, rightVolume: Float, priority: Int, loop: Int, rate: Float) {
soundPool.play(soundID, leftVolume, rightVolume, priority, loop, rate)
}
}
Please give me some pointers... Thank in advance...

Change your Holder like below
class SecondCustomViewGolder(var viewTwo : View) : RecyclerView.ViewHolder(viewTwo) {
private var soundEngine = SoundEngine()
fun loadAndPlaySound(soundIdToPlay:Int, priority: Int) {
val soundToPlay = soundEngine.load(viewTwo.context, soundIdToPlay, priority)
soundEngine.play(soundToPlay, 1F, 1F, 1, 0, 1F)
}
}
And call it like below:
override fun onBindViewHolder(holder: SecondCustomViewGolder, position: Int) {
holder.loadAndPlaySound(soundList.get(position), 1)
}

Related

Lazy Loading for the images in Recycler view

i am not able to do the lazy loading for the images
this is my code of the adapter. I am providing it all the urls from my database in the form of list please help
class Horizontal_lower_recycler(private val images:List<Image>,private val context: Context,private val recyclerView: RecyclerView):
RecyclerView.Adapter<Horizontal_lower_recycler.MyViewHolder>() {
private var isLoading = false
init {
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
if (!isLoading) {
if (visibleItemCount + firstVisibleItemPosition >= totalItemCount
&& firstVisibleItemPosition >= 0
&& totalItemCount >= PAGE_SIZE
) {
isLoading = true
}
}
}
})
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val image1: ImageView = itemView.findViewById(R.id.lower_image1)
val image2: ImageView = itemView.findViewById(R.id.lower_image2)
val image3: ImageView = itemView.findViewById(R.id.lower_image3)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(
R.layout.bootm_recycler,
parent, false
)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return images.size / 3 + images.size % 3
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val images = images.subList(position * 3, min(position * 3 + 3, images.size))
for (i in images.indices) {
when (i) {
0 -> {
Glide.with(holder.itemView).load(images[i].url).apply(RequestOptions().format(
DecodeFormat.PREFER_RGB_565).disallowHardwareConfig())
.into(holder.image1)
holder.image1.setOnClickListener {
val intent = Intent(context, image_full_size_avtivity::class.java)
intent.putExtra("url", images[i].url)
context.startActivity(intent)
}
}
1 -> {
Glide.with(holder.itemView).load(images[i].url).apply(RequestOptions().format(
DecodeFormat.PREFER_RGB_565).disallowHardwareConfig())
.into(holder.image2)
holder.image2.setOnClickListener {
val intent = Intent(context, image_full_size_avtivity::class.java)
intent.putExtra("url", images[i].url)
context.startActivity(intent)
}
}
2 -> {
Glide.with(holder.itemView).load(images[i].url).apply(RequestOptions().format(
DecodeFormat.PREFER_RGB_565).disallowHardwareConfig())
.into(holder.image3)
holder.image3.setOnClickListener {
val intent = Intent(context, image_full_size_avtivity::class.java)
intent.putExtra("url", images[i].url)
context.startActivity(intent)
}
}
}
}
}
}
Help me in doing the lazy loading. When i open the app all the images are loaded at once without scrolling the recycler view.

When i refresh my pagelist, My items in PageAdapter will be misplaced for a short time

As above pic show, The items will be misplaced momently while i refresh.
smartRefresh.setOnRefreshListener {
mViewModel.observeComposition(ConnectivityUtil.isNetworkReachable(this),mLabelId.toInt(),lifecycleScope).observe(this, Observer {
mCompositionAdapter.submitList(it)
smartRefresh.finishRefresh()
})
}
My Adapter
class CompositionsAdapter(context: Context) : PagedListAdapter<CompositionAbstract, CompositionsAdapter.ViewHolder>(CompositionAbstractDiffCallback()) {
private val mScreenWidth by lazy {
val displayMetrics = DisplayMetrics()
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
windowManager.defaultDisplay.getRealMetrics(displayMetrics)
displayMetrics.widthPixels
}
val width by lazy {
(mScreenWidth - 15.px * 3) / 2
}
val height by lazy {
val srcWidth = 165f.px
val srcHeight = 155f.px
width * (srcHeight / srcWidth)
}
class ViewHolder(private val binding: HomepageItemGroupCompositionBinding)
: RecyclerView.ViewHolder(binding.root) {
fun bind(item: CompositionAbstract) {
binding.apply {
composition = item.briefComposition
itemView.setOnClickListener {
ARouter.getInstance().build(HomePageArouterConstants.PATH_AUDIO_PLAYER).withString(HomePageArouterConstants.KEY_ID, item.briefComposition.id).navigation()
}
executePendingBindings()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = HomepageItemGroupCompositionBinding.inflate(LayoutInflater.from(parent.context))
binding.imageView.layoutParams = LinearLayout.LayoutParams(width, height.toInt())
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
getItem(position)?.let {
holder.bind(it)
}
}
}
My Itemdecoration
class GridSpacingItemDecoration(private val spanCount: Int,
private val verticalSpacing: Int,
private val topSpacing: Int
) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val position = parent.getChildAdapterPosition(view)
if (position / spanCount == 0) {
outRect.top = topSpacing
}
if (position % spanCount == 1) {
outRect.left = 7.px
}
outRect.bottom = verticalSpacing
}
}
My diffUtil
class CompositionAbstractDiffCallback : DiffUtil.ItemCallback<CompositionAbstract>() {
override fun areItemsTheSame(oldItem: CompositionAbstract, newItem: CompositionAbstract): Boolean {
return oldItem.briefComposition.id == newItem.briefComposition.id
}
override fun areContentsTheSame(oldItem: CompositionAbstract, newItem: CompositionAbstract): Boolean {
return oldItem == newItem
}
}
Any ideas for this problem? Thanks for first!

Making an Intent on a selected GridLayout position

I am trying to create a method that will listen to the item that is clicked and if the category is clicked, it should open the activity selected. I have a Grid Layout setup, but I am not really sure how I would set an onClickListener or an onRecyclerViewItemClick for this purpose. I do have a pseudocode that I believe could be implemented, but would need guidance for this.
Here is my MainActivity.kt:
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var appBarConfiguration: AppBarConfiguration
private var mAuthListener : FirebaseAuth.AuthStateListener? = null
lateinit var myApi: IMyAPI
lateinit var txt_user_name:TextView
lateinit var txt_email_address:TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
myApi = RetrofitClient.getInstance().create(IMyAPI::class.java)
Log.d("__MAIN__", "OnCreate")
}
private fun initView() {
recycler_view.layoutManager = GridLayoutManager(this, 2)
recycler_view.addItemDecoration(GridItemDecoration(10, 2))
val categoryListAdapter = CategoryListGridRecyclerAdapter()
recycler_view.adapter = categoryListAdapter
categoryListAdapter.setProductList(generateDummyData())
val navView: NavigationView = findViewById(R.id.nav_view)
navView.setNavigationItemSelectedListener(this)
navView.bringToFront()
}
private fun generateDummyData(): List<Category> {
val listOfCategory = mutableListOf<Category>()
var categoryModel = Category(1, "Products", R.drawable.kumo_logo, 1.90)
listOfCategory.add(categoryModel)
categoryModel = Category(2, "Food", R.drawable.kumo_logo, 1.90)
listOfCategory.add(categoryModel)
categoryModel = Category(3, "Technology", R.drawable.kumo_logo, 1.90)
listOfCategory.add(categoryModel)
categoryModel = Category(4, "News", R.drawable.kumo_logo, 1.90)
listOfCategory.add(categoryModel)
categoryModel = Category(5, "Economy", R.drawable.kumo_logo, 1.90)
listOfCategory.add(categoryModel)
categoryModel = Category(6, "Sports", R.drawable.kumo_logo, 1.90)
listOfCategory.add(categoryModel)
return listOfCategory
}
//Pseudocode:
/*override fun onRecyclerViewItemClick(category: Category, position: Int)
{
lateinit var catClick: Intent
if(category.id == 1)
{
catClick = Intent(this, ShowProducts::class.java)
}
startActivity(catClick) //start activity selected
}*/
override fun onNavigationItemSelected(item: MenuItem):Boolean {
when (item.itemId) {
R.id.nav_sign_out -> {
Log.d("Testing logout ", "user")
FirebaseAuth.getInstance().signOut()
startActivity(Intent(this#MainActivity, LoginActivity::class.java))
finish()
}
}
return true
}
}
GridItemDecoration.kt:
class GridItemDecoration(gridSpacingPx: Int, gridSize: Int) : RecyclerView.ItemDecoration() {
private var mSizeGridSpacingPx: Int = gridSpacingPx
private var mGridSize: Int = gridSize
private var mNeedLeftSpacing = false
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val frameWidth = ((parent.width - mSizeGridSpacingPx.toFloat() * (mGridSize - 1)) / mGridSize).toInt()
val padding = parent.width / mGridSize - frameWidth
val itemPosition = (view.getLayoutParams() as RecyclerView.LayoutParams).viewAdapterPosition
if (itemPosition < mGridSize) {
outRect.top = 0
} else {
outRect.top = mSizeGridSpacingPx
}
if (itemPosition % mGridSize == 0) {
outRect.left = 0
outRect.right = padding
mNeedLeftSpacing = true
} else if ((itemPosition + 1) % mGridSize == 0) {
mNeedLeftSpacing = false
outRect.right = 0
outRect.left = padding
} else if (mNeedLeftSpacing) {
mNeedLeftSpacing = false
outRect.left = mSizeGridSpacingPx - padding
if ((itemPosition + 2) % mGridSize == 0) {
outRect.right = mSizeGridSpacingPx - padding
} else {
outRect.right = mSizeGridSpacingPx / 2
}
} else if ((itemPosition + 2) % mGridSize == 0) {
mNeedLeftSpacing = false
outRect.left = mSizeGridSpacingPx / 2
outRect.right = mSizeGridSpacingPx - padding
} else {
mNeedLeftSpacing = false
outRect.left = mSizeGridSpacingPx / 2
outRect.right = mSizeGridSpacingPx / 2
}
outRect.bottom = 0
}
}
CategoryListGridRecyclerAdapter.kt
class CategoryListGridRecyclerAdapter:RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var listOfCategory = listOf<Category>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return CategoryListViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.product_row, parent, false))
}
override fun getItemCount(): Int = listOfCategory.size
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
val productViewHolder = viewHolder as CategoryListViewHolder
productViewHolder.bindView(listOfCategory[position])
}
fun setProductList(listOfCategory: List<Category>) {
this.listOfCategory = listOfCategory
notifyDataSetChanged()
}
}
You can do something like this:
lateinit var mOnItemClickListener: (category: Category,pos: Int)-> Unit
fun setOnItemClickListener(callback: (category: Category,pos: Int)-> Unit){
mOnItemClickListener = callback
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return CategoryListViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.product_row, parent, false))
.listen {pos,_ ->
if(::mOnItemClickListener.isInitialized){
mOnItemClickListener(listOfCategory[pos],pos)
}
}
}
//I took this code from a post a while back, don't know the author
fun <T : RecyclerView.ViewHolder> T.listen(event: (position: Int, type: Int) -> Unit): T {
itemView.setOnClickListener {
event.invoke(adapterPosition, itemViewType)
}
return this
}
On MainActivity
categoryListAdapter.setOnItemClickListener { category, pos ->
...
}

LinearLayout is not drawing though onDraw is called

I'm building an MultiStateToggle Button.
To highlight the selected state, I need to draw a rectangle which is exactly the size of a button. This rectangle slides to the current state. Therefore I need to draw, but whatever I do, I do not see any change even though onDraw was called.
The superclass ToggleButton simply holds some constants. It extends LinearLayout!
Does anybody know, why drawing does not work in this LinearLayout sub-class?
class MultiStateToggleButton : ToggleButton {
//region Variables
private val mHighlightPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
#DrawableRes
private val iSelectableItemBackgroundDrawableResId: Int
private val mButtons = mutableListOf<Button>()
//endregion
constructor(context: Context) : this(context, Any() as AttributeSet)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
val mTypedValue = TypedValue()
context.theme.resolveAttribute(R.attr.colorPrimary, mTypedValue, true)
val iPrimaryColor = mTypedValue.data
context.theme.resolveAttribute(R.attr.colorPrimary, mTypedValue, true)
val iPrimaryDarkColor = mTypedValue.data
setBackgroundColor(iPrimaryDarkColor)
context.theme.resolveAttribute(R.attr.colorAccent, mTypedValue, true)
val iAccentColor = mTypedValue.data
val mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.MultiStateToggleButton)
foregroundColor = mTypedArray.getColor(R.styleable.MultiStateToggleButton_foregroundColor, iPrimaryColor)
highlightColor = mTypedArray.getColor(R.styleable.MultiStateToggleButton_highlightColor, iAccentColor)
val mTexts = mTypedArray.getTextArray(R.styleable.MultiStateToggleButton_elements)
if (mTexts != null) {
val iSelectedElement = mTypedArray.getInt(R.styleable.MultiStateToggleButton_selectedElement, 0)
setElements(Array(mTexts.size) { i ->
mTexts[i].toString()
}, iSelectedElement)
}
mTypedArray.recycle()
}
init {
val mTypedValue = TypedValue()
context.theme.resolveAttribute(android.R.attr.selectableItemBackground, mTypedValue, true)
iSelectableItemBackgroundDrawableResId = mTypedValue.resourceId
mHighlightPaint.apply {
color = highlightColor
style = Paint.Style.FILL
}
}
//region Public Variables
override var selectedElement: Int = 0
set(value) {
selectButton(value)
field = value
super.selectedElement = value
}
//endregion
//region Methods
fun setElements(texts: Array<String>) {
removeAllViews()
mButtons.clear()
texts.forEachIndexed { i, text ->
val mButton = Button(context).apply {
layoutParams = LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, LAYOUT_WEIGHT_EQUAL)
setBackgroundResource(iSelectableItemBackgroundDrawableResId)
setText(text)
setTextColor(textColor)
setOnClickListener { selectedElement = i }
}
mButtons.add(mButton)
addView(mButton)
}
}
fun setElements(texts: Array<String>, selectedItem: Int) {
setElements(texts)
selectButton(selectedItem)
}
override fun setEnabled(enabled: Boolean) {
for (i in 0 until childCount) {
getChildAt(i).isEnabled = enabled
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawRect(0f, 0f, 30f, 30f, mHighlightPaint)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
setWillNotDraw(false)
}
override fun onSaveInstanceState(): Parcelable {
return Bundle().apply {
putParcelable(KEY_INSTANCE_STATE, super.onSaveInstanceState())
putInt(KEY_SELECTED_BUTTON, selectedElement)
}
}
override fun onRestoreInstanceState(state: Parcelable?) {
var mRestoredState: Parcelable? = state
if (state is Bundle) {
selectButton(state.getInt(KEY_SELECTED_BUTTON))
mRestoredState = state.getParcelable(KEY_INSTANCE_STATE)
}
super.onRestoreInstanceState(mRestoredState)
}
private fun selectButton(position: Int) {
if (mButtons.isNotEmpty()) {
if (position >= mButtons.size) {
throw IndexOutOfBoundsException("Position was $position but there are only ${mButtons.size} Buttons.")
}
getChildAt(selectedElement).isEnabled = true
getChildAt(position).isEnabled = false
invalidate()
}
}
//endregion
companion object {
private const val KEY_SELECTED_BUTTON = "mtb_selected_button"
private const val KEY_INSTANCE_STATE = "mtb_instance_state"
}
}
As Kotlins' init block is called on Primary Constructor call, my Paint was not initialized.

Attempt to invoke virtual method 'void android.graphics.Canvas.drawText()' on a null object reference

i want to draw text on screen, but i received a error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawText(java.lang.String, float, float, android.graphics.Paint)' on a null object reference
my code:
package com.example.root.runningmanv2
import android.content.Context
import android.graphics.Paint
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.SurfaceView
import android.view.WindowManager
class GamingActivity : AppCompatActivity() {
private lateinit var gameView: SurfaceGame
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//set fullscreen
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN)
gameView = SurfaceGame(this)
setContentView(gameView)
}
override fun onPause() {
super.onPause()
}
override fun onResume() {
super.onResume()
gameView.start()
}
inner class SurfaceGame(context: Context): SurfaceView(context), Runnable{
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
val ourHolder = holder
val canvas = ourHolder.lockCanvas()
fun start(){
val thread = Thread(this)
thread.start()
}
override fun run() {
drawFigure()
}
fun drawFigure(){
paint.setARGB(255, 255, 255, 255)
canvas.drawText("Hello", 500f, 500f, paint)
ourHolder.unlockCanvasAndPost(canvas)
}
}
}
How to do fix it?
Instead of getting the holder in the SurfaceGame class yourself get it from SurfaceView.Callback
class GamingActivity : SurfaceHolder.Callback, AppCompatActivity() {
private var holder: SurfaceHolder? = null
private var pos = 0
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val view = SurfaceView(this)
setContentView(view)
view.holder.addCallback(this)
}
override fun surfaceCreated(holder: SurfaceHolder) {
this.holder = holder
pos = 0
Thread({
while (this.holder != null) {
drawFigure(this.holder)
Thread.sleep(100)
}
}).start()
}
override fun surfaceChanged(holder: SurfaceHolder, frmt: Int, w: Int, h: Int) {
this.holder = holder
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
this.holder = null
}
private fun drawFigure(holder: SurfaceHolder?) {
if (holder == null) return
val canvas = holder.lockCanvas()
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.setARGB(255, 0, 0, 0)
paint.textSize = 96f
canvas.drawText("Hello", 100f + pos, 500f, paint)
pos++
holder.unlockCanvasAndPost(canvas)
}
}

Categories

Resources