Can somebody explain to me how it's works?
From (MainFragment) tap on FAB to create new fragment(HabitEditorScreenFragment) through navigation component. Applying to it Parcelable argument. In that fragment i'm going in new fragment(EditColorFragment) with new argument type of Int. In that fragment:
saving new int in sharable viewModel
i'm going back with findNavController().navigateUp()
and now is strange things. If i enter something in editfields that values will be in safeArgs value. But i haven't save it in there anywhere!
Update:
It happend riht in time when i type somthing in edit fields.
But:
private fun setDoAfterTextChanged() = with(binding) {
fhesHabitNameInput.doAfterTextChanged {
viewModel.editorHabit.name = fhesHabitNameInput.text.toString()
viewModel.canWeSave() //just cheking errors
checkName() // checking specific field
}
fhesHabitDescriptionInput.doAfterTextChanged {
viewModel.editorHabit.description = fhesHabitDescriptionInput.text.toString()
viewModel.canWeSave()
checkDescription()
}
fhesHabitFrequencyInput.doAfterTextChanged {
viewModel.editorHabit.frequency = fhesHabitFrequencyInput.text.toString()
viewModel.canWeSave()
checkFrequency()
}
}
Here's the code
Ok, i'm figure it out what's happening. Dumb me. :D
viewModel.editorHabit = args.habitCharacteristics
this is changing link on viewModel.EditorHabit not copying info from args. Really stupid :D Sorry for that.
Related
I have fragments S1, S2, P, D1, and D2.
Both S1 and S2 have action leading to P. When I am in fragment P I can navigate to D1 or D2.
When I came from S1 I want to navigate to D1, but when I came from S2 I want to go to D2.
What is the best way to do navigate based on the source fragment?.
I know I can use arguments for this, but it seems like a much more basic operation. I would expect some more clear and quicker solution (for example some method getNameOfSource()).
You can do this via getting the entry from your Fragment Backstack, although you need to ensure you are providing some sort of TAG to them in the first place. You can simply use something like this then. Using arguments is still better I would say, but that is out of scope for this question
private fun getNameOfSource(): String? {
val fm = supportFragmentManager
val count = fm.backStackEntryCount
return fm.getBackStackEntryAt(count - 2).name
}
You can get the fragment tag using this code:
public Fragment getSourceFragmentName() {
// you need to check this because you need at least 2 fragments at the backstack
if (getSupportFragmentManager().getBackStackEntryCount() < 2) {
return null;
}
String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 2).getName();
return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
I'm just starting out on learning Kotlin, and I'm currently making a simple Quiz application for Android. The user can choose an answer with four buttons which are stored in an array. The program contains a functions which is supposed to check if the correct button is clicked and return a corresponding boolean:
fun checkAnswer (solution: Int): Boolean {
for (z in answerButtons.indices) {
answerButtons[z].setOnClickListener{
return z == solution
}
}
}
Now I know that this return doesn't work, but I just can't find a way to return a value depending on which button is clicked. If anyone could help me here, I'd be very grateful. Thanks!
So when you call setOnClickListener, the Kotlin compiler is really abstracting away some important details. What is really happening is this:
setOnClickListener(object: View.OnClickListener {
override fun onClick(v: View?) {
doAThing()
}
})
This is a SAM constructor. But, as you can see, the return type of onClick is Unit, and it doesn't make sense to return from an anonymous object either. It would help to have more context as to why you've structured your code the way you have, but here's a potential solution to your problem:
// in onCreate
for (btn in answerButtons) {
btn.setOnClickListener {
if (btn.text == solution) {
doTheThingWhenCorrectAnswer()
} else {
doTheThingWhenIncorrectAnswer()
}
}
}
If this were a real application, I would additionally suggest pushing the logic for checking answers into the model layer to maintain strong separation of concerns.
I'm creating an Intent like so:
public void showThings(ArrayList<Thing> things) {
Intent intent = new Intent(this, ThingActivity.class);
intent.putExtra(THINGS, things);
startActivity(intent);
}
Then in the ThingActivity I want to get the ArrayList<Thing>
class ThingActivity {
var things: ArrayList<Thing>? = null
override fun onCreate(savedInstanceState: Bundle?) {
things = intent.extras.getSerializable(OtherActivity.THINGS) as? ArrayList<Thing>
}
Unfortunately, I can't seem to figure out how to cast to the appropriate type without triggering an "unchecked cast" warning. Is there a way to gracefully set to null if (somehow unexpectedly) the cast fails?
Appending ?: return null does not seem to work as I've seen suggested elsewhere
The unchecked cast warning is happening due to the way Java generics work at runtime. Because of type erasure, at runtime, the type of the list is just List, and not List<Thing>. That means that the cast is considered unsafe, even though it's quite possible for a human to look at the code and see that there's no problem.
While I agree with you that suppressing the warning isn't ideal, in this case I think it's fine.
The best solution, though, would be to implement the Parcelable interface on Thing. That way, when you want to pass a List<Thing> through an intent, you could write:
intent.putParcelableArrayListExtra(THINGS, things)
And when you want to read it back out:
things = intent.extras.getParcelableArrayListExtra(OtherActivity.THINGS)
Neither of these will cause a compiler warning.
As an alternative to Ben P's answer, you could use Gson.
Assuming that Things is simply a data class (holds a bunch of variables), this will work perfectly (this is also required by Ben P's answer).
Here's a way to implement it:
public void showThings(ArrayList<Thing> things) {
String json = new Gson().toJson(things);
Intent intent = new Intent(this, ThingActivity.class);
intent.putExtra(THINGS, json);
startActivity(intent);
}
Then you can get the ArrayList like this:
String json = intent.getStringExtra(THINGS);
TypeToken<ArrayList<Things>> token = new TypeToken<ArrayList<Things>>() {};
ArrayList<Things> things = new Gson().fromJson(json, token.getType());
Activity one:
val intent = Intent(this, SecondActivity::class.java)
val arrayGuide = ArrayList<Guide>()
intent.putParcelableArrayListExtra("arrayInfo",arrayGuide)
startActivity(intent)
Activity two:
if(intent != null){
val arrayList =
this.intent.getParcelableArrayListExtra<Guide>("arrayInfo")
}
I was looking for my problem on the internet, but the solutions given still do not work.
How to transfer data from first Activity to second?(plain text)
MainActivity
btn.setOnClickListener {
val player1= findViewById<EditText>(R.id.et1) as EditText
val player2= findViewById<EditText>(R.id.et2) as EditText
val intent1= Intent(this, MainActivity3::class.java).apply {
putExtra("player1",player1.getText().toString())
putExtra("player2",player2.getText().toString())
}
startActivity(intent1)
}
Second Activity
fun PlayGame(cellID:Int,buSelected:Button){
val playe1= intent.getStringExtra(EXTRA_MESSAGE)
val playe2= intent.getStringExtra(EXTRA_MESSAGE)
val textView2= findViewById<TextView>(R.id.textView2).apply{
text= playe1
text=playe2
}
if(ActivePlayer==1){
textView2.setText(": $playe1")
buSelected.text="0"
buSelected.setBackgroundResource(R.color.blue)
player1.add(cellID)
ActivePlayer=2
}else{
textView2.setText(": $playe2")
buSelected.text="X"
buSelected.setBackgroundResource(R.color.green)
player2.add(cellID)
ActivePlayer=1
}
buSelected.isEnabled=false
CheckWiner()
}
I want the player's name from MainActivity goes to Second ;p
The problem is in the way you get your values. Try this:
val playe1= intent.getStringExtra("player1")
val playe2= intent.getStringExtra("player2")
Use a sharedpreferences, in your next activity after saving the values to a Val or var delete the shared preferences continue.
It’s not ideal but it just may get you to where you can at least interact with that data.
I used this method for something similar last night. If I have time tonight I was going to post a how to on this on my website. If I can I’ll swing by here and edit my answer. With code and explanation unless you get it figured out by then.
So I'm still working on my first little app here, new to Android and Java, so I'm stuck on a basic little problem here. Answers to my first questions were really helpful, so after researching and not coming up with anything, I thought I'd ask for some more help!
The idea is that on another screen the user makes a choice A, B, C, or D, and that choices is passed as a string through the intent. OnResume checks if the choice is not null and sets an integer that corresponds to that string. Later when the user pushes another button, some if else logic checks that int and performs and action based on which was chosen. The problem is that the App crashed at onResume.
I learned that I have to use equals(string) to compare string reference, but maybe the problem is that I am trying to compare a string in reference to a literal string? Any help would be greatly appreciated.
Thanks!
protected void onResume() {
super.onResume();
// Get the message from the intent
Intent intent = getIntent();
String choice = intent
.getStringExtra(ExtensionSetupSlector.TORQUE_SETUP);
// Create the text view
TextView displayChoice = (TextView) findViewById(R.id.displayChoice);
if (!choice.equals("")){
displayChoice.setText(choice);
if (choice.equals("A")) {
myChoice = 1;
}
if (choice.equals("B")) {
myChoice = 2;
}
if (choice.equals("C")) {
myChoice = 3;
}
if (choice.equals("D")) {
myChoice = 4;
}
}
}
myChoice is declare right after ...extends Activity{ Also I'm not quite sure If this should really be in onResume, but it was working before I started try to set myChoice in the onResume (when I was just displaying the choice). Thanks again!
Change if (!choice.equals("")) to check for null instead. Otherwise your app attempts to access an empty reference and crashes.