I'm using a navigation component but when I click an Item to load an activity it starts in dark screen and I don't know what's going on?
View works only when I press the square to "resume my app" and I don't really know where's the mistake
This is my code
navigation.xml
<activity
android:id="#+id/mn_log_out"
android:name="mx.MyApp.android.LogOutMessageActivity"
android:label="LogOutMessageActivity" />
mx.MyApp.android.LogOutMessageActivity
#SuppressLint("ResourceType", "CommitPrefEdits")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val builder = AlertDialog.Builder(this)
builder.setTitle(resources.getString(R.string.log_out_title))
builder.setMessage(resources.getString(R.string.log_out_description))
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> logOut()
}
}
builder.setPositiveButton(resources.getString(R.string.yes), dialogClickListener)
builder.setNegativeButton(resources.getString(R.string.no), dialogClickListener)
dialog = builder.create()
dialog.show()
}
The problem was on the build.gradle
I made downgrade to this libraries. We need to report this issue on the newest version
THIS
implementation "androidx.navigation:navigation-fragment-ktx:2.3.0"
implementation "androidx.navigation:navigation-ui-ktx:2.3.0"
INSTEAD
implementation "androidx.navigation:navigation-fragment-ktx:2.3.1"
implementation "androidx.navigation:navigation-ui-ktx:2.3.1"
Related
I want the app to run like this:
When you run the app, you go to the window to set the notification access right, and if you go back while allowing access to the app, you go to the main screen. and when notification access right is not granted, you go to notification access window until right granted.
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val notificationManager =
this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= 23) {
if (!notificationManager.isNotificationPolicyAccessGranted) {
this.startActivity(Intent(android.provider.Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS))
}
}
}
The code is written as above, but regardless of whether the notification permission is allowed or not, if you go back, you will be taken to the main page.
How can I modify my code so that I can navigate to the main page only when permission is granted?
I'm trying to implement StateFlow in my app with MVVM architecture between ViewModel and Fragment.
In ViewModel:
...
private val _eventDataState = MutableStateFlow<EventDataState>(EventDataState.Loading)
val eventDataState: StateFlow<EventDataState> = _eventDataState
...
In Fragment:
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.eventDataState.collect { eventDataState ->
when (eventDataState) {
is EventDataState.Loading -> {}
is EventDataState.Success -> onEventDataUpdated(data = eventDataState)
is EventDataState.Deleted -> onEventDataDeleted()
}
}
}
}
viewModel.getEventData()
}
...
All seems to work well:
2022-04-15 17:57:20.352 5251-5251/ ... E/EVENT: Data state: Success(...)
But when I switch to another Fragment through Activity's SupportFragmentManager and then hit Back button I get multiple responses from StateFlow:
2022-04-15 17:57:30.358 5251-5251/ ... E/EVENT: Data state: Success(...)
2022-04-15 17:57:30.362 5251-5251/ ... E/EVENT: Data state: Success(...)
So the more times I switch to another Fragment and back - the more copies of response I get from StateFlow (this is not initial StateFlow value).
My guess is that when another Fragment are called the first one destroys its view but subscription to Flow is still exists, and when returning back from another Fragment the first one calls its onViewCreated and so creating another copy of subscription to this Flow. Nevertheless I was unable to find any solution to my case on stackoverflow or any other resources.
What have I missed?
You should use viewLifecycleOwner.lifecycleScope.launch in fragments. viewLifecycleOwner.lifecycleScope and all its jobs will be cancelled when the view is destroyed.
Hi there I want to convert those blocks from the AppInventor project to Android Studio Project Using Kotiln as my programing language but I am very new to android development can anyone help me with that?
What this app does is opening webview and reload my webpage URL at a randomly generated time.
What I tried so far!
package com.technosoftkpk.y_view
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myWebView: WebView = findViewById(R.id.webview)
myWebView.setWebViewClient(WebViewClient())
myWebView.loadUrl("https://technosoft.pk")
val webSettings = myWebView.settings
webSettings.displayZoomControls = true
webSettings.javaScriptEnabled = true
}
}
Would something like this work? This will randomly wait between 0 and 5 seconds. (Add the code at the end of onCreate):
import kotlin.concurrent.thread
import kotlin.random.Random
thread {
while (true) {
Thread.sleep(Random.nextLong(5000))
runOnUiThread { myWebView.reload() }
}
}
This might look complicated, but we need to make a new thread to avoid blocking the UI thread and allowing user input. But then the reloading needs to happen on the UI thread again. An alternative would be to use postDelayed.
In my Activity I setup the NavController in OnCreate:
navController = findNavController(this, R.id.NavHostFragment)
In my Fragments, I setup the NavController in onViewCreated:
navController = Navigation.findNavController(view)
The Activity only navigates to a few Fragments (e.g. SitesFragment, ContactsFragment, TasksFragment etc) from the NavigationView when item is clicked as below:
R.id.nav_sites_fragment -> {
navController.popBackStack(R.id.sitesFragment, true)
navController.navigate(R.id.sitesFragment)
}
In the Fragments, click events (in RecyclerViews mainly heading to other Fragments, such as SiteFragment, ContactFragment, TaskFragment etc) are handled as below:
if (!navController.popBackStack(R.id.siteFragment, false)) {
// not in BackStack
navController.navigate(R.id.action_contactFragment_to_siteFragment)
}
The problem is, Fragments from Fragment actions remain in the backstack even when I popBackStack in the Activity actions..
I think my understanding of backstack is not correct as I'm not sure what is going on - but that maybe I have created two separate instances of NavController?
EDIT: Although I have looked at this post How to clear navigation Stack after navigating to another fragment in Android, I am still finding same behaviour. PopBackStack in Activity is not clearing Fragments added to the backstack..
For example:
SITES -> SITE -> CONTACT -> CONTACTS should remove first three fragments, but backpress still returns to CONTACT..
Ok, so I found this post https://github.com/android/architecture-components-samples/issues/767.
I modified the code a bit and in my Activity I have the following function:
private fun navigateWithClearStack(destination: Int) {
val navController = findNavController(R.id.NavHostFragment)
val navHostFragment: NavHostFragment = supportFragmentManager.findFragmentById(R.id.NavHostFragment) as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.business_navigation)
graph.startDestination = destination
navController.graph = graph
}
Then, where I handle the NavigationView clicks:
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_sites_fragment -> navigateWithClearStack(R.id.sitesFragment)
R.id.nav_projects_fragment -> navigateWithClearStack(R.id.projectsFragment)
R.id.nav_contacts_fragment -> navigateWithClearStack(R.id.contactsFragment)
R.id.nav_tasks_fragment -> navigateWithClearStack(R.id.tasksFragment)
R.id.nav_profile_fragment -> makeToast("Todo: Profile Fragment")
R.id.nav_settings_fragment -> makeToast("Todo: Settings Fragment")
}
business_drawer_layout.closeDrawer(GravityCompat.START)
return true
}
So as users Navigate through app, Fragments are added to the BackStack (using popUpTo to deal with duplicates), but when user clicks shortcut back to one of 'starting' fragments, the graph is replaced, thus clearing the BackStack.. Which I think is kind of neat.
I'm trying to make a simple load screen in a app using kotlin
Instead of just displaying a text, I want to play a sound and show an image for like, 3 seconds.
I created a layout to set for 3 seconds using Thread.sleep, but it didn't work.
Can anyone see what I'm missing?
Thank you!
class MatrixActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.loading_activity_matrix)
Thread.sleep(3000)
setContentView(R.layout.activity_matrix)
A00.setOnClickListener { sendCommand("00000")}
B00.setOnClickListener { sendCommand("00100")}
C00.setOnClickListener { sendCommand("00200")}
D00.setOnClickListener { sendCommand("00300")}
E00.setOnClickListener { sendCommand("00400")}
F00.setOnClickListener { sendCommand("00500")}
G00.setOnClickListener { sendCommand("00600")}
H00.setOnClickListener { sendCommand("00700")}
If you're using Kotlins coroutines, you can use
runBlocking {
delay(3000) //waits for 3s
}
in place of Thread.sleep(3000) to let a thread sleep for the given amount of milliseconds. If you need help setting up coroutines, or need further information, great explanations are on the Kotlin website: Your first coroutine with Kotlin.