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

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

Related

FMX: destruction of visible controls in tab at runtime

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.

Android WebView causing RuntimeException at WebViewDelegate.getPackageId

I have a WebView in the layout xml of my MainActivity, to which I setWebViewClient(new WebViewClient()), followed by loadUrl(...) in onCreate.
Most of the time the app runs fine and the Web content is displayed correctly.
But in some cases, opening the app causes a crash. I've noticed that it happens when the app scheduled a PendingIntent broadcast with AlarmManager, which triggers a Notification whose contentIntent is a PendingIntent.getActivity set to launch MainActivity.
But it happens only in the case when the user has removed the app from the stack of active apps in the meantime (Notification is visible, not yet clicked, and stack if apps cleared. So, app process probably stopped?).
Seemingly no other system modifications in between (in particular no app/system update, no playing around with user profiles or Chrome app.)
Stack trace:
java.lang.RuntimeException:
at android.webkit.WebViewDelegate.getPackageId (WebViewDelegate.java:164)
at yj.a (PG:16)
at xH.run (PG:14)
at java.lang.Thread.run (Thread.java:764)
Occurs with Android 7.0 thru 9. Also, seems to have started to occur when I upgraded target SDK to 28.
I don't use explicitly a WebViewDelegate. It must be internal system code (hence the obfuscation).
By reading the source code of AOSP, it seems that the WebView fails to retrieve the package to which it belongs -- but why sometimes only!?
Any help appreciated! Thanks.
It has taken weeks of investigation on and off, but I've finally found why I'm seeing this issue. For me, it was just because I'd overridden the getResources() method in my application scope to use the current activity. Something like this:
public class MyApplication extends MultiDexApplication {
private static MyApplication sInstance = null;
private WeakReference<Activity> mCurrentActivity;
public static MyApplication getInstance() {
return sInstance;
}
public void setCurrentActivity(Activity activity) {
mCurrentActivity = new WeakReference<>(activity);
}
public Activity getCurrentActivity() {
return mCurrentActivity == null ? null : mCurrentActivity.get();
}
#Override
public Resources getResources() {
// This is a very BAD thing to do
Activity activity = getCurrentActivity();
if (activity != null) {
return activity.getResources();
}
return super.getResources();
}
}
This was done as a shortcut as I often wanted to get strings that were activity-specific, so I was calling MyApplication.getInstance().getResources().getString(). I now know this was a bad thing to do - removing my override of this method instantly fixed it.
So the key takeaway from this for me is that when the WebView is initialising, it MUST be able to get hold of the application context, so that the resources passed into WebViewDelegate.getPackageId() are at the application level - the activity context isn't enough, and causes this error.
As a side note - I wasn't even trying to add a WebView to my application. I was only actually using the following:
String userAgent = WebSettings.getDefaultUserAgent(this);
I was then passing this value into a custom media player that I'm using. Passing "this" as either application or activity scope always failed, due to my override.
Looking through documentation,you can see that error is thrown when package can't be found.Check your syntax ,package name and try again.
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/webkit/WebViewDelegate.java (Line 164)
/**
* Returns the package id of the given {#code packageName}.
*/
public int getPackageId(Resources resources, String packageName) {
SparseArray<String> packageIdentifiers =
resources.getAssets().getAssignedPackageIdentifiers();
for (int i = 0; i < packageIdentifiers.size(); i++) {
final String name = packageIdentifiers.valueAt(i);
if (packageName.equals(name)) {
return packageIdentifiers.keyAt(i);
}
}
throw new RuntimeException("Package not found: " + packageName);
}

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.

Correct way to use IdlingResource in Espresso Android

I'm writing UI tests with Espresso. App cooperates tightly with server, so in many cases, I need to wait for either value to be calculated, or data is got and displayed, etc. Espresso suggests using IdlingResource for this.
My IdlingResource classes look like this (simple and clear example).
public class IRViewVisible implements IdlingResource {
private View view;
private ResourceCallback callback;
public IRViewVisible(View view) {
this.view = view;
}
#Override
public String getName() {
return IRViewVisible.class.getName();
}
#Override
public boolean isIdleNow() {
if(view.getVisibility() == View.VISIBLE && callback != null) {
callback.onTransitionToIdle();
return true;
}
return false;
}
#Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.callback = resourceCallback;
}
}
Please correct me if I'm wrong anywhere (as sometimes it seems to me that my IdlingResources do not work properly).
I register the idling resource in setUp() like this:
IRViewVisible ir = new IRViewVisible(View v);
Espresso.registerIdlingResources(ir).
Unregister it on tearDown().
I found this article (there is a section called "Register a component tied to an Activity instance") — I do not use his schema, but I checked hashcode of view that was set to IdlingResource after registering (in each method), and it's not the same view — all hashes are different.
Another question: One Test class (it's results) can't have any effect on another Test class, can it?
I'm guessing your problem stems from getName() returning the same name for all instances of IRViewVisible. This means you can only have one registered instance of it at a time - any subsequent registrations will fail (silently!).
You mention that you clear the IdlingResources at the end of each test, but if you are register multiple instances of it at once, you need to make sure each instance has a unique name. it's not clear from your question if you're registering multiple instances of IRViewVisible in a single test.
As to your final question: Yes, it is possible. Android doesn't completely shut down the Application between test runs - just the Activities. Common things which can cause problems:
Failing to clear persistent state (saved data).
Failing to clear global state - e.g. static variables/singletons
Not waiting for background threads to finish running.
As an aside, it's worth noting that you only call onTransitionToIdle() inside isIdleNow(). This works (thanks #Be_Negative for the heads up!) but it could slow down your tests a lot, since Espresso will only poll isIdleNow() every few seconds. If you call onTransitionToIdle() as soon as the view becomes visible, it should speed things up considerably.
I needed something similar to your IRViewVisible myself, here's my effort.
So the isIdleNow() method will never return true if you don't set a callback to the idlingResource?
I reckon it's better to refactor it like this:
#Override
public boolean isIdleNow() {
boolean idle = view.getVisibility() == View.VISIBLE;
if(idle && callback != null) {
callback.onTransitionToIdle();
}
return idle;
}
Well, first of all you shouldn't need to use Espresso IdlingResource to test server calls. If you use AsyncTasks in your server calls, Espresso will be able to know when to be idle and when not. If this is not enough: try to refactor your code in this way:
IRViewVisible idlingResource = new IRViewVisible(yourView);
IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
// Now we wait
Espresso.registerIdlingResources(idlingResource);
// Stop and verify
// Clean up
Espresso.unregisterIdlingResources(idlingResource);
Hope to be helpful.

A question on activity lifecycle and resource deletion/allocation

I've been puzzled very much by this lifecycle thing, so I did a little experiement. Long story short: The result shows that when a process is created after having been destroyed, UI objects allocated in the last session were all gone and need be re-created (which is expected). But other memory space allocated in the last session are still available for this session.
The surprise to me is: system's UI objects (like ListView) and memory space allocated by me are not destroyed at the same time. Why they don't die (or stay alive) at the same time???
See the experiement here:
public class PracticeActivity extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If there is left-over value in G.count[99], then do not populate
// the ListView.
if (G.count[99] == 0) {
ListView lv = getListView();
lv.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, m_Starbucks));
}
Log.d("TAG", MessageFormat.format("Created, count = {0,number}", G.count[99]));
Log.d("TAG", MessageFormat.format("Starbucks = {0}", m_Starbucks[0]));
G.count[99]++; // increment the count
m_Starbucks[0] = "Coffee Frappuccino"; // and change the menu
}
#Override public void onRestart() { super.onRestart(); Log.d("TAG", "Restarted"); }
#Override public void onStart() { super.onStart(); Log.d("TAG", "Started"); }
#Override public void onResume() { super.onResume(); Log.d("TAG", "Resumed"); }
#Override public void onPause() { super.onPause(); Log.d("TAG", "Paused"); }
#Override public void onStop() { super.onStop(); Log.d("TAG", "Stopped"); }
#Override public void onDestroy() {
super.onDestroy();
if (isFinishing())
Log.d("TAG", "Destroyed -- someone finished me");
else
Log.d("TAG", "Destroyed -- system needs resources");
}
private static final String[] m_Starbucks = {
"Latte", "Cappuccino", "Caramel Macchiato", "Americano", "Mocha",
"White Mocha", "Mocha Valencia", "Cinnamon Spice Mocha",
"Toffee Nut Latte", "Espresso", "Espresso Macchiato",
"Espresso Con Panna"
};
}
Here is the class G, defined in G.java file:
public class G {
public static int[] count = new int[100];
}
Running this test produced the following results:
Created, count = 0
Starbucks = Latte
Started
Resumed
Paused
Stopped
Destroyed -- someone finished me
Created, count = 1
Starbucks = Coffee Frappuccino
Started
Resumed
In the first session, count[99]'s value was 0, so the program went to populate the ListView, so everything was fine.
In the 2nd session, count[99] still holds the value left over from the first session, so the program did not populate the ListView, in hope that the ListView would also be available too. But it's not, the result is a black screen. This means G.count[] was retained (and so is m_Starbucks[]) from last session, but the ListView didn't survive.
It's apparent that there's only one instance of PracticeActivity in the system, when this instance dies, both PracticeActivity and G classes should die too. But they didn't, they still retain values from the last session.
QUESTIONS:
If count[] and m_Starbucks[] are
still available, then this means
PracticeActivity and G are both
alive too. Then why the ListView is
gone? Shouldn't all of them die or
live at the same time?
When I see some of my classes'
members hold their old values from
last session, can I trust that
all of my classes' members are also valid??? I.e., does Android
kill my resources in an all-or-none
fashion? Or, it can delete some and
leave some others? (This question
shouldn't have existed in the first
place, but seeing the result of the
experiement, one starts to wonder.)
Can anybody shed some light on this? Much appreciated.
Static class members live as long as JVM (DVM) lives - which may be (and certainly is) longer than
your activity lifecycle. Your activity could be destroyed, but static fields survive it.
If count[] and m_Starbucks[] are still
available, then this means
PracticeActivity and G are both alive
too.
No. count and m_Starbucks are both declared static. Per Java documentation:
"Class Variables (Static Fields) A
class variable is any field declared
with the static modifier; this tells
the compiler that there is exactly one
copy of this variable in existence,
regardless of how many times the class
has been instantiated"
So say you do the following: (pretend this isn't an activity and you can conveniently just construct it)...
PracticeActivity example1 = new PracticeActivity();
PracticeActivity example2 = new PracticeActivity();
Then you do not have example1.m_Starbucks[0] and example2.m_Starbucks[0] as distinct variables. Instead, you just have PracticeActivity.m_Starbucks[0] and any specific instance of that class has the same variable. Therefore it is unaffected by (unrelated to!) the destruction of the actual instance of your Activity. And in fact, they exist, even if you have never constructed an instance of the class that contains them.
Also, if you change example1.m_Starbucks[0], you will find that example2.m_Starbucks[0] also has changed -- because, again, there's only one array.
The simple answer here is that you shouldn't be using static variables for this type of storage. It's safe to use static for constants and some other special cases, but never as member variables that you expect to hold attributes of a given instance of a class, that make that instance uniquely different from other classes.

Categories

Resources