FMX: destruction of visible controls in tab at runtime - android

RAD Studio 10.2, c++, FMX:
I have a function that takes XML from a server and programmatically instantiates controls (typically TSpeedButton instances) on a tab of a TTabControl like this:
void TForm1::SetupUserControlsFromXML(_di_IXMLDocument &XMLDoc)
{
...
UserControls->ClearAll();
...
// Various controls instantiated and displayed.
...
}
The ClearAll method below clears all controls from the previous call of the above function. Note that TUserControls class inherits a TList.
void TUserControls::ClearAll(void)
{
TUserControlType *Ctrl;
TSpeedButton *Button;
TLabel *Label;
while (TList::Count) {
// Delete controls.
Ctrl = reinterpret_cast<TUserControlType *>(Items[0]);
switch (Ctrl->ControlType) {
case ctButton:
Button = reinterpret_cast<TSpeedButton *>(Ctrl->Control);
...
Button->Parent = NULL;
delete Button;
break;
case ctLabel:
Label = reinterpret_cast<TLabel *>(Ctrl->Control);
...
Label->Parent = NULL;
delete Label;
break;
}
// Now delete struct instance.
delete Ctrl;
// Remove pointer from list.
Remove(Ctrl);
}
...
}
The TUserControlType struct is like this:
typedef struct {
enum TVisibleControlType ControlType;
...
TControl *Control;
} TUserControlType;
If the device disconnects from the server and then reconnects, it calls the SetupUserControlsFromXML() again, clears the controls and repopulates the tab.
The problem is, when the controls are cleared (destroyed), bad things happen, but ONLY if that tab (and hence the controls) are displayed. I get a class segmentation fault (11). I find the occasional pointer to a design time component is NULL!
This problem doesn't occur if the tab (and hence controls) are not displayed. Rarely, the call stack shows that the exception happened in the tab controls redraw function.
Any suggestions? It's probably obvious... I even tried hiding the control first before deleting it but the result is the same.
I've been stuck on this for a week now!
Cheers.

Related

Extent Report Issue Parallel testing

I have the following Reporting code:
public class Reporting {
private ExtentHtmlReporter extentHtmlReporter;
private static ThreadLocal<ExtentReports> extentReports = new ThreadLocal<>();
private static ThreadLocal<ExtentTest> extentTest = new ThreadLocal<>();
public synchronized ExtentTest createInstanceReport(String testCaseName) {
System.out.println(extentReports.get());
new File(Constants.userDir + "/Reports/").mkdirs();
// To generate report with name
extentHtmlReporter = new ExtentHtmlReporter(
Constants.userDir + "/Reports/" +
"ExecutionReport_" + new SimpleDateFormat(
Constants.date).format(new Date()) + ".html");
// Setting Document Title
extentHtmlReporter.config().setDocumentTitle("Demo");
// Setting Report Name
extentHtmlReporter.config().setReportName("Demo Automation");
// Setting Theme
extentHtmlReporter.config().setTheme(Theme.STANDARD);
// Setting Chart location
extentHtmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
// Setting Chart visibility
extentHtmlReporter.config().setChartVisibilityOnOpen(false);
// Setting Time stamp
extentHtmlReporter.config().setTimeStampFormat("yyyy-MM-dd HH:mm:ss");
// Setting append exist as true
extentHtmlReporter.setAppendExisting(true);
ExtentReports extentReports = new ExtentReports();
extentReports.attachReporter(extentHtmlReporter);
// Setting system info
extentReports.setSystemInfo("Name",
BaseTest.prop.getProperty(Constants.testerName));
extentReports.setSystemInfo("Environment",
BaseTest.prop.getProperty(Constants.environment));
extentReports.setSystemInfo("Browser",
BaseTest.prop.getProperty(Constants.browser));
Reporting.extentReports.set(extentReports); // Instead of using here extentReport thread like this, Can anyone suggest to use it directly
// Add test case name in report
ExtentTest extentTest = Reporting.extentTest.get();
extentTest = Reporting.extentReports.get().createTest(testCaseName);
Reporting.extentTest.set(extentTest);
// Assigning categories
extentTest.assignCategory(MultiFunction.getProp()
.getProperty(Constants.browser));
System.out.println(Reporting.extentReports.get());
System.out.println(Reporting.extentTest.get());
return extentTest;
}
public synchronized ExtentTest getExtentTest() {
return extentTest.get();
}
public synchronized ExtentReports getInstanceReport() {
return extentReports.get();
}
public synchronized void remove() {
extentReports.remove();
extentTest.remove();
}
}
I was trying parallel testing using TestNG (and will have to use Selenium grid and sauce in future). I execute 2 test cases then only one test case result is added in the report.
I have isolated the extentTest, extentReporter and WebDriver instances using threadPool.
Tried below with extentHtmlReporter instance:
1) Tried to make it static(no luck)
2) Tried to make it local (the same behaviour, getting only 1 test case result)
3) Tried as a non-static global variable ( no luck)
Could you suggest how to solve the above issue?
Please note: Only one report is generated. But when I tried to run parallel test cases in debug mode reports are generated for both the test case. I think because one test case gets over its killing some instance (when running in non-debug mode)
Also, I want to redesign the following place in my code:
For extentRpeort, I am using:
Reporting.extentReports.set(extentReports);
To add extentReport instance to my extentReport Thread.
Instead of adding like this I want to use it directly so as to reduce line of code.
If I understand correctly you have to generate Report from all executed TestNG cases.
However, from code which you shared, it is very visible that you will have some trouble with it. You are making a few critical mistakes and result are obvious:
For generating reports with TestNG I will suggest grabbing information about test execution from TestNG listener. Something like:
public final class TestNGListener extends TestListenerAdapter implements IInvokedMethodListener, ISuiteListener {
#Override
public void onStart(ITestContext context) {
Logger.info(buildMessage(Logger.PREFIX_TEST_STARTED, context.getName()));
}
#Override
public void onFinish(ITestContext context) {
Logger.info(buildMessage(Logger.PREFIX_TEST_FINISHED, context.getName()));
}
#Override
public void onTestStart(ITestResult result) {
Logger.info(buildMessage(Logger.PREFIX_METHOD_STARTED, getMethodName(result)));
}
#Override
public void onTestSuccess(ITestResult result) {
Logger.info(buildMessage(Logger.PREFIX_METHOD_SUCCESS, getMethodName(result)));
processTestResult(result);
}
#Override
public void onTestFailure(ITestResult result) {
Logger.info(buildMessage(Logger.PREFIX_METHOD_FAILED, getMethodName(result)));
}
You can't do everything in one method! You broke Single Responsibility Principle. Your createInstanceReport() is doing all jobs (setting report details, set system info, attach an executed test case to report) at one place. You have to redesign this logic to some logical separate operations. After redesigning your problem with the next line:
Reporting.extentReports.set(extentReports)
Could successfully disappear.
You have to consider a case, why you need to use exactly Extent, Reports Version 3. TestNG has test reports from the box. They are poor but they are presented out of the box. If you want just to improve it a little bit you could use ReportNG over TestNG.
It is quite easy to configure: Configuring ReportNG with TestNG for HTML Reports.
It isn't maintained, but it makes TestNG reports really eye candy and understandable.
Anyway, my suggestion is to use TestNGListener for getting info about test cases execution. And read more about good programming practice.
Work with TestNG/jUnit (or other runner framework that you are using) listener, here is a good example how to do it.
Do not put everything in a single class.
https://www.swtestacademy.com/extent-reports-version-3-reporting-testng/
The issue was with the flushing of extent report instance.
I was using ThreadLocal for storing extent report instance and was flushing the wrong instance.

Race condition in android dlopen()?

My Android app has a simple "loader" NativeActivity with a very simple android_main() which only loads a different shared object and passes control to it:
typedef void (*Tandroid_main)( android_app*);
void android_main( android_app* state )
{
void* glib = dlopen("libmain.so", RTLD_NOW);
void* fmain = dlsym(glib, "android_main");
Tandroid_main libmain = (Tandroid_main)fmain;
libmain(state)
}
This works well.. about half of the times. Other times it crashes since dlopen() fails and return NULL with errno=2 (No such file).
Due to the strange inconsistency of this occurrence I suspected a timing issue and indeed, adding a sleep(1) before dlopen() stopped it from happening. Something more robust than sleep(1) would be just trying it in a loop:
int count = 0;
void* glib = dlopen(soName, RTLD_NOW);
while(glib == NULL) {
sched_yield();
++count;
glib = dlopen(soName, RTLD_NOW);
}
The count I'm getting from this loop is usually something in the range of 10-70 on my device. But this is a hackish ugly solution.
What is really going on here? How come I can only load other shared objects only slightly after the NativeActivity starts? Is there a better way to find when when it's safe to load it?
It should be noted that I am also calling System.loadLibrary("main") from my NativeActivity's onCreate()
Not sure, but it is recommended to call loadLibrary() from a static initializer:
public class MainActivity extends Activity {
static {
System.loadLibrary("main")
}
...
}
Does it help?

Android application crashing when stepping into a method of a base class

I'm very new to Android programming and I am using Android Studio to target a Nexus 9. So far it's been a good/great experience.
I'm finally encountering some odd behavior though, when I tried something a little advanced -- sorry for the oddball question, I'd be happy with just some troubleshooting tips, since the observations don't give me much to go on. Here goes...
I have one class derived from another, as follows:
cWidget, which has method OnMyEvent()
cFrame extends cWidget, overrides OnMyEvent()
Each of my cWidgets (and hence my cFrames) has a linked list of "child" cWidgets (and/or cFrames), to form a tree structure. In both my cWidget.OnMyEvent() method and the cFrame.OnMyEvent() override I loop through the child cWidgets and call the OnMyEvent() on each -- so that my event is kind of "passed down" through the hierarchy by traversing the tree. My hope is that if the child is a cWidget it calls cWidget.OnMyEvent() and if it's actually a cFrame it calls the cFrame.OnMyEvent() override (this is how it would work in .NET, I should write some code to verify this is how it works here in Java but I realize now this is currently an assumption).
The problem: when I debug and set a breakpoint in cWidget.OnMyEvent() it never fires, even though there are definitely cWidgets in the tree. When I breakpoint on the call from cFrame.OnMyEvent() to a child cWidget.OnMyEvent(), and I inspect all the local variables, everything looks right; ie the child is a cWidget as expected, and nothing is null... but if I resume execution it still does not trip the breakpoint in the cWidget.OnMyEvent() as expected, it just passes over it. Even weirder, if I "Step Into" the call to cWidget.OnMyEvent(), my application halts with an "Unfortunately, MyFirstApp has stopped", and no exception report in my logcat.
So... very sorry for the long description but I'm not sure what's important and what's not. Without an exception report I'm not sure how to treat this problem, and there is some chance I am breaking some rules by linking together parents and children in the same tree and hoping Java knows whether to call the base method or the override. (This worked in .NET, and so far everything there has worked here but maybe not in this case.)
Thanks a lot for any thoughts or troubleshooting tips.
EDIT: I boiled it down and tested it, get similar results but still don't know why. I defined cA with an AddChild and Handle method, then derived cB and overrode Handle. I created a tree (two cAs as children of a cB) and then called cB handle. When I try to build a tree and call Handle it crashes. I'm guessing I'm trying a .NET trick that is disallowed here.
// *************
// BASE CLASS WITH AddChild, Handle
// *************
public class cA
{
public int m_Tag = 0;
protected cA ptr_FirstChild = null;
protected cA ptr_LastChild = null;
protected cA ptr_Parent = null;
protected cA ptr_NextSibling = null;
public cA(int tag)
{
m_Tag = tag;
}
public void AddChild(cA a)
{
a.ptr_Parent = this;
if (ptr_FirstChild == null)
{
ptr_FirstChild = a;
ptr_LastChild = a;
}
else
{
ptr_LastChild.ptr_NextSibling = a;
ptr_LastChild = a;
}
}
public void Handle()
{
int a;
a=3;
cA tmp = ptr_FirstChild;
while (tmp!= null)
{
tmp.Handle();
tmp = tmp.ptr_NextSibling;
}
}
}
// *************
// DERIVED CLASS, overrides Handle
// *************
public class cB extends cA
{
public cB(int tag)
{
super(tag);
}
#Override
public void Handle()
{
int a;
a=4;
cA tmp = ptr_FirstChild;
while (tmp!= null)
{
tmp.Handle();
tmp = tmp.ptr_NextSibling;
}
}
}
// *************
// Usage of classes
// build a tree with both cAs and cBs, then call
// root.Handle, hoping to traverse the tree.
// *************
public cA ptr_Root; // define the 'root' of the tree
cA a1 = new cA(1); // instantiate all leaves
cA a2 = new cA(2);
cB b1 = new cB(1);
ptr_Root = b1; // build the tree
b1.AddChild(a1);
b1.AddChild(a2);
b1.Handle(); // call Handle on the root, intending to traverse the tree, but this halts the program

Android Service communcation

I'm writing an application which run a background Service which communicate with a remote server.
when the server sends me a new message, i need to update an object which is represent in the UI and then to update the UI View to represent the new state of the object (for example if the object's background propery is true - set the background of the View to green and if false set the background of the view to red).
I'm using a list view to show all an ArrayList of all those objects throw an ArrayAdapter.
I have an Application object (named app) for static reference and i have there a CurrentActivity property which store the current activity running (or null if the UI is closed).
i'm using this code to update the UI:
in my Service:
onNewMessage(boolean backgruond)
{
if (app.getCurrentActivity != null)
app.getCurrentActivity.onNewMessage(background);
}
in my Activity:
onNewMessage(boolean background)
{
object.setBackground(bacground);
Log.d("Background", String.valueof(background));
runOnUiThread(new Runnable() {
#Override
public void run()
{
arrayAdapter.notifyDataSetChanged();
}
});
}
and although the Log returns the right background state, the view isn't refreshing with the notifyDataSetChanged();
i've tried to send message to Activity throw BroadcastRecevier but it much more complicated because i have lots of messages coming from the server and i will have to register many receivers.
And besides - i don't understand why would the recevier work and this mechanism wont..
example of working method which updates the ListView:
ListViewActivity - inheritance from BaseActivity:
#Override
public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient)
{
super.onUnFriend(facebookUser, isYouRemovedClient);
updateView();
}
BaseActivity (the super class which extends Activity):
public void onUnFriend(FacebookUser facebookUser, boolean isYouRemovedClient)
{
facebookUser.setApplicationFriend(false);
app.getApplicationFriends().remove(facebookUser);
app.getDatabaseManager().deleteApplicationFriend(facebookUser.getId());
if (isYouRemovedClient)
app.showToast(facebookUser.getName() + " has removed from your friends", true);
else
app.showToast(facebookUser.getName() + " has removed you from friends", true);
}
this one works and does change the background color in the ListView.
not working example
ListViewActivity:
#Override
public void onFriendRequestAccepted(FacebookUser facebookUser, boolean showDialog) {
super.onFriendRequestAccepted(facebookUser, showDialog);
updateView();
}
BaseActivity:
public void onFriendRequestAccepted(FacebookUser facebookUser, boolean showDialog)
{
facebookUser.setApplicationFriend(true);
app.getApplicationFriends().add(facebookUser);
app.getDatabaseManager().addApplicationFriend(facebookUser);
if (showDialog)
app.showNewEventActivity(facebookUser, EventDialogManager.EVENT_FRIEND_ACCEPTED);
}
no update is made... i can't really understand why..
i have there a CurrentActivity property which store the current activity running (or null if the UI is closed)
I do not recommend this practice. It relies upon you consistently and reliably updating that Application data member, and it increases the coupling between your service and your UI.
and although the Log returns the right background state, the view isn't refreshing with the notifyDataSetChanged();
It would appear that you did not change the data in the adapter. Certainly, there is no evidence in the code that you have here that you updated the data in the adapter.
BTW, neither of the code snippets you have shown here are likely to compile (first is not valid Java, second has a typo).
i have lots of messages coming from the server and i will have to register many receivers
No, you will have to register one receiver, and in onReceive(), use an if statement (or perhaps a switch, if you prefer) to distinguish one message from another.
In addition to what CommonsWare said, I assume that object in the first line of your onNewMessage is the view. setBackround accepts an int parameter, not a boolean.
Use 0xFF00FF00 for green and 0xFFFF0000 for red.
By the way, it's a very bad practice to keep static references of Context objects and it's derived classes (Application and Activity both derive from Context, and keeping a static reference of them may lead to serious memory leaks. Read more here.)
Use a BroadcastReceiver instead. They are much more simple comparing to how you described them - you only need one.

Screen Rotation with Threading using Mono Android?

In CommonsWare eBook Android v3.6 pg 270, he discusses handling threads with rotation. He offers a solution where you create an inner static class to hold your state, call detach in the workflow and then attach again during screen rotation.
The problem is that each rotation will destroy the Activity and recreate it in Android, thus when you come back your thread may reference the destroyed activity giving you an exception for accessing an object set for collection.
I tried this in Mono Android and was unable to get it to work, I got an exception every single time. My question, hopefully Jonathan Pryer reads this is, how can I make this work in Mono Android? I have asked this twice on the forums with no results. So I am taking it to StackOverflow. I wanted to post the actualy code but I didn't want to violate CommonsWare licensing. So please take a look at the example in the book.
What was the exception? What's the adb logcat output?
The C# equivalent is the-same-but-different from the Java source. For example, here's the "rotation-aware" version of the default Mono for Android sample project:
[Activity (Label = "Scratch.PreserveCount", MainLauncher = true)]
public class Activity1 : Activity
{
CountInfo Info;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button> (Resource.Id.myButton);
button.Click += delegate {
SetButtonCount (button, Info.Count++);
};
Info = (CountInfo) LastNonConfigurationInstance;
if (Info == null) {
Info = new CountInfo {
Count = 1,
};
} else {
SetButtonCount (button, Info.Count);
}
}
void SetButtonCount (Button button, int count)
{
button.Text = string.Format ("{0} clicks!", Info.Count);
}
public override Java.Lang.Object OnRetainNonConfigurationInstance ()
{
return Info;
}
class CountInfo : Java.Lang.Object {
public int Count;
}
}
It's the same basic approach as the Java sample: the Activity.OnRetainNonConfigurationInstance() method is invoked by Android before the Activity is disposed, so we return our "state" from that method. The Activity.LastNonConfigurationInstance property will return null the first time it's invoked, otherwise it will return the last value returned from OnRetainNonConfigurationInstance(). The only missing piece of the puzzle is that the "state" object (CountInfo here) must inherit from Java.Lang.Object as we're passing the instance to Java.

Categories

Resources