Adjust Textview according to variable in Kotlin - java

i am building an app in Android Studio using kotlin,
the app is a quiz app with a text in the end depending on the result.
I want to know, what is the smoothest way to move a value(i am guessing intent) from the first activity to the last, adjusting it on the way. And how do i use this value to adjust the string showed on the result activity?
I was thinking of creating strings for all results and name them result100, result200, result300 etc. then have a variable that changes according to the answers such as:
buttonParty.setOnClickListener{
desNumber = 100
val intent = Intent(this, ResultPageActivity::class.java)
intent.putExtra("EXTRA_DES", desNumber)
startActivity(intent)
}
retreive it with:
val desNumber = intent.getIntExtra("EXTRA_DES", 100)
than on the last activity:
resultText.setText = findViewById(R.string.result$desNumber)
But this doesnt seem to work unfortunately.
Thanks in advance for any help!

You can do this with something called ViewModel
So you would do something like this:
-On your parent activity (the first), create your ViewModel that will hold your data, and the functions that will alter (or retrieve) that data:
class GameActivity : AppCompatActivity() {
class GameData: ViewModel(){
//Creates the variables that hold the data, with a type that allows them to change over time,
//and to be "observed", but not be useful to this specific example, but this is what I usually use
private val _Result1 : MutableLiveData<String> by lazy {
MutableLiveData<String>().apply { value = "You got a Low Score" }
}
private val _Result2 : MutableLiveData<String> by lazy {
MutableLiveData<String>().apply { value = "You got a High Score" }
}
//Publishes the values of the strings without letting them being altered directly
val Result1 : LiveData<String>
get() = _Result1
val Result2 : LiveData<String>
get() = _Result2
}
}
-On the activity that you want to retrieve the data, do this:
//Declare the variable that will give access to the variables
private val dataModel : GameActivity.GameData by activityViewModels()
//Acess the variables
if(dataModel.Result1.value === "...")
While this answer shows how you can create a model to hold your data in one activity, and access in others, I think the way you are doing it (saving different messages to show) might be done better in a different way. Shouldn't you just save the "points" value in the data model, and use conditions to show the different messages?
You can save the points in this data model the same way it's done with the strings above, but with "Int" instead of "String" in the data types.

Related

How to properly serialize and deserialize an array of objects into/from json?

I'm trying to implement a friends list which needs to be stored in a .json file, in Kotlin/Java with libgdx, but this isn't neccesary(Java is fine).
My code for (1) doesn't work so instead of pasteing it here I'll just try to explain my design and only paste the one for (2) as this I believe is closer to a good implementation.
I made a "Friend" class. When adding a new friend the main thread created such an object, then I read the existing "FriendsList.json" into a string, edited the string by removing "]" and appending the serialized Friend object and a "]" to close the array.
I had and still have a feeling this isn't good, so I changed it.
I made a "FriendArray" class, in which I thought of storing "Friend" objects in an List. I think this would allow me to get rid of the string manipulation code, and just serialize the FriendList class itself, which would hopefully also be easier to read. One of the problems is that addFriendToListOfFriends() doesn't add the data in the objects (it adds "{}" instead of also inserting the name and id).
What do you think of (2) ? Do you know a better way of doing this?
(Just to be clear, I'm more interested in the design and less about compilable code)
import com.badlogic.gdx.files.FileHandle
import com.unciv.json.json (this is com.badlogic.gdx.utils.Json)
import java.io.Serializable
class FriendList() {
private val friendsListFileName = "FriendsList.json"
private val friendsListFileHandle = FileHandle(friendsListFileName)
private var friendListString = ""
var arrayOfFriends = FriendArray()
fun getFriendsListAsString(): String {
return friendsListFileHandle.readString()
}
fun addNewFriend(friendName: String, playerID: String) {
val friend = Friend(friendName, playerID)
arrayOfFriends.addFriendToListOfFriends(friendName, playerID)
saveFriendsList()
}
fun saveFriendsList(){
friendListString = getFriendsListAsString()
friendListString = friendListString.plus(json().prettyPrint(arrayOfFriends))
friendsListFileHandle.writeString(friendListString, false)
}
}
class Friend(val name: String, val userId: String)
class FriendArray(): Serializable {
var nrOfFriends = 0
var listOfFriends = listOf<Friend>()
fun addFriendToListOfFriends(friendName: String, playerID: String) {
var friend = Friend(friendName, playerID)
listOfFriends.plus(friend)
}
}
You don't realy need a class FriendArray for this. You can just searialize a list to JSON. Also it's easier to load the existing friend list to a list, add the new friend to the list and serialize the new list, instead of appending a string.
This way you won't have to worry about the correct JSON format or string manipulation. You just add an object to a list, and serialize the list.
Something like this should work (in java, sorry I don't know enough kotlin to implement this):
public void addFriendAndSerializeToFile(Friend friend) {
// load existing friend list from the file
Json json = new Json();
// here the first parameter is the List (or Collection) type and the second parameter is the type of the objects that are stored in the list
List<Friend> friendList = json.fromJson(List.class, Friend.class, friendsListFileHandle);
// add the new friend to the deserialized list
friendList.add(friend);
// serialize the whole new list to the file
String serializedFriendListWithNewFriendAdded = json.prettyPrint(friendList);
// write to the file handle
fileHandle.writeString(serializedFriendListWithNewFriendAdded, false);
}

Make class as Parcelable

I am currently trying to make one of my classes implement Parcelable but I can't do it properly. This is the class.
class T(val eyes:Int,val img:ImageButton){
var image = img
var value = eyes
var isPressed = false
}
Android Studio suggests that my constructor should look similar to this when implementing Parcelable, but I don't know how to use a parcel to initialize my ImageButton.
constructor(parcel: Parcel) : this(
parcel.readInt(),
//parcel.
) {
value = parcel.readInt()
isPressed = parcel.readByte() != 0.toByte()
}
Tried to use a parcel. any and cast it to an ImageButton without success, any suggestions on how to solve this? Thanks in advance.
If you want to make a class like this, you can create it in this way
class T(var eyes: Int, var img: ImageButton, var isPressed: Boolean = false)
ImageButton class doesn't implement the Parcelable interface, in this case, you cannot pass it into Parcel. It's not a good approach to put Views into Parcel, you can save their state into primitives or classes which implements Parcelable and restore it after that. For example, if you want to pass a text from EditText to another activity, you can put this text into Parcel as String, and restore it in the next Activity.
If you are using kotlin always use data class for model. and use #Parcelize annotation so you don't need to write extra boilerplate code. But in your case you can't Parcelize ImageButton it's not a class that implements Parcelable interface
In case you are searching about a normal way to implement, Just use like that:
#Parcelize
data class UserInformationData(
var userId : String? = null,
var firstName : String? = null,
var lastName : String? = null,
var email : String? = null,
var gender : String? = null,
var dateOfBirth : String? = null,
var phoneNumber : String? = null
):Parcelable

Kotlin accessing variable from other class not by name directly but by string variable

I'm trying to access a variable from another class. The usual way would be:
in Class A
var something = ClassB().element
in Class B
val element = "hi"
Is it also possible to address element not by its name directly, but when I have the name stored in a string? So I have a string that holds
var name = "element"
and want to do something like
var something = ClassB().name //(this doesn't work)
The reason I'm asking is because I have a class in which I do some pitch processing and another class in which I store all of my pitch data in float arrays (the Hz values of different musical notes for different tunings of different instruments)
In the class I do my pitchprocessing in I want to select the right float array depending on a user selection (made with a spinner), which I "translate" with a map (so for example the spinner says "Standard Tuning" and the according array would be called "guitarStandard", in my map "Standard Tuning" would be the key and "guitarStandard" the according value). To not hardcode the different cases in which I need different arrays with if statements, I simply want the name of the array stored in a string by getting the correct value of my map and adress it that way.
I feel like that should be either super simpel or I'm thinking about it the completely wrong way, can someone help out? Thanks
I would advise that you don't store a list of strings, and instead store a list of lambdas that return property values:
class Foo {
val prop1 = arrayOf(1.0, 2.0, 3.0)
val prop2 = arrayOf(4.0, 5.0, 6.0)
}
fun main() {
val props: List<(Foo) -> Array<Double>> = listOf({it.prop1}, {it.prop2})
val foo = Foo()
for (prop in props) {
println(prop(foo).toList())
}
}
But, if you wanted to search up property names from a string, you should look into reflection.
I'd suggest to refactor your ClassB by extracting those properties to separate enum class:
enum class Tunes(vararg f: Float) {
TUNE1(1.0f, 2.0f, 3.0f), TUNE2(4.0f, 5.0f, 6.0f);
val frequencies: FloatArray = f
}
That will make your mapping more straightforward and won't involve reflection:
import Tunes.*
val mapping = mapOf("Standard Tuning" to TUNE1, "Alternate Tuning" to TUNE2)
val result = mapping[userInput]?.frequencies

Design for large scale parameter validation for JPA?

I have a method that takes in a JSON and takes out the data and distributes it to various strings so that they can be set in an entity and persisted. My example below is quite simple but for my actual code I have about 20+ fields
For example see
public Projects createProject(JsonObject jsonInst) {
Projects projectInst = new Projects();
String pId = jsonInst.get("proId").getAsString();
String pName = jsonInst.get("proName").getAsString();
String pStatus = jsonInst.get("proStatus").getAsString();
String pCustId = jsonInst.get("proCustId").getAsString();
String pStartDate = jsonInst.get("proStartDate").getAsString();
...
//Set the entity data
projectInst.setProjectId(pId);
projectInst.setProjectName(pName);
...
Notice if a varible dosent have a corrosponding entry in the Json this code will break with null pointer exception. Obviously I need to validate each parameter befopre calling .getAsString()
What is the best way to do this from a readability point of view I could create 2 varibles for each parameter and check and set for example.
if(jsonInst.get("proName")){
String pName = jsonInst.get("proName").getAsString();
}
Or should I wait for it to be set
if(!pName.isEmpty()){
projectInst.setName(pName)
}
...
Which of these do you think is the best parameter to use for preventing errors.
Is there a way to handle if something is set on a large scale so that I can reduce the amount of code I have to write before I use that varible?
You can create a method that will take field name as parameter and will return json value for that field :
private String getJSONData(String field,JsonObject json){
String data=null;
if(json.has(field)){
data=json.get(field).getAsString();
}
return data;
}
you can call this method for each of your field:
String pId = getJSONData("proId",jsonInst);
By this way you can not only escape NullPointerException, but also avoid code repetition.

how to send value from one class into different classes(more than one class)

I have value strUser and KEY ,I want to send this value to multiple different classes because this value will be used in 5 classes for url, I know the way to send value to one class only using Intent.putExtra as bellow :
Intent policy= new Intent(LoginActivity.this,EpolicyListPolis.class);
policy.putExtra("etUser",strUser);
policy.putExtra("key",KEY);
startActivity(policy);
How can I send this value to multiple different classes at a time? can i use SharedPrefences..? how the way i write sharedPrefences in class and my destination class?
You can use SharedPreferences.
For storing values into SharedPreferences:
SharedPreferences settings = getSharedPreferences("PREFS_NAME", 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("etUser", strUser);
editor.putString("key",KEY);
editor.commit();
Just paste these lines before calling startActivity(policy);
And get values from SharedPreferences
SharedPreferences settings = getSharedPreferences("PREFS_NAME", 0);
String etUser1 = settings.getString("etUser", null);
String key1 = settings.getString("key", null);
And paste these lines at where you want etUser1 and key1. You can access this SharedPreferences value in any Activity. If you cant please take a look on here. It may help you.
I hope this will help you.
Try this...
send value from this class with Intent....
Intent policy= new Intent(LoginActivity.this,EpolicyListPolis.class);
policy.putExtra("key",strUser);
startActivity(policy);
this works like: KEY-"key" and VALUE-strUser.
and you get this value from another class using KEY.
Get value like this.
String user = getIntent().getExtras().getString("key",null);
in user you get strUser value. and if strUser not pass any value than default null(right side of "key") asign for user....
same you use from all class you need... but remember all works with KEY...
because KEY(one type of ID) is only which is works to Put and Get particular value.....
If you are using dependency injection create a Model which hold your states in value objects.
Then inject this model in your activities.
Or simply create a Singleton State object which can be referenced from anywhere.
You have to just get these things in the other activity--
Bundle bundle = getIntent().getExtras();
String user = bundle.getString("etUser");
String key = bundle.getString("key");
Or,
you can set these values in a class and get from them whereever you need.
First, get the intent which has started your activity using the getIntent() method:
Intent intent = getIntent();
If your extra data is represented as strings, then you can use intent.getStringExtra() method.
String etUser = intent.getStringExtra("etUser");
String key = intent.getStringExtra("key");
Refer this for more details.
I would like to tell you to use Application class. The better idea to get the reference from the following link
maintain the state of all the variables from the Application class
Bettter to go for this Application b'coz you can access all the variables in every class with out sending from intent.
This will help you.
Application Object are some way, i would go for EventBus (like OTTO from Square or Greenrobot).
Do everting on Application Context tend to create the "GOD Object" problem after quite some time. You should avoid this. SharedPreferences are also some good option.
you can use Bundle for pasing data form one Activity class to other Activity class Like this
Bundle bundle = new Bundle();
bundle.putString("Id", videoChannelId);
bundle.putString("C/V", "C");
bundle.putString("mode", "ch");
bundle.putString("code", "LiveTV");
bundle.putString("urlcount", "2");
Intent intent = new Intent(First.this,Second.class);
intent.putExtras(bundle);
startActivity(intent);
Get the data in the second class like this by giving the bundle id
Bundle getBundle = this.getIntent().getExtras();
name = getBundle.getString("Url")
etc......
I'm not really sure what you want to do, but IMO, if i will use a variable from one class to another, i will make the variable static and "get" the value of that variable from the class..
for example in one class i have a variable:
public class Login extends Activity {
static String username;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.login_layout);
username = "Your Name";
}
and in another class, i would get that value like this;
String var;
var = Login.username;
but as i've read, this is not the best practice. Sometimes it just sufficient.

Categories

Resources