Application class can be used for store data? (persistent data) - persistence

I'm trying to use Android Application class (MyApplication.java) for store data in some ArrayLists of strings and ints
I want that these data get's stored forever, like a database, but without using databases, to simplify my app.
Currently the data get's stored when I exit of the app only when the process of the app is still on background. But if i kill the process of the app, the data stored on MyApplication.java class get's removed.
There is a way to solve this?
Code resumed:
public class MyApplication extends Application {
public static String LeagueTable[][] = new String[21][8];
//COLUMNAS MATRIZ:
//0 /1 /2 /3 /4 /5 /6 /7
//nombre/P.J./P.G./P.E./P.P./G.F./G.C./Pts
public static League LFP = new League();
public static Category Primera = new Category(20);
public static int NEQUIPOS=20;
public static int[][] matriz= new int[NEQUIPOS+1][NEQUIPOS+1]; //esta es la matriz de emparejamientos, representa el calendario
public static int PlayerTeamID;
public static boolean ExistingSaveGame=false;//esto es true cuando existe una partida guardada
//variables candidatas a poner dentro de una de las clases del modelo, como season por ejemplo
public static int RoundNumber; //jornada actual
public static boolean SeasonOver=false;//true cuando la temporada ha terminado
public void onCreate() {
super.onCreate();
}
public void onTerminate() {
super.onTerminate();
}
"and a lot of functions that works with the static variables"

No it can not. If you don't store your data in storage (that doesn't need to be a db, could be a flat file or whatever) then it is not persistent.

Related

Trying to record level time data and print to screen at the end Unity 2D

So I have a 2D platformer parkour game which holds a timer when player starts level. I have 5 levels and at the end of each level, I want to keep the last time value and display them at the end of the game.
So far, I tried to hold the last time value when player triggers the End portal and store them in an array in the code below. Here are the scripts:
Time Data Manager Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
void Start(){
}
void Update(){
Debug.Log(timeDataArr[SceneManager.GetActiveScene().buildIndex-1]);
}
public void AddTimeData(string timeData, int levelBuildIndex){
timeDataArr[levelBuildIndex-1] = timeData.ToString();
}
}
End Portal Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class EndPortal : MonoBehaviour
{
public AudioSource aSrc;
private int sceneNumber;
public GameObject bgAudio;
public Text scoreText;
string textData;
public timeDataManager tDManager;
void Start(){
sceneNumber = SceneManager.GetActiveScene().buildIndex;
tDManager = GameObject.FindGameObjectWithTag("TimeDataManager").GetComponent<timeDataManager>();
}
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
aSrc.Play();
Destroy(bgAudio);
textData = scoreText.text;
Debug.Log(textData);
Debug.Log(sceneNumber);
tDManager.AddTimeData(textData,sceneNumber);
SceneManager.LoadScene(sceneBuildIndex:sceneNumber+1);
}
}
}
As I said before, I tried to keep all timer values at the end of each level and store them in an array in my timeDataManager script. But it's not working.
Any ideas on how to fix? Or do you have any other ideas? Thanks a lot for your time.
Issylin's answer is a better solution for your needs but i want to mention couple of things about your code.
One thing about your timeDataArr. If you don't touch it in inspector, you need to initialize it first. So let's say, if you want to hold 5 levels of time data, you need to do something like;
public string[] timeDataArr = new string[5];
or
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
public int sceneAmount_TO_HoldTimeData = 5;
void Start()
{
timeDataArr = new string[sceneAmount_TO_HoldTimeData];
}
}
or
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
public int sceneAmount_NOT_ToHoldTimeData = 1;
void Start()
{
timeDataArr = new string[SceneManager.sceneCountInBuildSettings - sceneAmount_NOT_ToHoldTimeData];
}
}
Another thing is you need to be careful about levelBuildIndex-1. If you call that in first scene,
SceneManager.GetActiveScene().buildIndex
will be 0 and levelBuildIndex-1 will be -1 or in Debug part it will be timeDataArr[-1] but array indexes must start with 0. So it will throw an error.
One more thing, this is not an error or problem. Instead of this part
tDManager = GameObject.FindGameObjectWithTag("TimeDataManager").GetComponent<timeDataManager>();
you can do
tDManager = FindObjectOfType<timeDataManager>();
There are several way to achieve what you're trying to do.
The easier would be to use a static class for such a simple data like the one you're carrying through your game.
using System.Collections.Generic;
public class Time_Data
{
/// TODO
/// Add the members
/// e.g. your time format as string or whatever,
/// the scene index, etc
}
public static class Time_Manager
{
private static List<Time_Data> _times;
public static void Add_Time(in Time_Data new_time)
{
_times.Add(new_time);
}
public static List<Time_Data> Get_Times()
{
return _times;
}
public static void Clear_Data()
{
_times.Clear();
}
}
Use it like any other static methods within your OnTriggerEnter2D call.
Time_Manager.Add( /* your new data here */ );
The other way, if you intend to stay with a game object within your scenes, would be to use the DontDestroyOnLoad method from Unity so your game object which has your script timeDataManager would remain.
Note that in your code, using string[] might be unsafe. For your use of it, consider using a List<string>.

Calling protected variable from another class

I need to call a protected variable from a public class into an if statement in a private method of another public class
I am programing a video game in unity and I need to use a bool variable (that shows if the character is out of stamina) in an if statement to determine whether or not the character can run
This is what my code looks like excluding everything unrelated to the problem
Public class CharacterStats : MonoBehaviour
{
[SerialzeField] protected bool Tired;
}
Public class PlayerMovement : MonoBehaviour
{
Private void HandleRunning()
{
If (Input.GetKeyDown(KeyCode.LeftShift) && X != True)
{
Speed = RunSpeed;
}
}
}
X is where I want the Tired variable to be.
Use a public readonly property like e.g.
public class CharacterStats : MonoBehaviour
{
// Keep you serialized field protected
[SerialzeField] protected bool tired;
// Have a public read-only accessor property
public bool Tired => tired;
}
and then e.g.
public class PlayerMovement : MonoBehaviour
{
// Somehow you will need to get a reference to the CharacterStats instance
// e.g. via the Inspector
[SerializeField] private CharacterStats stats;
[SerializeField] private float RunSpeed;
private float Speed;
private void HandleRunning()
{
if (Input.GetKeyDown(KeyCode.LeftShift) && !stats.IsTired)
{
Speed = RunSpeed;
}
}
}
Alternatively (and my apologies to #aybe who had answered this) you can actually directly serialize a property using explicitely
[field: SerializeField] public bool Tired { get; protected set; }
this is a property which can be accessed by everyone but only this and inherited classes (and due to the serialization now the Inspector) have the permission to set the value.
In general: Fix your casing! In c# all keywords are lower key!

Way to find all affected locations by variable

I want to find code lines, where a certain property can get.
Consider I have property holder class and in java editor look to some setter method. In code is property readed and setted to entity. And before save to database, do validation on server side. So I want see from client.propertyHolder.setter to server.entityValidator.getter
Simple example
public class Main{
public static void main(String[] args) {
Holder h = new Holder();
h.setHolder("Something"); // Here i want use plugin
Entity e = new Entity();
e.setName(h.getHolder());
// Consider this is on server side in validator and call only if annotation validation is OK
Assert.assertTrue(e.getName().length() > 0)
}
}
public class Holder{
public String holder = null;
public void setHolder(String holder){this.holder = holder}
public void getHolder(){return holder}
}
public class Entity{
#javax.validation.constraints.NotNull
private String name = null;
public void setName(String name){this.name = name}
public void getName(){return name}
}
So i should get lines
e.setName(h.getHolder());
Assert.assertTrue(e.getName().length() > 0)
and be nice if NotNull anotations too
Is there a way, how to achive this? Some good free eclipse-plugin maybye?
Thanks for help. Pavel

Overriding Getters and Setters in tinkerpop Frames annotated model

I'm working on a new piece of software and I'd like the values in the database to be encrypted. We are using OrientDB and are trying to implement the project using the tinkerpop libraries. Here I'm stuck a little bit.
For one function, I need to pull a list of all vertices of a type and return them. I have my annotated interface for the person object, and I added methods to encrypt and decrypt necessary fields right now. But when I decrypt them, it persists the decrypted values back to the database.
Is there a way to either override the getters and setters to handle the encryption/decryption at that point or do I need to detach the models from the db before performing my decryption?
Here's my code for my interface:
public interface iPerson {
#Property("firstName")
public void setFirstName(String firstName);
#Property("firstName")
public String getFirstName();
#Property("lastName")
public String getLastName();
#Property("lastName")
public void setLastName(String lastName);
#Property("id")
public String getId();
#Property("id")
public void setId(String id);
#Property("dateOfBirth")
public String getDateOfBirth();
#Property("dateOfBirth")
public void setDateOfBirth(String dateOfBirth);
#JavaHandler
public void encryptFields() throws Exception;
#JavaHandler
public void decryptFields() throws Exception;
public abstract class Impl implements JavaHandlerContext<Vertex>, iPerson {
#Initializer
public void init() {
//This will be called when a new framed element is added to the graph.
setFirstName("");
setLastName("");
setDateOfBirth("01-01-1900");
setPK_Person("-1");
}
/**
* shortcut method to make the class encrypt all of the fields that should be encrypted for data storage
* #throws Exception
*/
public void encryptFields() throws Exception {
setLastName(Crypto.encryptHex(getLastName()));
setFirstName(Crypto.encryptHex(getFirstName()));
if(getDateOfBirth() != null) {
setDateOfBirth(Crypto.encryptHex(getDateOfBirth()));
}
}
/**
* shortcut method to make the class decrypt all of the fields that should be decrypted for data display and return
* #throws Exception
*/
public void decryptFields() throws Exception {
setLastName(Crypto.decryptHex(getLastName()));
setFirstName(Crypto.decryptHex(getFirstName()));
if(getDateOfBirth() != null) {
setDateOfBirth(Crypto.decryptHex(getDateOfBirth()));
}
}
}
}
(I assume) Data is persisted to the database when a Vertex's property is set. If you want to store encrypted values in the database, then you need to ensure the value is encrypted when the property is set.
If you want to override the default behaviour of the #Property getter/setter methods (so that you can add en/decryption), I'd recommend using a custom handler (e.g. #JavaHandler).
For example:
IPerson
#JavaHandlerClass(Person.class)
public interface IPerson extends VertexFrame {
#JavaHandler
public void setFirstName(String firstName);
#JavaHandler
public String getFirstName();
}
Person
abstract class Person implements JavaHandlerContext<Vertex>, IPerson {
#Override
void setFirstName(String firstName) {
asVertex().setProperty('firstName', encrypt(firstName))
}
#Override
String getFirstName() {
return decrypt(asVertex().getProperty('firstName'))
}
static String encrypt(String plain){
return plain.toUpperCase(); // <- your own implementation here
}
static String decrypt(Object encrypted){
return encrypted.toString().toLowerCase(); // <- your own implementation here
}
}
Usage example (Groovy)
// setup
IPerson nickg = framedGraph.addVertex('PID1', IPerson)
IPerson jspriggs = framedGraph.addVertex('PID2', IPerson)
nickg.setFirstName('nickg')
jspriggs.setFirstName('jspriggs')
// re-retrieve from Frame vertices sometime later...
IPerson nickg2 = framedGraph.getVertex(nickg.asVertex().id, IPerson)
IPerson jspriggs2 = framedGraph.getVertex(jspriggs.asVertex().id, IPerson)
// check encrypted values (these are stored in the DB)...
assert nickg2.asVertex().getProperty('firstName') == 'NICKG'
assert jspriggs2.asVertex().getProperty('firstName') == 'JSPRIGGS'
// check decrypted getters...
assert nickg2.getFirstName() == 'nickg'
assert jspriggs2.getFirstName() == 'jspriggs'
If using Groovy, you could intercept calls to these methods programatically (which would be nice because you could keep using #Property annotations).
I'm not sure if there's a Tinkerpop solution to intercepting these calls, other than writing your own custom handler (maybe try extending the JavaHandlerModule?).
Thanks for the comment, and I should have gotten back to respond to this sooner, but I recently found a better answer to my problem. I was looking for a way to make the encrypt/decrypt happen without overhead and without developers really noticing it happens.
The better way to tackle this issue was actually to write hooks for before insert/update and after read to handle it just at the database layer. I was able to write it in java, package a jar file for it and install it on our orientDB instance, picked up pretty flawlessly and helped us to encrypt the necessary fields without noticing any speed decreases.

Global application class with stack of activities

Stemming from this article more efficient way of updating UI from service I was wondering if I could take that a step further and implement the following. I may have a misunderstanding of my Apps lifecycle though.
public class MyApplication extends Application {
private static final String TAG = MyApplication.class.getSimpleName();
private static Stack<MyActivity> mActivityStack = new Stack<MyActivity>();
private static String mTopActivity = "none";
public static void pushActivity(MyActivity activity)
{
mActivityStack.push(activity);
mTopActivity = activity.getClass().getSimpleName();
Log.i(TAG, "push::"+mTopActivity);
}
public static void popActivity()
{
Log.i(TAG, "pop::"+mTopActivity);
mActivityStack.pop();
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.w(TAG, "low memory!!!");
Log.w(TAG, "Current::"+mTopActivity);
}
}
public class MyActivity extends Activity
{
private static final String TAG = MyActivity.class.getSimpleName();
public void onCreate(Bundle last)
{
super.onCreate(last);
MyApplication.pushActivity(this);
}
public void onDestroy()
{
super.onDestroy();
MyApplication.popActivity();
}
}
Would the stack be valid during the lifecycle of the application?
As CommonsWare said, this did not work out. Also, it is not a great idea to derive from Activity, because you would then have to also derive listactivity, preferenceactivity, etc. Obviously, I did not think this would solve any problem it was just an experiment in android life cycles.
Would the stack be valid during the lifecycle of the application?
Of course it won't be valid. You assume every activity is created and destroyed in the same sequence. They won't be in many cases (e.g., user presses HOME).
Whatever problem you think you are solving this way, this is not the right solution by any stretch of the imagination.