How to Use UiApplication.activate() in BlackBerry - blackberry

I want to use the UiApplication.activate() method in BlackBerry. In Android, we use the onResume() method; so how do we use the UiApplication.activate() method in BlackBerry?
There is not that much info available.

It's difficult to answer this question because of the comment below Peter's answer. Activity#onResume() in Android is not normally used simply "to refresh ... UI data on the spot after making changes".
Android
onResume() is called by the Android OS when a user comes (back) to an Activity; this usually happens after leaving it ... either because another Activity was displayed in front of it, or because the user left your application and came back to it (going home and back, to the phone and back, etc.)
BlackBerry
In BlackBerry, Application#activate() is called when the user returns to your app. This callback happens at the app level. An app in Android is made of many Activies (normally). onResume() gets called separately for each Activity in your app, as the user returns to that individual Activity.
Although not identical, a similar construct in BlackBerry is the Screen class. One app may have many Screens, as Android apps have many Activities. So, if you're looking for the most similar thing to onResume(), I would try, as Peter suggested:
Screen#onExposed()
Screen#onUiEngineAttached(boolean)
To get closest to onResume(), you probably need both of those methods, because Screen#onExposed() does not get called the first time your Screen is shown (while Activity#onResume() does). You would override these methods in your own classes that extend Screen (or MainScreen, etc.)
If your problem is just determining when to refresh your UI, you'll need to explain more about what kind of UI objects (Fields) you're using, and when you get new data to display.
Update:
Here is some sample code for how you might build your main Screen class, to try to mimic Android's onResume() callback:
public final class MyScreen extends MainScreen {
public MyScreen() {
setTitle("MyTitle");
}
protected void onExposed() {
super.onExposed();
onResume();
}
protected void onUiEngineAttached(boolean attached) {
super.onUiEngineAttached(attached);
if (attached) {
onResume();
}
}
private void onResume() {
// TODO: put your Android-like processing here
System.out.println("onResume()");
}
}

There is nothing really to know about activate(). If you look at the documentation
http://www.blackberry.com/developers/docs/7.1.0api/net/rim/device/api/system/Application.html
it says:
"The system invokes this method when it brings this application to the foreground."
So if your application has been pushed to the background (for example, by a phone call), and then the user clicks on your icon to look at your application again, then activate() will be called. By contrast, deactivate() will be called when the system pushes your application to the background (for example, when a phone call is received).
Note that activate() is also called when the application is first started.
The question really is what do you do in onResume() that you need to replicate in the BlackBerry code. If you can tell us this, we might be able to suggest what is the best way to achieve the result you want.
Update
Given that you appear to be using onResume() to update a Ui, there is unfortunately, no one simple way of doing this for the entire application. The method you would use actually depends on what is being updated.
But be aware that most Fields are updated automatically when you change their contents. To give a simple example, if you have an EditField that contains data, and you use the
.setText("new data");
method, this will automatically repaint that Field on the screen for you.
I expect that you have a screen that you have populated from the database or data source, and in activate() you want to refresh this data. So you will have to go through each of the screen's Fields and use the associated set... method to update the contents.
This is slightly problematic, because activate is called for the Application, not the screen, and you might have multiple screens on the stack, and you really need to update all of them There are various methods available to do this, involving say, your screens registering themselves to be updated, or your activate() method searching the display stack for the screens there.
But possibly a simple approach is to use each screen's 'onExposed()' method to automatically update the contents. This method is called anytime the screen is hidden and then shown, which is exactly what would happen after the application has been foregrounded. It also happens when the screen is hidden by another screen being pushed on top of it, or even a user pressing the menu key. So perhaps, if the update is time consuming (for example requires a database lookup), you might want not want to update every time onExposed() is invoked, but instead try to restrict the update frequency.
This 'onExposed()' approach does not get out of the requirement to update the contents of each Field separately, but it might make it easier to implement.
Further update
Note Nate's answer, Nate has experience of both Android and BB, so can better relate to your problem.
But if you know that the screen has been updated, so you have just processed a network request that relates t that screens content, then you should go through each of the Field individually, "set"ting the updated value at that time, don't worry about using onExposed(). One design approach that accommodates this is to separate the screen construction from the screen population, so you can call the 'population' from multiple places (note that you do need to be on the Event Thread when you update the Fields).
But in this circumstance, you might find it easier and faster to create a new Screen and push that and pop the old screen (which has the old values).

Related

Observe backForwardList changes of WKWebview

To explain my problem I would like to start with the fundamentals of my project.
We are building an app which employs a web view which loads a lot of different websites (web apps) to form our app package. Those web apps are made with different web tech like ruby or ember/react (single page web app). The later change urls via push state which is problematic for the webviews WKNavigationDelegate as it doesn't recognise any of those url changes. If you load normal http requests (like old rails pages) then everything is fine and well.
In order to know on which page the user is at any time I created a user script which tapped into the pushsstate js prototype and messaged back the url change to the iOS app and even though this is A solution its in my eyes incredibly hacky. So I have been looking for alternatives and I came across the WKWebView.backForwardList which actually records all those push state changes.
The issue I have now is how do I monitor/observe the backForwardList for changes in lets say the currentItem? You can't use KVO to do so as these properties don't support it.
I did however found a possible solution by observing the webview.scrollView.contentSize which for some reason will trigger every time something changes on the screen. It's odd that this observer is fired for every single animation which is running on the screen its almost as if its called on pixel changes of the scrollview. Our web apps are animating all the time as they build with canvas elements for games which means the observer is called a lot and don't feel comfortable to have this running all the time.
Do you know a nicer/neater way to keep track of the changes WKWebView.backForwardList items.
Cheers Thomas
I found the solution which seems obvious but wasn't at the time
// Add observation.
urlObservation = webView?.observe(\.url, changeHandler: { (webView, change) in
print("Web view URL changed to \(webView.backForwardList.currentItem?.url.absoluteString ?? "Empty")", webView.scrollView.contentSize.width, webView.scrollView.contentSize.height)
})
This seems to track the url changes even though the navigation delegate are NOT triggered in any way.

iOS How to differentiate between changes to underlying data from outside vs from within the class

I am having a conceptual issue which I am not sure there is a solution for - tracing the origin of data change.
For example, in my app I have a preferences class that writes settings to user defaults, and I have set up a custom observer pattern where any class interested in a change to settings subscribes as an observer, and is notified when the setting changes. Now, if a setting changes online or on another device, the app receives the change, saves it and notifies all observers.
If I make the change within the app by going into the settings and selecting a new value, the settings class receives the change and again notifies all observers.
The problem is, that the way one would handle the change changes based on whether is the change within the class or elsewhere.
For example, let's say I let the user pick languages they would like to support. This is done through a UITableView where the user can add/remove/reorder the languages. The class that handles this is subscribed as an observer of changes to the languages property of settings, so that if I am in the page and data is changed online, the table view gets reloaded and new languages are displayed. However, when I drag the languages into a new order, I save the new order, this fires the change event of which the class is an observer, and so the table view reloads, cutting short the animation of the drag.
In short, when receiving the observer event, I would like to be able to know whether has this change been handled already (such as if it's internal and so I already dragged/inserted/removed a row) or it requires a table view reload.
Is there any pattern, concept or method that I am unaware of which addresses this?
(By the way I am writing this in Swift 4 for a universal iOS app if that makes any difference)
Thanks

Using Xcode UI tests to test underlying framework behavior

I am building an iOS framework that collects information about various events in an iOS app and performs local and remote analysis. Some of these events can't be tested outside of an app: for example, view controller transitions. To test these events, I built a test iOS app and would like to use Xcode UI tests to:
Initiate a view controller transition by, say, tapping a button that pushes a VC to a navigation controller, or by switching to a different tab in a tab controller
Verify that the framework was able to detect the view controller transitions and generate the necessary events (e.g., send them to the server)
The problem is that Xcode UI tests run outside the app, so I can't access any shared objects to verify that the framework is functioning properly. I also can't insert any mock objects, because, again, I don't have access to the framework loaded in the app's process.
I went as far as trying to load the framework in a kind of test mode and have it update a label with some results that the UI test would then be able to read. But even that is difficult, because XCUIElement doesn't give me the actual text of the element; I can only query for elements with some predefined text. I can sort of work with that, but it seems like a very roundabout approach for something that should be rather trivial.
Are there any better alternatives for testing events that can only be simulated in a running app, and then verifying that my framework was able to detect and process them? In addition to view controller transitions, I am also interested in touch interactions, accelerometer events, and other features that can't be simulated outside of an app. Naturally, I can simulate these events for unit testing, but I would also like to automatically test that when these events occur in an actual app, the proper responses are generated in my framework.
You could try using SBTUITestTunnel. This library extends the functionality of UI Tests adding some features that might come in handy in cases like yours.
Network monitoring
The library allows your test target to collect network calls invoked in the app. Usage is pretty straight forward:
func testThatNetworkAfterEvent() {
// Use SBTUITunneledApplication instead of XCUIApplication
let app = SBTUITunneledApplication()
app.launchTunnelWithOptions([SBTUITunneledApplicationLaunchOptionResetFilesystem]) {
// do additional setup before the app launches
// i.e. prepare stub request, start monitoring requests
}
app.monitorRequestsWithRegex("(.*)myserver(.*)") // monitor all requests containing myserver
// 1. Interact with UI tapping elements that generate your events
// 2. Wait for events to be sent. This could be determined from the UI (a UIActivitiIndicator somewhere in your app?) or ultimately if you have no other option with an NSThread.sleepfortimeinterval
// 3. Once ready flush calls and get the list of requests
let requests: [SBTMonitoredNetworkRequest] = app.monitoredRequestsFlushAll()
for request in requests {
let requestBody = request.request!.HTTPBody // HTTP Body in POST request?
let responseJSON = request.responseJSON
let requestTime = request.requestTime // How long did the request take?
}
}
The nice thing of the network monitoring is that all the testing code and logic is contained in your test target.
Custom block of code
There are other use cases where you need to perform custom code to be conveniently invoked in the test target, you can do that as well.
Register a block of code in the app target
SBTUITestTunnelServer.registerCustomCommandNamed("myCustomCommandKey") {
injectedObject in
// this block will be invoked from app.performCustomCommandNamed()
return "any object you like"
}
and invoke it from the test target
func testThatNetworkAfterEvent() {
let app = ....
// at the right time
let objFromBlock = app.performCustomCommandNamed("myCustomCommand", object: someObjectToInject)
}
Currently you can only inject data from the test target -> app target. If you need the other way around, you could store that data in the NSUserDefaults and fetch it using the SBTUIApplication's userDefaultsObjectForKey() method.
I personally don't like the idea of mixing standard and test code in your app's target, so I'd advise to use this only when really needed.
EDIT
I've update the library and starting from vision 0.9.23 you can now pass back any object from the block to the test target. No need for workarounds anymore!
Not much of an automated way to have things done, but do use breakpoints as an intermediate way, at least until you get things started automatically. You can add a symbolic breakpoint to hit on UI methods such as [UIWindow setRootViewController:], viewWillAppear, etc.
You can explicitly define modules, conditions and actions, so that whenever someone views your VC, some action will be done that might be helpful to you.
If you can print something from your framework using a simple "po myEvent" upon some viewDidAppear, you're good to go. I've never tried using fancier methods as an action, but those can be done as well.

iOS Cross Cutting Concerns

I have a Swift application i'm working on that allows a user to save various settings about their profile. Throughout my code, there are times where knowing these settings/preferences are important for the application's business logic. One of them is where the user works (their job, (which is a row in a sqllite database that has an ID as a primary key). The user is allowed to select one (and only one) in the app at any given time. Think of it like a profile - they can work many jobs, but only have one selected.
The following are scenarios where knowing the workplaceid profile is important:
In my sqllite database, retrieving work/shift information based upon the currently selected work ID(so not the ID from the database, but the ID they currently have selected). I'm passing this into my query.
In an NSDate extension function, when I go to determine some things about their starting date, I need to retrieve their currently selected profile, and use that for the calculation.
Within a particular view model when I want to show/hide certain fields.
On an alert view to show something related to their current workplace.
Now I think the quick and dirty way to do this is simply create a wrapper class to your nsuserdefaults in a utility class. Sure, all your info is stored in sqllite, but your currently selected app preferences are in nsuserdefaults since I can change this around (and it will change). This would parallel my other cross-cutting concerns such as logging/error handling, where I could use similar utility classes for all my work.
The fact that I might call this helper/utility class from every single layer of my application seems like a typical red flag you wouldn't do. Whether it's logging, or a user service to get information.
I'm curious to know what other people are doing in scenarios like this. When you need nsuserdefaults from all over your app, is the answer "eh who cares, just make a utility class and call it wherever you need it" ? Or is there a best practice others have followed with well-designed iOS apps? I know AOP is something folks tend to recommend. Does that have a place in iOS?
Thanks so much stackoverflow :)
The user is allowed to select one (and only one) in the app at any given time.
This tells me you want to create a singleton class. Every time you want to change the profile, you hit the singleton class and set it. That class encapsulates all the logic to get/set whatever you need, and the accessor functions. That's what I've been doing in my ObjC code for many years, and it has served me well. It's extremely easy to debug, and the rest of the code needs to know nothing about profile management (unless it's the UI part where you choose a profile).

Tracking/Instrumenting events/methods fired

I am trying to print out (e.g., NSLog) the information about events that fired on iPhone application. For example user executes a scenario and I want to track all the methods called and events clicked by the user.
Is there anyway to do that using a category extension and method swizzling features of objective-C to inject some code to log and print the information needed? Right now, I defined a category for UIWindow, UIApplication and UIView. I am not sure where is the best place to track tho, e.g., [UIWindow sendEvent:]? Should I observe objc_msgSend()?
I basically want to instrument a project and inject code with category extension in order to not change the source code as much as possible.

Resources