Saving and reading int values in case of app close - basic4android

I've created an application which contains settings as int values... Basically my app contains multiple layouts. When the user presses the "back" key, the app returns to the first panel (which is the main screen!). If pressed on the main screen, the app will pause/finish.
The integer values that I have are what I use to determine whether the user has done something in the app. They also determine which layout the user is in.
I really need to have these int values for when the user opens the app again. What is the best way that I should go about saving multiple int values so that I can access them if the app is killed?
Thanks
Sorry... I'm finding it really hard to write and read to and from a map file... Here is what I have so far simplified. Can you see if I am missing something... more than likely its really easy.
Sub Activity_Resume
Dim m As Map
m.Initialize
If File.Exists(File.DirInternal, "1.txt") Then
m = File.ReadMap(File.DirInternal,"1.txt")
int1 = m.Get("int1")
int2 = m.Get("int2")
End If
End Sub
Sub Activity_Pause (UserClosed) As Boolean
Dim m As Map
m.Initialize
m.Put("int1", int1)
m.Put("int2", int2)
File.WriteMap(File.DirInternal, "1.txt", m)
End Sub

You have several options. You can use StateManager or you can store the settings in a Map and then in Activity_Pause save the Map with File.WriteMap, and read the Map in Activity_Create if the file exists.

Related

How can I check if the user is playing the game for the first time?

I want to show a text for the first time running like "Hi, my name is NAVI." and then when the player will start the game again the next time it will another text for example "Welcome back."
Using player prefs is probably the easiest solution, though definitely not the only one*.
Due to the lack of boolean playerpref I usually opt to use SetInt/GetInt instead, but that's personal preference. You could also do it with a string or float.
private void Start()
{
if(PlayerPrefs.GetInt("HasLaunched", 0) == 0)//Game hasn't launched before. 0 is the default value if the player pref doesn't exist yet.
{
//Code to display your first time text
}
else
{
//Code to show the returning user's text.
}
PlayerPrefs.SetInt("HasLaunched", 1); //Set to 1, so we know the user has been here before
}
Playerpref stores values between sessions, so the next session will still have "HasLaunched" set to 1. This is however stored on the local device. so users can manually reset it if they'd really want to.
If you ever want to show the "first launch" text again, simply set HasLaunched back to zero, or delete it altogether with DeleteKey("HasLaunched");
*There are plenty of alternative solutions, like storing it in a config file locally, or using a remote database (this would be required if you don't want users to be able to reset it). They would however come down to the same principle. Setting a value to true or 1 somewhere, and checking that value on launch.

Close session of choice in unified service desk

We have multiple sessions i-e four sessions opened in USD. I need to close without clicking on 'X' on the session.
Can it be possible to have 4 buttons on the toolbar and by clicking the third button will close the third session in USD?
This should be possible provided that Microsoft's documentation is valid. Even if it is possible, it would be crude, limited, and difficult to implement/maintain without writing custom code. I highly recommend a "close current session" button that simply closes the foreground session. Through configuration however, here's how you could theoretically do what you're asking.
Create a Close button for each session, considering your max number of sessions, let's say 4. On start of a new session, a series of actions fires in an attempt to locate a Close button upon which to attach the session close command, based on logic like this:
Does Global Context variable Session1ID have data?
If not, place the new session ID in Session1ID.
Does Global Context variable Session2ID have data?
Is the new session ID already stored in Session1ID?
If not, place the new session ID in Session2ID.
Does Global Context variable Session3ID have data?
Is the new session ID already stored in Session1ID or Session2ID?
If not, place the new session ID in Session3ID.
Does Global Context variable Session4ID have data?
Is the new session ID already stored in Session1ID, Session2ID, or Session3ID?
If not, place the new session ID in Session4ID.
The buttons themselves could be made visible or enabled based on whether their Session ID is in Global Context.
On click of any of these buttons, let's say #3, the following would occur:
Close Session command using Session3ID
Nullify value of Session3ID, making it available for the next attempt to attach a session ID.
I foresee a few problems with this. You may encounter issues reading from and writing to Global Context variables while inside of a session. Furthermore, you may encounter issues with closing background sessions by their ID.
Further still, closing sessions out-of-sequence would cause new sessions to attach to buttons in a disorderly-looking fashion, creating a bad user experience. Let's say you need to start six sessions (A, B, C, D, E, and F). You have to close the two sessions in the middle (B and C) before starting the last two due to your limit of 4. With A on button 1 and D on button 4, you start sessions E and F which attach to buttons 2 and 3. Now your four buttons correspond to sessions A, E, F, and D, while the session tabs themselves are in the order that you opened them: A, D, E, F. This would be a bad user experience. (I don't believe that you can manipulate the order in which buttons appear using replacement parameters. Button Order is likely to be configuration integers only.)
Hopefully, this clarifies the elegance of a simpler solution: Create a "Close Current Session" button that is only enabled or visible while you have a session.

Create a Resolution Independent Form in ms access

I have designed my form in 1280*1024 resulotion. They lookvery nice on my Monitor, but If I see on another Monitors, they look very chaotic . Is there a way that I solve this problem?
It's not so easy. This is where MVC comes in very handy and you can distinguish between different components. You can have different views for different devices. Unfortunately VBA does not support that and you would have to implement your own framework to handle different screen resolutions.
The easiest way to avoid having to re-implement the design of your userform is to actually DESIGN it in your head before writing a single line of code. Think of the different resolutions(devices) your software is going to support, what the language you are using is supporting and what are your choices. Generally, think it over. In VBA I normally just go for the default size to avoid the headache of fitting someone's else screen.
You would have to redesign the entire UserForm. Not visually, but programmatically set both width, and height of the userform and make controls dependable on the current resolution. I do not recommend doing it this way but still this could be a solution.
You can achieve that by accessing the current resolution and modifying your Userform_Initialize() event.
So example, if the current resolution is 1024x768, you set the width and height to currentWidth-100px and currentHeight-100px.
If you open a new workbook and create an empty userform. Go to its code behind and add
Private Sub UserForm_Initialize()
Me.Width = GetCurrent(0) - 600
Me.Height = GetCurrent(1) - 800
End Sub
Then insert a module and add
Private Declare Function GetSystemMetrics Lib "user32.dll" (ByVal nIndex As Long) As Long
Sub A()
UserForm1.Show
Unload UserForm1
End Sub
Function GetCurrent(x As Long) As Long
GetCurrent = GetSystemMetrics(x)
End Function
This will display a different size userform depending on the current resolution.
you can (but I wouldn't recommend it) use that technique. Note: depending on how many controls you have this may be the best approach but if you have lots of controls on the userform I would look for an alternative.
Alternatively, you can use the below code which checks the current screen resolution, warns the users and asks if the user wants to change his resolution.
The below code comes from here and the original author is DRJ
You stick the first part in the Workbook code behind
Option Explicit
Private Sub Workbook_Open()
Call VerifyScreenResolution
End Sub
and the below part in a module
Option Explicit
Private Declare Function GetSystemMetrics Lib "user32.dll" (ByVal nIndex As Long) As Long
Const SM_CXSCREEN = 0
Const SM_CYSCREEN = 1
Sub VerifyScreenResolution(Optional Dummy As Integer)
Dim x As Long
Dim y As Long
Dim MyMessage As String
Dim MyResponse As VbMsgBoxResult
x = GetSystemMetrics(SM_CXSCREEN)
y = GetSystemMetrics(SM_CYSCREEN)
If x = 1024 And y = 768 Then
Else
MyMessage = "Your current screen resolution is " & x & " X " & y & vbCrLf & "This program " & _
"was designed to run with a screen resolution of 1024 X 768 and may not function properly " & _
"with your current settings." & vbCrLf & "Would you like to change your screen resolution?"
MyResponse = MsgBox(MyMessage, vbExclamation + vbYesNo, "Screen Resolution")
End If
If MyResponse = vbYes Then
Call Shell("rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,3")
End If
End Sub
update.
your initialize event is here

Some beginner questions

I guess I'll start by saying I am very new to B4A, and to programming in general. I have some very basic java and html exp. but that's it. I do not have any basic4ppc or really any IDE experience. Been using B4A for a few days now and can't get over the hump. Here are my noob questions:
Does having many activities (20-30+) slow down the app? Is there a downside to having a lot of activities?
I can't figure out how to scroll in the designer. I am trying to make a screen that has 25 buttons down in 1 column. However I can't scroll down to add more buttons below. I am able to add buttons programmically and in the fashion that I want (using a for loop), but is it normal to create views at runtime like this?
How do you ensure your app looks the same across all devices? Tablets? I have a scroll view that fits perfect in the emulator, but on my phone (droid x), the bottom of the scroll view is not stretched to the bottom of the phone. I use the code: scvScreen1.Initialize(100%y). Is that not right?
I have a Email screen in which is comprised of an edittext and a Send button, so that the users can send me questions from the app. However the Send button gives me this error on the 'URI =' line: "LastException java.lang.NumberFormatException: mailto:" here is the code:
Sub btnSendEmail_Click
Dim Uri As String
Uri="mailto:me#gmail.com?subject=Test Email&body=" + edtHelpEmail.Text
Dim Intent1 As Intent
Intent1.Initialize(Intent1.ACTION_VIEW,Uri
StartActivity(Intent1)
End Sub
Or is there another way to open the device's default email program?
Regarding last question, how do I copy error messages to clipboard?? I selected the red error message on the bottom right of the IDE and tried ctrl-c, but didn't work.
In B4A, what is a good method of storing persistent data? All I really need to store are some strings. Nothing fancy. These strings are to be stored locally. AI made this easy by using TinyDB.
When using the designer, how do you ensure your views are centered on all devices? For instance, I have a screen that has several rows made up of: (label, edittext, label). And I want each row to be center aligned. Do I do this programmically? I'm thinking I would have to append each row of (label, edittext, label) to a panel, then in the code center the panel. Is this correct?
That's all I got for now, but I'm sure there will be plenty more questions later.
1) The whole idea of android is to small components i.e. Apps working together, so no need to worry about opening lots of activities. Memory is very well managed behind the scenes in Android.
2) Sure. That sounds fine to me. Use the Layout designer as much as you can and then add the dynamic stuff later. It's all about striking a balance between the size of your code and the number of activities.
3) In the Designer there's an option called 'Send to UI Cloud'. This compares your app over multiple screen sizes. You can also scale your design and programmatically resize specific controls within your app in the Activity_Create Lifecycle
4) What you're doing is almost correct. I corrected your code:
Sub MailTo(StrAddress As String, StrSubject As String, StrBody As String)
Dim StrMethod As String = "Sub MailTo(StrAddress As String, StrSubject As String, StrBody As String)"
Try
Dim StrUri As String
StrUri = "mailto:" & StrAddress & "?subject=" & StrSubject & "&body=" & StrBody
Dim Intent As Intent
Intent.Initialize(Intent.ACTION_VIEW, StrUri)
StartActivity(Intent)
Catch
If BlnLoudExceptions Then CdException.Show(StrClass, StrMethod, LastException)
End Try
End Sub
I tend to have a code module called CdIntent.bas for these functions as it both keeps the project organised and makes it easier to implement the same functionality across projects.
Then to call you would use
CdIntent.MailTo("me#yes.no", "Subject!", "Body!")
5) I have a file called CdException.bas
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
End Sub
Sub Show(StrClass As String, StrMethod As String, Ex As Exception)
LogColor("Exception: " & Ex.Message & " - Class: " & StrClass & " - Method: " & StrMethod, Colors.Magenta)
End Sub
and then wrap functions in the following way:
Sub FunctionName(...Parameters...) as Int
Dim StrMethod As String = "Sub Sleep(LngMilliseconds As Long)"
Dim IntResult As Int = 0
Try
[code here inc. IntResult = ???]
Catch
If BlnLoudExceptions Then CdException.Show(StrClass, StrMethod, LastException)
End Try
Return IntResult
End Sub
BlnLoudExceptions is a global boolean that you'd declare in
Process_Globals that you can switch on an off exception logs.
StrClass is a global String that you'd declare in Process_Globals
that contains the name of the class e.g. "CdIntent.bas"
The exceptions then appear in magenta in the log screen along with the method name and class in which they occurred allowing you to home in on them.
6) I have a table in an SQLLite database called TabletSettings, which has two TEXT colums called 'Name' and 'Value'. It works well and gets you into a (what I think is a) good habit of always having a database available to your app from the get-go.
7) I'll get back to you on this as I haven't done this before.
Until then, the following thread will help you in the B4A forum http://www.basic4ppc.com/android/forum/threads/convert-integer-to-dip.18800/
I agree with Jim's point but will attempt to answer 1.
I'm new to android myself but as I understand it activities on the whole are only running when active. Unless you are using the app to continuously do something there is only one activity at a time. The number of activities is likely to affect the ram available more than anything. Lastly it might be worth walking first rather than running so to speak but trying a single and then add multiple activities.
You could try adding a ListView or ScrollView where the items are the buttons, this seems to be the std way of doing things otherwise a tabbed view.

unable to get simple program logic

i m making an iphone app in which when same person calls you and u dont pick the phone then the a sound will be played when same user calls u more than 4 times ,now when a call is incoming i am storing its callid in a string or whatever but my problem is i cant find logic to check that the same user has called four times or more??
Use an NSDictionary (a form of hash database). If the current callers name isn't there as the key, add it, and set the value to be count of 1. If the callers name exists as a key in the dictionary, increment the count value by 1. After that, read the count value and do whatever you want depending on the comparison against 4.
But getting the callers name may require some sort of non-stock OS on an iPhone.
Hm.
Loop through an array of received calls.
Instead of storing the callerId in a string, store it in an array called receievedCalls.
During each incoming call, loop through the array (foreach loop?), looking for the callerId of the current caller.
foreach (receivedCalls as $key => $value) {
if ($value == $callerId) {
count++;
}
if (count >= 4) {
(play sound)
}
}
Probably flawed logic but meh. Again, I haven't worked with iPhone apps before so I don't know what kind of language it uses.
No API for that, Sorry.