I have 3 activities:
Setup
Test
Result
After I passed a test and got a result, I need to get back to SetupActivity with the saved result (it's a custom class). To keep its state saved, I don't apply the finish() method on SetupActivity before opening TestActivity but then I have a problem with passing my results to the SetupActivity because I can't make an intent to already opened activity. So what is the best way to solve this problem? I need to keep the instance of SetupActivity saved and at the same time, I need to pass the data to this activity.
You could use SharedPreferences to save the data in one activity and then get it in the other.
If you are using Dependency Injection, you can send your data easily. If you don't use it, try below.
Pass from First Activity
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("key", "value")
startActivity(intent)
Get in Second Activity
val value = intent.getStringExtra("key")
Suggestion
Always put keys in constant file for more managed way.
companion object {
val KEY = "key"
}
way is using a Singleton class:
object UserModelSingleton { var KEY: String? = null}
Related
I was following a tutorial by geekbygeeks they made a todo list in an activity but I want to put mine in a fragment.
So As a beginner I ran into a bunch of errors.
The first one is initializing the adapter class (of a recyclerviwer) in the Fragment.kt class
// on below line we are initializing our adapter class.
val noteRVAdapter = NoteRVAdapter(this, this, this)
I think because this refers to activities and not fragment, I get errors for the parameter this.
although if I change the first parament this to this.context it stops the error of the first parameter. (i.e)
val noteRVAdapter = NoteRVAdapter(this.context, this, this)
but I don't really know the meaning of this nor if it will work when I run the App.
Here is the NoteRVAdapter.kt file (which was initialize in the fragment.kt) :
class NoteRVAdapter(
val context: Context,
val noteClickDeleteInterface: NoteClickDeleteInterface,
val noteClickInterface: NoteClickInterface
) :
RecyclerView.Adapter<NoteRVAdapter.ViewHolder>() {
// on below line we are creating a
// variable for our all notes list.
private val allNotes = ArrayList<Note>()
....
The next Error I encountered was an Unresolved reference: application from ViewModel,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(...
The application parameter of getInstance gives an Unresolved reference error even though it requires the parameter.
Here's more code of the ViewModel in the fragment.kt
// on below line we are
// initializing our view modal.
viewModal = ViewModelProvider(
this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application)
).get(NoteViewModal::class.java)
This next error is on intent.
I got an unresolved reference error on #MainActivty and finish, in the code below
val intent = Intent(this#MainActivity, AddEditNoteActivity::class.java)
startActivity(intent)
this.finish()
I am not familiar with the intent but I think the this#MainActivity shouldn't be there, as I want to put this in a fragement (DashboardFragment) not an activity.
here's the whole code, the the fragment.kt file:
binding.idFAB.setOnClickListener {
// adding a click listener for fab button
// and opening a new intent to add a new note.
val intent = Intent(this#MainActivity, AddEditNoteActivity::class.java)
startActivity(intent)
this.finish()
}
And finally I got a similar error on intent here; (also in the fragment.kt file)
override fun onNoteClick(note: Note) {
// opening a new intent and passing a data to it.
val intent = Intent(this#MainActivity, AddEditNoteActivity::class.java)
intent.putExtra("noteType", "Edit")
intent.putExtra("noteTitle", note.noteTitle)
intent.putExtra("noteDescription", note.noteDescription)
intent.putExtra("noteId", note.id)
startActivity(intent)
this.finish()
}
The difference is that the finish() declared last, gives an unresolved referenceerror, and the override at the start gives an error, saying onNoteClick' overrides nothing
please by fragment.kt I mean the fragment (DashboardFragment) I want to put the todo list.
I know this is a lot, but any feedback will be greatly appreciated.. And I am more than happy to provide any other information if required.
Thanks massively for your help in advance, I honestly appreciate,
TLDR: Replace this and this#MainActivity with requireContext(). Add requireContext(). in front of startActivity() and add requireActivity(). in front of finish().
What is Context? is kind of meme among Android developers because it is so hard to explain. It's basically something you need an instance of to use many different Android classes. The weird thing is, an Activity is a Context (it's a subclass of it), but a Fragment gets attached to a Context. So when you are passing a Context parameter to a class constructor, an Activity can pass itself as this, but a Fragment has to get a reference to its attached context and pass that.
In a Fragment you can replace this with requireContext(). You usually need requireContext() instead of just context because context is nullable. They made it nullable because it is null during certain stages of the Fragment lifecycle. You need to remember not to use requireContext() in property initializers or callbacks (other than UI listeners) because property initializers are called before there is an attached context and callbacks could get fired when there is no context available and cause a crash.
When you see this#MainActivity instead of this, that's because that class named MainActivity wants to pass itself as the context, but it's doing it inside a listener interface. In that context, this would be the listener, not the Activity, so the code has to clarify which this it is referring to, which is done with # and the name of the outer class.
Once again, since you're in a Fragment, you should pass requireContext() for that parameter instead. Since it's in a click listener, which can only be called while the Fragment is attached, it's safe to use requireContext().
startActivity() is a function of Context. That's why in an Activity, you can simply call it from anywhere. In a Fragment, you need to use requireContext().startActivity().
finish() is specifically a function of an Activity so you can't call it on a Fragment. If you want to finish the Activity that contains the Fragment, you can call requireActivity().finish(). But since you're replacing your Activity with a Fragment, your structure of how you're organizing the screens of your app is different, so this may not be a one-to-one correspondence with what the original code was doing.
I have a button in an activity that when pressed adds 1 to a text view in another activity. However, when I try to access that variable in a different activity, I cannot. How could I solve this without passing intents (making the variable open for use in the whole program)?
You can use companion object in the Activity where you set the desired variable:
class ShowCaseActivity : Activity {
companion object {
var yourVariable = 0
}
}
Now you can use this variable in every file in the project, you just have to import it accordingly like this:
import ShowCaseActivity.Companion.yourVariable
....
val number = ShowCaseActivity.yourVariable
It should be said that this is not a recommended way of solving this issue. You should pass data between Activities with intents.
There is a wall between Activities and you can only pass data over that wall with Intents. For this reason, it is recommended to use only one Activity. You can use Fragments to represent your different screens. Use an Activity-scoped ViewModel to hold properties and LiveData you need to access from both screens.
In your case, you would have a function in the ViewModel that the button calls. The function would increment a private variable and set its value to a public LiveData. The TextView would observe that LiveData so it is automatically updated when the value is changed.
I have 5 Activities in my App. Each Activity having some data. I need all previous Activity data in last Activity. All previous Activity is a kind of Form. User fill the data and move to next Activity and last Activity displays all previous Activity's data.
There are several ways to do this.
Use of Intents and save the data like putString(...):
Which isn't really nice because you have to temporarilly save the data of each Intent in the Activity and move them further with the next Intent.
Use a class for your data and pass it through the Activities per Intent:
This way you pass the instance of the class to the Activities to write/read your data. But this class needs the Parcelable / Serializable interface
Use of a static class:
You can access this class in every Activity and write/read like you want.
Use a Bundle with the Intent:
Save all your data in a Bundle and pass it to the Activities.
Think about your design and use Fragments:
Have one Activity with 5 Fragments. Every Fragment saves/reads the data from the Activity.
Best approach would be to use a Bundle.
Option 1:
If you want to add data for every activity and carryforward it to next activity then it's better to pass data with bundle.
Bundles are better in a scenario, when data is comparatively small and where you just want to pass data to next activity and don't want to store the data for future.
Option 2:
You can use Sharedprefrences. Better to use when data is to be stored for future.
Option 3:
If you have more records and you want it to be in a structured manner, and to be stored for future then Sqlitedatabase is obvious.
Above to options are in case if you want to use your data to use very frequently and it is not structured.
You can use Intent
FirstActivity
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("key_value", string);
startActivity(intent);
SecondActivity
String text = getIntent().getStringExtra("key_value");
Or if you need the data to stay longer, and you can reuse it after the application is killed, you can use SharedPrefrences
Place the data in some Activity
SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
editor.putString("ValueOne", "SomeValue" );
editor.commit();
Retrieve data from shared preference in any Activity
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
String prefString = prefs.getString("ValueOne", null);
My app contains 2 activitys. Activity A is the one which is created by starting the app. In this one I create an object of my own class MyClass. This class contains one string and 3 integers. In activity A this object gets written.
The second activity B needs to read this object. How can I pass it from A to B? Or is there an other solution?
There are couple of way you can pass an object from one activity to another:
1. Application Class: this class is visible to all your application Activities so you can save your object in this class from one Activity and then access it from the other.
2. You can break apart your Class into the simple variables: string and 3 integers and pass them via a bundle or the intent it self from one activity to another, then construct your object again.
Intent intent = new Intent (this, TargetActivity.class);
intent.putExtra(KEY, value);
intent.putExtra(KEY, "value");
startActivity(intent);
3. If your object implements Serializable/Parcelable then you can pass it via a bundle.
Example on how to serialize an object:
How do I serialize an object and save it to a file in Android?
One option could be implementing Serializable interface and then you can pass object instances in intent extra using putExtra(Serializable..) variant of the Intent#putExtra() method.
//to pass :
intent.putExtra("MyClass", obj);
// to retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");
It can be tricky, because there's no guarantee that your application can't be killed between activities. Actually, it can be killed during activities, so keeping persistent objects around can be tricky.
My preferred way to do this is the "singleton pattern" in which you create a class whose purpose is to create a single instance that holds whatever data you want to hang around. If your application gets killed, the singleton instance will be lost and have to be re-created, but all Android apps run this risk all the time anyway.
See Save multiple instances states of the same Activity in Android for my implementation of a singleton in Android.
Oh, and I should add that this only works within an application where all the activities are in the same process, sharing the same address space. Otherwise, you'll have to make your object serialiazable and write it off to a file.
In passing the value of a variable from 1st activity to 3rd activity should I use intent.putextra or should I make the variable a global variable so that I could use it in any activity.
You have several options :
implement your own Application class, and make this variable an attribute of the class
save and get this variable in the preferences
The best way to do that is to use intent.
Nevertheless, you sometimes want a more persistant variable, or store a more complexe object. In these cases, you can use a static variable, in a singleton class for instance.
This is definitely your decision but I suppose the user can go to Activity 2 and press back, and thus canceling the need for this variable.
The best option would be to send the value as an extra to Activity 2. It can then send it to Activity 3 if needed.
REMINDER
Do not use static variables for Static Variables are WRONG Almost Always
you can pass the sesssion id to the signout activity in the intent ur using to start the activity:
Intent intent = new Intent(getBaseContext(), SignoutActivity.class);
intent.putExtra("EXTRA_SESSION_ID", sessionId);
startActivity(intent)
Note: Make the session ID available to every activity where you want to allow the user to signout. Otherwise, you could store it in the Application object, but then you'll have to manage the state of the session (checking if it's valid before using it,...)