fun main() {
val myPhone = Myphone()
myPhone.phoneOn()
myPhone.onClick()
myPhone.onTouch()
myPhone.openApp()
myPhone.closeApp()
myPhone.brightMax()
myPhone.Something1.something()
}
interface Application {
var appName: String
var x1: Int
fun something()
fun brightMax() {
println("Brightness level is on Max!")
}
fun openApp() {
println("$appName is opening!")
}
fun phoneOn() {
println("The phone is ON")
}
fun onClick() {
println("App is running")
}
fun closeApp() {
println("${Myphone.Something1.appName} App is closed!")
}
}
interface Button {
val x: Int
var helloMessage: String
fun brightMax() {
println("Brightness is on $x")
}
fun phoneOn() {
println("Power on button was pressed!")
}
fun onClick()
fun onTouch() {
println("The screen was touched!")
}
}
class Myphone: Button, Application {
override fun something() {
println("Doing something")
}
object Something1 : Application {
override var x1: Int = 100
override var appName: String = "Instagram"
override fun something() {
println("He wants to die!")
}
}
override var x1: Int = 12
override var appName: String = "Facebook"
override var x: Int = 100
override fun phoneOn() {
super<Application>.phoneOn()
}
override fun brightMax() {
super<Application>.brightMax()
super<Button>.brightMax()
}
override var helloMessage: String = "Hello"
override fun onClick() {
super.onClick()
}
}
I created object inside the class and I can't "call" it back in main function.
Once I did and I can't remember how to solve it again.
Don't blame me because of code. I made it for presentation.
on the 9th line, there is error, why? the something1 has red line in kotlin.
something1.appName - is working perfectly?
You get the error because it's not recommended to access nested objects via instance references. Use Myphone.Something1.something() instead of myPhone.Something1.something().
Related
Adapter class
class AppListAdapter(private val context: Context, initialChecked: ArrayList<String> = arrayListOf()) : RecyclerView.Adapter<AppListAdapter.AppViewHolder>() {
public val appList = arrayListOf<ApplicationInfo>()
private val checkedAppList = arrayListOf<Boolean>()
private val packageManager: PackageManager = context.packageManager
init {
context.packageManager.getInstalledApplications(PackageManager.GET_META_DATA).sortedBy { it.loadLabel(packageManager).toString() }.forEach { info ->
if (info.packageName != context.packageName) {
if (info.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
appList.add(info)
checkedAppList.add(initialChecked.contains(info.packageName))
}
}
}
}
inner class AppViewHolder(private val item: ItemAppBinding) : RecyclerView.ViewHolder(item.root) {
fun bind(data: ApplicationInfo, position: Int) {
item.txApp.text = data.loadLabel(packageManager)
item.imgIcon.setImageDrawable(data.loadIcon(packageManager))
item.cbApp.isChecked = checkedAppList[position]
item.cbApp.setOnCheckedChangeListener { _, checked ->
checkedAppList[position] = checked
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder {
return AppViewHolder(ItemAppBinding.inflate(LayoutInflater.from(context), parent, false))
}
override fun onBindViewHolder(holder: AppViewHolder, position: Int) {
holder.bind(appList[position], position)
}
override fun getItemCount(): Int {
return appList.size
}
on MainActivity
binding.searchView2.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
binding.searchView2.clearFocus()
// how to write code filtered by query?
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
// how to write code filtered by newText?
return false
}
})
I'm newbie in kotlin..anyone can help?
I believe you want to filter items with "ApplicationInfo.txApp", so i will write the code for it.
First you need your adapter class to extend Filterable like below, and add one more list to hold all items:
class AppListAdapter(private val context: Context, initialChecked: ArrayList<String> = arrayListOf()) : RecyclerView.Adapter<AppListAdapter.AppViewHolder>(), Filterable {
public val appList = arrayListOf<ApplicationInfo>()
public val appListFull = ArrayList<ApplicationInfo>(appList)
// This full list because of when you delete all the typing to searchView
// so it will get back to that full form.
Then override it's function and write your own filter to work, paste this code to your adapter:
override fun getFilter(): Filter {
return exampleFilter
}
private val exampleFilter = object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults? {
val filteredList: ArrayList<ApplicationInfo> = ArrayList()
if (constraint == null || constraint.isEmpty()) {
// when searchview is empty
filteredList.addAll(appListFull)
} else {
// when you type something
// it also uses Locale in case capital letters different.
val filterPattern = constraint.toString().lowercase(Locale.getDefault()).trim()
for (item in appListFull) {
val txApp = item.txApp
if (txApp.lowercase(Locale.getDefault()).contains(filterPattern)) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}
#SuppressLint("NotifyDataSetChanged") #Suppress("UNCHECKED_CAST")
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
appList.clear()
appList.addAll(results!!.values as ArrayList<ApplicationInfo>)
notifyDataSetChanged()
}
}
And finally call this filter method in your searchview:
binding.searchView2.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
yourAdapter.filter.filter(query)
yourAdapter.notifyDataSetChanged()
binding.searchView2.clearFocus()
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
yourAdapter.filter.filter(newText)
yourAdapter.notifyDataSetChanged()
return false
}
})
These should work i'm using something similar to that, if not let me know with the problem.
i want to if i press play - the audio start playing, but if I will turn off the internet after some time, I can still listen to the audio to the end, how can i do this using andoid-mediaPlayer?
in kotlin
class MusicService:Service(),MediaPlayer.OnPreparedListener,MediaPlayer.OnCompletionListener,MediaPlayer.OnErrorListener {
override fun onBind(intent: Intent?): IBinder? {
return musicBind
}
override fun onCreate() {
super.onCreate()
player= MediaPlayer()
}
fun initMusic(){
player.setWakeMode(applicationContext,PowerManager.PARTIAL_WAKE_LOCK)
player.setAudioStreamType(AudioManager.STREAM_MUSIC)
player.setOnPreparedListener(this)
player.setOnCompletionListener(this)
player.setOnErrorListener(this)
}
override fun onUnbind(intent: Intent?): Boolean {
player.stop()
player.reset()
player.release()
return false
}
inner class MusicBinder:Binder(){
val service: MusicService
get() = this#MusicService
}
companion object{
const val STOPPED = 0
const val PAUSED =1
const val PLAYING = 2
}
override fun onPrepared(mp: MediaPlayer?) {
mp!!.start()
val duration=mp.duration
seekBar.max=duration
seekBar.postDelayed(progressRunner,instentval.toLong())
end_point.text= String.format("%d:%02d",TimeUnit.MILLISECONDS.toMinutes(duration.toLong()),
TimeUnit.MILLISECONDS.toSeconds(duration.toLong())-
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration.toLong())))
}
private fun playSong(){
try {
player.reset()
val playSong=songs
val uri = playSong.link
player=MediaPlayer.create(this, Uri.parse(uri))
try {
player.start()
progressRunner.run()
}catch (e:HttpException){
Toast.makeText(this,"Http went wrong!",Toast.LENGTH_SHORT).show()
}
} catch (e:Exception){
Toast.makeText(this,"something went wrong!",Toast.LENGTH_SHORT).show()
}
}
fun setUI(seekBar: SeekBar,start_int:TextView,end_int:TextView){
this.seekBar=seekBar
start_point=start_int
end_point=end_int
seekBar.setOnSeekBarChangeListener(object :SeekBar.OnSeekBarChangeListener
{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser){
player.seekTo(progress)
}
start_point.text = String.format(
"%d:%02d",TimeUnit.MILLISECONDS.toMinutes(progress.toLong()),
TimeUnit.MILLISECONDS.toSeconds(progress.toLong())-
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(progress.toLong())))
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
TODO("Not yet implemented")
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
TODO("Not yet implemented")
}
}
)
}
private var progressRunner:Runnable = object :Runnable {
override fun run() {
if (seekBar!=null){
seekBar.progress=player.currentPosition
if (player.isPlaying){
seekBar.postDelayed(this,instentval.toLong())
}
}
}
}
fun setSong(result: Result){
songs=result
playerState= PLAYING
playSong()
}
fun setSongmp3(mp3: Mp3){
songsmp3=mp3
playerState= PLAYING
playSongmp3()
}
public fun puseSong()
{
player.pause()
playerState = PAUSED
}
public fun resumeSong(){
player.start()
playerState= PLAYING
}
override fun onCompletion(mp: MediaPlayer?) {
}
override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
return false
}
}
I've got such code for searching streams by their name.
compositeDisposable.add(Observable.create(ObservableOnSubscribe<String> { subscriber ->
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextChange(newText: String?): Boolean {
subscriber.onNext(newText!!)
return false
}
override fun onQueryTextSubmit(query: String?): Boolean {
subscriber.onNext(query!!)
return false
}
})
})
.debounce(250, TimeUnit.MILLISECONDS)
.distinct()
.subscribe { text ->
val pagerPos = binding.streamsPager.currentItem
val currentFragment =
activity?.supportFragmentManager?.findFragmentByTag("f${pagerAdapter.getItemId(pagerPos)}")
(currentFragment as StreamFragment).onSearchHolder.onSearch(text)
}
)
It works fine with onQueryTextSubmit, but ignores setOnQueryTextListener. So when I want to erase symbols and "reset" search I get nothing
How to fix this?
use a wrapper class for your ObservableOnSubscribe and sealed class for your search events. Like this:
class SearchViewWrapper(private val searchView: SearchView) : ObservableOnSubscribe<SearchViewEvent> {
override fun subscribe(emitter: ObservableEmitter<SearchViewEvent>) {
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
emitter.onNext(SearchViewEvent.onQueryTextSumbit(query))
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
emitter.onNext(SearchViewEvent.onQueryChanged(newText))
return true
}
})
}
}
Sealed class for events:
sealed class SearchViewEvent {
data class onQueryChanged(val text: String?): SearchViewEvent()
data class onQueryTextSumbit(val query: String?): SearchViewEvent()
}
Try to use it where you need(just example):
fun useIt(searchView: SearchView) {
Observable.create(SearchViewWrapper(searchView))
.subscribe(::handleSearchViewEvent)
.addTo(yourCompositeDisposable)
}
private fun handleSearchViewEvent(event: SearchViewEvent) {
when (event) {
is SearchViewEvent.onQueryChanged -> TODO()
is SearchViewEvent.onQueryTextSumbit -> TODO()
}
}
I am trying to listen to my ViewModels MutableStateFlow from my FlutterSceneView. But I get the following error when trying to set the listener from the views init:
Suspend function 'listenToBackgroundColor' should be called only from a coroutine or another suspend function
class FlutterSceneView(context: Context, private val viewModel: FlutterSceneViewModelType): PlatformView {
private val context = context
private val sceneView = SceneView(context)
init {
listenToBackgroundColor() // Error here
}
private suspend fun listenToBackgroundColor() {
viewModel.colorFlow.collect {
val newColor = Color.parseColor(it)
sceneView.setBackgroundColor(newColor)
}
}
}
My ViewModel:
interface FlutterSceneViewModelType {
var colorFlow: MutableStateFlow<String>
}
class FlutterSceneViewModel(private val database: Database): FlutterSceneViewModelType, ViewModel() {
override var colorFlow = MutableStateFlow<String>("#FFFFFF")
init {
listenToBackgroundColorFlow()
}
private fun listenToBackgroundColorFlow() {
database.backgroundColorFlow.watch {
colorFlow.value = it.hex
}
}
}
the .watch call is a helper I have added so that this can be exposed to iOS using Kotlin multi-platform, it looks as follows but I can use collect instead if necessary:
fun <T> Flow<T>.asCommonFlow(): CommonFlow<T> = CommonFlow(this)
class CommonFlow<T>(private val origin: Flow<T>) : Flow<T> by origin {
fun watch(block: (T) -> Unit): Closeable {
val job = Job()
onEach {
block(it)
}.launchIn(CoroutineScope(Dispatchers.Main + job))
return object : Closeable {
override fun close() {
job.cancel()
}
}
}
}
I resolved this by using viewModel context:
private fun listenToBackgroundColor() {
viewModel.colorFlow.onEach {
val newColor = Color.parseColor(it)
sceneView.setBackgroundColor(newColor)
}.launchIn(viewModel.viewModelScope)
}
I had to import the following into my ViewModel:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
from:
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")
I want to test a method of my ViewModel that collects a Flow. Inside the collector a LiveData object is mutated, which I want to check in the end. This is roughly how the setup looks:
//Outside viewmodel
val f = flow { emit("Test") }.flowOn(Dispatchers.IO)
//Inside viewmodel
val liveData = MutableLiveData<String>()
fun action() {
viewModelScope.launch { privateAction() }
}
suspend fun privateAction() {
f.collect {
liveData.value = it
}
}
When I now call the action() method in my unit test, the test finishes before the flow is collected. This is how the test might look:
#Test
fun example() = runBlockingTest {
viewModel.action()
assertEquals(viewModel.liveData.value, "Test")
}
I am using the TestCoroutineDispatcher via this Junit5 extension and also the instant executor extension for LiveData:
class TestCoroutineDispatcherExtension : BeforeEachCallback, AfterEachCallback, ParameterResolver {
#SuppressLint("NewApi") // Only used in unit tests
override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean {
return parameterContext?.parameter?.type === testDispatcher.javaClass
}
override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any {
return testDispatcher
}
private val testDispatcher = TestCoroutineDispatcher()
override fun beforeEach(context: ExtensionContext?) {
Dispatchers.setMain(testDispatcher)
}
override fun afterEach(context: ExtensionContext?) {
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
}
class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {
override fun beforeEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance()
.setDelegate(object : TaskExecutor() {
override fun executeOnDiskIO(runnable: Runnable) = runnable.run()
override fun postToMainThread(runnable: Runnable) = runnable.run()
override fun isMainThread(): Boolean = true
})
}
override fun afterEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance().setDelegate(null)
}
}
You can try either,
fun action() = viewModelScope.launch { privateAction() }
suspend fun privateAction() {
f.collect {
liveData.value = it
}
}
#Test
fun example() = runBlockingTest {
viewModel.action().join()
assertEquals(viewModel.liveData.value, "Test")
}
or
fun action() {
viewModelScope.launch { privateAction()
}
suspend fun privateAction() {
f.collect {
liveData.value = it
}
}
#Test
fun example() = runBlockingTest {
viewModel.action()
viewModel.viewModelScope.coroutineContext[Job]!!.join()
assertEquals(viewModel.liveData.value, "Test")
}
You could also try this,
suspend fun <T> LiveData<T>.awaitValue(): T? {
return suspendCoroutine { cont ->
val observer = object : Observer<T> {
override fun onChanged(t: T?) {
removeObserver(this)
cont.resume(t)
}
}
observeForever(observer)
}
}
#Test
fun example() = runBlockingTest {
viewModel.action()
assertEquals(viewModel.liveData.awaitValue(), "Test")
}
So what I ended up doing is just passing the Dispatcher to the viewmodel constructor:
class MyViewModel(..., private val dispatcher = Dispatchers.Main)
and then using it like this:
viewModelScope.launch(dispatcher) {}
So now I can override this when I instantiate the ViewModel in my test with a TestCoroutineDispatcher and then advance the time, use testCoroutineDispatcher.runBlockingTest {}, etc.