I've bumped into a strange issue - WebView becomes unresponsive when I finish the activity that started the activity with the WebView BUT it doesn't happen on the first launch, only on the consecutive ones and it also happens on Android 6 and 7, newer Android versions seem to handle that gently.
The full project which reproduces this can be found here
I have two activities Launcher
class LauncherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startActivity(Intent(this, MainActivity::class.java))
finish()
}
}
And MainActivity with the WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val webView = findViewById<WebView>(R.id.oauthWebView)
webView.loadUrl("https://semantic-ui.com/examples/login.html")
}
}
When I start the app the first time everything seems okay, but the second time when I open it,
WebView becomes unresponsive, the keyboard is not showing and it happens right after Launcher onDestroy
If I'm not calling finish in the LauncherActivity everything is fine.
It looks like finishing LauncherActivity has some impact on WebView loading or some other process that's happening under the hood.
It's pretty weird, Logcat is not very helpful either.
Maybe any of you can provide some hint what might be the reason for such behaviour?
Side note:
I'm not looking for answers on how to architect my navigation better, I know it can be done differently - I'm curious why WebView is behaving so weird.
Can you try this?
val webView = findViewById<WebView>(R.id.oauthWebView)
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("https://semantic-ui.com/examples/login.html")
Related
I wanted to keep the light of my app's screen always on when I go to a certain activity or fragment, but I can't do that.
You should use this concept WakeLock or Keep Screen On
There are two things
1)If you need to make activity on keep on you can use Keep screen on. It does not require any special permission. You can do this in activity or xml.
Activity:
class MyActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
//Make sure call this function to clear flags when you dont need this in between .
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_parent"
android:keepScreenOn="true"></RelativeLayout>
Second way - if you need to do some CPU running .
Example like a game app.
You need to declare permission in manifest.
And follow this example. Its a straight forward way.
I would like that animation on MainActivity to be exhibited only when the user opens the app, but remains static if the user comes from another Activity/Fragment (e.g. by using BottomNavigationMenu), so as not to pollute the window too much.
I think it can be solved by using onCreate, onStart, onResume but I am unable to set it properly (still learning).
The only answer I found is here: https://www.tutorialspoint.com/how-to-launch-activity-only-once-when-android-app-is-opened-for-the-first-time
but it is not what I want since I still would like the animation to be exhibited every time the app opens.
Thank you in advance.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// execute animation here??
}
override fun onStart() {
super.onStart()
setContentView(R.layout.activity_main)
// logic part (buttons) is executed here??
}
Once the Main activity is loaded then you have to finish() from other Activity/Fragment then onResume() override method Main Activity will be called. Do not start Main activity every time if the user comes from another Activity/Fragment.
For fragments:
activity.finish()
For Activity:
finish()
Rather then:
Intent startIntent = new Intent(context, MainActivity.class);
startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startIntent);
I have a function of which I call from MainActivity
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
doSomethingFunction(this)
}
...
doSomethingFunction(activity: AppCompatActivity)
{
var button = activity.findViewById<Button>(R.id.button)
// if I try do something with button the app crashes eg
button.text = "Text"
}
Which leads me to believe somehow I must not be accessing activity from MainActivity and activity.findViewById<Button>(R.id.button) didn't actually return my buttons id thats why its crashing. I tried to extend doSomethingFunction(activity: MainActivity) but it crashes the same.
How do I properly pass "MainActivity" to doSomethingFunction so that I can do stuff with "activity"
you don't have a setContentView so yes, it will crash, because there's no layout associated with this activity.
you have to use setContentView(R.layout.yourLayoutHere) in order for you to be able to access xml components.
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.something)
doSomethingFunction(this)
}
a_local_nobody answered my question correctly. I am just posting so that others may benefit. The are two reasons I was facing that error
Reason 1
Just as my code denotes I was calling doSomethingFunction(this) before setContentView thats why there was no setContentView in my sample code. So I couldn't access members in MainActivity well
This lead me to believe in my own project I wasn't initialising my button in time. So After investigations the culprit is in the xml of which a_local_nobody encouraged me to post. I couldn't do that because it was a complex project and I didn't know which part of the xml.
Reason 2
I was using drawer layout which was in turn loading a layout with my button
<androidx.drawerlayout.widget.DrawerLayout
app:headerLayout="#layout/layout_with_button">
This was causing a delay and at run time the button would be null so the app was crashing.
I put the button as a child of Drawer layout and the app runs fine. I deleted app:headerLayout="#layout/layout_with_button"
<androidx.drawerlayout.widget.DrawerLayout>
<Button/>
</androidx.drawerlayout.widget.DrawerLayout>
I have an initialization activity in my app which displays the logo, then I show my next activity using
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // Call the parent class function
setContentView(R.layout.activity_launcher)
// This starts a new co-routine
// it is important to do it this way, in order to show the UI _before_
// all the initialization happens, otherwise launcher is pointless
GlobalScope.launch {
...
[initialization]
...
startActivity(ActivityTwo)
}
}
The transition takes about three seconds because of all the code that is running inside onCreate belonging to ActivityTwo. Is there a way to "create" the second activity behind the scenes, and then show it. I don't mind if the app stays on the initialization screen for those 3 seconds, but the white transition looks really ugly.
onCreate method is actually creating your activity. You must be doing some heavy computation if your activity is janking while rendering. If you are not satisfied with the transition between the two activities, then apply an animation between them.
Navigating in onCreate method like so:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.magic_mile_host)
setSupportActionBar(toolbar_start_test)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back_black_24dp)
navController = findNavController(R.id.nav_host_magic_mile)
navigateToMyTests()
}
Here is my navigateToMyTests() implementation
navController.navigate(R.id.myTestsFragment)
The problem only appears when i invoke this function immediately.
The problem is when I'm on fragment which i came from myTestsFragment. After rotating screen the current fragment is not restored but myTestsFragment is restored always.
The reason why I did this way is because i want to ommit my startDestination in nav graph in certain situation.
Could you explain me why it's happening and maybe help me to come up with other solution to this problem?
In your case, which is about setting your start destination it's better to change it when it's needed using this line of code: navController.getGraph().setStartDestination(int id);
Another point you should pay attention is that calling your navigation methods inside the onCreate() in your Activity is risky, as the navHost so the FragmentManager might not be ready yet. Make sure your start destination is attached, then start your navigation process.