我有一个想要在不同片段中播放的SoundPool。所以我在一个单例中加载它。我必须使用什么上下文?
object PingSoundPool {
fun loadpings(note: Int) {
val context = Application()
val mAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
val mSoundPool = SoundPool.Builder()
.setMaxStreams(9)
.setAudioAttributes(mAttributes)
.build()
val cping = mSoundPool.load(context, R.raw.cping, 1)
val dbping = mSoundPool.load(context, R.raw.dbping, 1)
[...]
if (note == 0) {}
if(note == 1)
mSoundPool.play(cping, 1f, 1f, 1, -1, 1f)
if(note == 2)
mSoundPool.play(dbping, 1f, 1f, 1, -1, 1f)
[...]
}
}
如果我这样使用它,可以像这样PingSoundPool.loadPings(0)
将其加载到活动的onCreate中,并使用PingSoundPool.loadPings(1)
在onClickListener中对其进行访问,不是吗?
在运行时,我得到了一个NullPointerExeption:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.soulfetch2/com.example.soulfetch2.FullscreenActivity}:
java.lang.NullPointerException: Attempt to invoke virtual method
'android.content.res.Resources android.content.Context.getResources()'
on a null object reference
该专家指出了val cping = mSoundPool.load(context, R.raw.cping, 1)
行
R.raw。文件存在,但无法以某种方式访问。我想我可能使用了错误的上下文。或者我以错误的方式实现了正确的上下文。
无论如何,帮助非常重要。
编辑:
最初的问题已解决,但仍然存在问题:每次尝试播放声音时,原样的代码都会重新加载SoundPool。 Hay有人知道如何分别加载它,这样PingSoundPool(this).loadPings(Int)
的调用只会播放声音而不重新加载所有内容?
另一件事:当我通过活动执行PingSoundPool(this).loadPings(Int)
时,一切正常。但是,从一个片段中,我得到一个TypeMismatch“ Required:Context,Found:MainFragment”。我可以使用PingSoundPool(this.requireContext()).loadPings(2)
或PingSoundPool(this.context!!).loadPings(2)
解决它,但这似乎并不是最好的选择。有什么建议吗?
这里是我现在使用的类,而不是对象:
class PingSoundPool(context: Context) {
val mAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_GAME)
.build()
val mSoundPool = SoundPool.Builder()
.setMaxStreams(9)
.setAudioAttributes(mAttributes)
.build()
val cping = mSoundPool.load(context, R.raw.cping, 1)
val dbping = mSoundPool.load(context, R.raw.dbping, 1)
fun loadPings(note: Int) {
if(note == 1)
mSoundPool.play(cping, 1f, 1f, 1, -1, 1f)
if(note == 2)
mSoundPool.play(dbping, 1f, 1f, 1, -1, 1f)
[...]
}
}
答案 0 :(得分:1)
您不应将SESSION
的实例创建为新的USER_ID
,而需要将现有的Application
传递给您的方法:
Context
如果您从Activity中调用该方法,只需传递Context
:
fun loadpings(note: Int, ctx: Context) {
...
val cping = mSoundPool.load(ctx, R.raw.cping, 1)
}
或者只是
this@YourActivity
答案 1 :(得分:1)
问题出在这一行:
val context = Application()
在这里,您正在创建一个不应使用的新Application
对象。您在这里有两个选择:
PingSoundPool
设为class
,而将Context
作为构造函数参数,并改为使用它:class PingSoundPool(private val context: Context) {
...
fun loadpings(note: Int) {
[...]
val cping = mSoundPool.load(context, R.raw.cping, 1)
val dbping = mSoundPool.load(context, R.raw.dbping, 1)
[...]
}
loadPings
接受Context
作为参数:fun loadPings(note: Int, context: Context) {
[...]
val cping = mSoundPool.load(context, R.raw.cping, 1)
val dbping = mSoundPool.load(context, R.raw.dbping, 1)
[...]
}
然后对方法1和2进行传递,将Application
/ Activity
/ Fragment
用作Context
。就我个人而言,我更喜欢方法1,因为它可以更好地扩展,如果将来您添加更多依赖Context
的方法。
希望有帮助!
答案 2 :(得分:1)
如果您是从活动的onCreate调用它的,为什么不还传递Context
作为参数?
功能如下:
fun loadPings(context: Context, note: Int) {
//val context = Application() //Remove this line
val cping = mSoundPool.load(context, R.raw.cping, 1) //Here it's used the parameter context
val dbping = mSoundPool.load(context, R.raw.dbping, 1)
[...]
}
在Activity的onCreate中,您可以通过以下方式调用它:
PingSoundPool.loadPings (this, 0)
编辑:
如果创建PingSoundPool对象,则不会在每次文件时都重新加载它:因此您可以在活动中执行此操作:
class YourActivity ... {
companion object { //So it is accesible from other classes with YourActivity.pingSoundPool
lateinit var pingSoundPool: PingSoundPool;
}
@Override
... onCreate(...) {
pingSoundPool = PingSoundPool(this)
...
}
}
然后,如果您需要播放声音(我愿意更改功能名称),则可以使用
pingSoundPool.load(1) // Inside of YourActivity
YourActivity.pingSoundPool.load(1) // Outside of YourActivity
这样,我也解决了您的最后一个问题,但是也许您想知道如何从Context
传递正确的Fragment
对象:在您的Fragment
中,您可以声明一个{ {1}}对象(或Context
对象,它是YourActivity
的子对象),并通过以下方式通过Context
方法为其分配值:
onAttach(..)
然后在片段内可以调用class YourFragment ... {
private lateinit var mContext : Context
private lateinit var mActivity : YourActivity // You don't need both
override fun onAttach(context: Context?) {
super.onAttach(context)
mContext = context!!
if (context is YourActivity)
mActivity = context
}
}
(或PingSoundPool(mContext)
)。
请注意,PingSoundPool(mActivity)
在任何其他回调方法之前被调用,在onAttach
之前也被调用。
您还可以使用onCreateView
(在Kotlin中仅为getContext()
)获得Fragment上下文,但是我认为上述解决方案更好,更安全。