I made a new project using navigation drawer that android gives me as builtin and then i added my menus in the navigation Drawer and then made another activity that is empty activity and made a button over there of getStarted and on the click listening i made an intent of the mainActivity that has the navigation drawer and then assigned this to the getstarted button to startActivity(mainIntent) but its not working, I have done many R&D but didn't work at all and i am getting following errors.
I have tried all the discussion over here
but nothing is working in my case
class WelcomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_welcome)
getStartedBtn.setOnClickListener {
val main = Intent(this,MainActivity::class.java)
startActivity(main)
}
}
I want to be routed to the main activity.In main activity I have used builtin toolbar or navigation drawer.
To access this from an outer scope (a class, or extension function, or labeled function literal with receiver) we write this#label where #label is a label on the scope this is meant to be from:
You should specify your scope. For more information you can check this link.
val main = Intent(this#WelcomeActivity, MainActivity::class.java)
startActivity(main)
Hope this works!
Try to change val main = Intent(this,MainActivity::class.java) to val main = Intent(WelcomeActivity.this,MainActivity::class.java)
Also make sure that getStartedBtn is correctly imported from xml file.
Do you imported getStartedBtn correctly and try to change the val main = Intent(this,MainActivity::class.java) to val main = Intent(applicatonContext,MainActivity::class.java) it thought this will help if you still facing any problem please post the error.
Related
Suppose I have a notification, that when clicked, launches my app's activity. It's a notification about a message, in a conversation, and so it launches the activity passing the conversationId as an argument. When the activity is launched by that intent from the notification, it should open MessagesScreen, which is a deeply nested screen in the app, passing to it conversationId.
What is the best way to do this in Compose? In the good old Fragments or Activities you just navigated straight to it, but with Compose is a little trickier. The path to the MessagesScreen is as follows:
SplashScreen (checks for authentication) -> HomeScreen (if authenticated) -> ConversationScreen -> MessagesScreen
I can't just navigate straight to MessagesScreen by having the compose's NavController be stored in the Activity, since I need to go through SplashScreen to check for authentication. Also, I don't know the Compose's implication of navigating to a deeply nested component from the Activity's onCreate().
What I currently do is have a field in my global ViewModel called notificationConversationId, that is set on my Activity's onCreate if it was passed by the notification's intent:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val conversationId = intent.getStringExtra("conversation_id") ?: ""
globalViewModel.notificationConversationId = conversationId
// ...
Then, in a LaunchedEffect in my HomeScreen I observe this field, and if it is not empty, I navigate to the MessagesScreen, and set it to an empty string, so the LaunchedEffect is not executed again.
val conversationId = globalViewModel.notificationConversationid
LaunchedEffect(conversationId) {
if (conversationId.isNotEmpty()) {
val path = getMessagespath(conversationId = conversationId)
globalViewModel.notificationConversationId = ""
navController.navigate(path)
}
}
It works, but it is horrendous. Is there a better way to accomplish this in Compose? Thanks in advance.
List the item
I'm developing an app using a navigation drawer and navigation components and I'm facing two issues:
I settled specifically each toolbar title where it is supposed to be, but every time I change the fragments, in the toolbar, for an instant, I can see the previous name from the fragment, which is the fragment name itself. So, it quickly changes from MySpecificFragment to MyFragmentName and I would like it to not happen. I've settled the title even onCreateView or onViewCreated. It didn't matter, still happening.
How could I decide the direction in which the back button of the fragment goes? I would like to create a standard position where the back button arrow goes, always the same. But it just travels back to the previous fragment (which is not a real problem, but I would like to improve its behavior)
Sorry for the lack of code, I don't know what I am supposed to display since I'm going against the standard android behavior.
P.S.: Using android studio and kotlin
Regarding the first issue, one way to avoid the brief display of the previous fragment name in the toolbar is to set the toolbar title in the parent activity and then update it from the fragment's onResume() method. This ensures that the toolbar title is set correctly when the fragment is resumed after being pushed onto the back stack. Here's an example code snippet:
In your activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
}
fun setToolbarTitle(title: String) {
supportActionBar?.title = title
}
}
In your fragment:
class MySpecificFragment : Fragment() {
override fun onResume() {
super.onResume()
(activity as? MainActivity)?.setToolbarTitle("MySpecificFragment")
}
}
Regarding the second issue, you can customize the back button behavior by using a custom NavController.OnDestinationChangedListener. In the listener, you can set the back button icon and its behavior based on the current and previous destinations. Here's an example code snippet:
class MyNavigationController(activity: AppCompatActivity, navController: NavController) {
init {
navController.addOnDestinationChangedListener(
activity, object : NavController.OnDestinationChangedListener {
override fun onDestinationChanged(
controller: NavController,
destination: NavDestination,
arguments: Bundle?
) {
if (destination.id == R.id.my_fragment) {
activity.supportActionBar?.setDisplayHomeAsUpEnabled(false)
} else {
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)
activity.supportActionBar?.setHomeActionContentDescription(R.string.back)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)
activity.supportActionBar?.setDisplayShowHomeEnabled(true)
}
}
})
}
}
Here, you can adjust the back button icon and behavior based on the current and previous destinations by setting setDisplayHomeAsUpEnabled, setHomeAsUpIndicator, and setHomeActionContentDescription.
I'm currently trying to develop a simple app and for my use case is easier to use Composable function for the menu, and then move to an activity for other operations.
Right now I have two classes:
MainActivity: a ComponentActivity that runs some composable functions
NewActivity: an Activity that runs its own class code and has a xml for the design
I successfully managed to move from MainActivity to NewActivity with:
val context = LocalContext.current
val intent = Intent(context, NewActivity::class.java)
startActivity(context, intentntent, null)
Once I reach the NewActivity, I can't however go back to the composable class. In particular, calling back:
val Intent : Intent = Intent(this,MainActivity::class.java)
startActivity(intent)
makes the application stuck.
Is there a way to switch back to the composable class? If not, what alternative do you suggest?
Thanks in advance
I got a question. I have two activities in my app. In first one, when I click the button, I need something to happen in the second one. How can I do it? If that button would be in the second activity I would just do it by:
button.setOnClickListener {}
But how can I do it when button is in the other activity? It's worth adding that code, that tells what should happen, must be in that second activity, just like it was in that "setOnClickListener". Sorry, I'm starting with Android development.
You could communicate between two activities via broadcast or intent.
But it make logic more complex.
So I suggest use two fragments instead two activities.
If you use two fragment in one activity, you can easy communicate between two fragments.
You can look more detailed information about fragment from this URL.
https://developer.android.com/guide/fragments
To achieve the intended flow you may try the below approach,
Start activity 2 on button click from activity 1.
On activity 2 place your code in onCreate so, once activity 2 loads up your code will fire up.
Activity 1:
button.setOnClickListener{
val intent = Intent(this, second::class.java)
startActivity(intent)
}
Activity 2:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
CallDefinedFunctionHere();
}
You cannot be sure that both activities are present at the same moment since the system might destroy inactive one therefore you cannot trigger any code from activity A inside activity B.
What you can do you can start activity B with an intent and some parameters describing what should happen inside activity B.
or
You can communicate by writing something down to a persistent storage (like SharedPreferences) and then when the other activity is resumed (active again) reading it, reacting to it and then removing it from the storage (to make sure you do not handle it twice).
You can pass data in the intent that opens the second activity.
// In first activity:
buttonX.setOnClickListner {
val intent = Intent(MySecondActivity::class.java).apply {
putExtra("wasFromButtonX", true)
}
startActivity(intent)
}
// In second activity:
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val wasLaunchedFromButtonX = intent.getBooleanExtra("wasFromButtonX", false)
// Above line uses false as default, so it will only be true if you explicitly
// put the extra in the Intent that started this Activity.
if (wasLaunchedFromButtonX) {
// do alternate setup here
}
}
How to pass information between Activities is explained in the introductory documentation here.
Create a function in class where 2nd activity are defined like this.
public void refresh(){}
Now Call that in your 1st activity where you want to call 1st after any action.
button.setOnClickListener {((MainActivity) Objects.requireNonNull(getActivity())).refresh();}
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>