I have the following test code (based on standard monodroid HelloWorld)
namespace TestGREF
{
[Activity (Label = "TestGREF", MainLauncher = true)]
public class Activity1 : Activity
{
int count = 1;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.Main);
Button button = FindViewById<Button> (Resource.Id.myButton);
button.Click += delegate {
button.Text = string.Format ("{0} clicks!", count++);
for(int i=0;i<10000;i++){
new Java.Lang.Object(new System.IntPtr(i));
//...some stuff here. Instead of Java.Lang.Object may be
//something much more useful.
}
//If uncomment here, looks ok
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
};
}
}
}
If I click the button 5-6 times, application crashes.
I know this happens because of global refences (GREF) limit (described here, "Unexpected NullReferenceExceptions" section). The question is: what to do with it? What is the best practice? If possible, with code example please
If uncomment GC.Collect() call, all seems working, but calling GC too often is too exspensive for performance. Another popular design is to put new statement put of loop, but it is not always possible cause of program logic.
Any more ideas?
You need to release all unmanaged objects when they no longer needed. All classes that inherits from Android.Runtime.IJavaObject also inherits IDisposable so you need to dispose them.
Here is part from my project
private Spinner _spType;
private ArrayAdapter _arrayAdapter;
protected override void OnCreate(Android.OS.Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_spType = FindViewById<Spinner>(Resource.Id.spinnerType);
_arrayAdapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleSpinnerItem, new[] {"1","2","3","4","5"});
_spType.Adapter = _arrayAdapter;
}
public override void Finish()
{
if (_spType != null)
_spType.Dispose();
if (_arrayAdapter != null)
_arrayAdapter.Dispose();
base.Finish();
}
for(int i=0;i<10000;i++){
var obj = new Java.Lang.Object(new System.IntPtr(i));
//...some stuff here. Instead of Java.Lang.Object may be
//something much more useful.
obj.Dispose(); //Deletes an object and GREF too.
//Cannot be used if object is still used in dalvik VM
}
If you cannot use Dispose() (for example, unmanaged object is a part of layout, which will be used by android lated, but not by C# code), use GC.Collect() wisely. GC.Collect() kills all the GREFs to variables, which are out of usage by Mono Environment and out of current scope.
Here is article about GC and memory management in monodroid. It can be helpful for you
http://docs.xamarin.com/android/advanced_topics/garbage_collection
Related
MainView include InformationCOmponent:
#Push
#Route
public class MainView extends VerticalLayout {
InformationComponent infoComponent;
public MainView(#Autowired StudentRepository studentRepo, #Autowired Job jobImportCsv, #Autowired JobLauncher jobLauncher, #Value("${file.local-tmp-file}") String inputFile) {
[...] // some stuffs
infoComponent = new InformationComponent(studentRepo);
add(infoComponent);
}
//update when job process is over
private void uploadFileSuccceed() {
infoComponent.update(myUploadComponent.getFile());
}
InformationComponent:
public class InformationComponent extends HorizontalLayout {
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
When I call InformationComponent from MainView the Label is not update in the browser.
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines))
also try wwith #Push(PushMode.MANUAL) and ui.push(); but doesn't work either...
Complete source code is here: https://github.com/Tyvain/ProcessUploadedFile-Vaadin_SpringBatch/tree/push-not-working
I suspect the problem here is that uploadFileSuccceed() is run from a background thread, in which case UI.getCurrent() will return null. This would cause a NullPointerException that either kills the background thread or alternatively the exception is caught and silently ignored by the caller. Another alternative is that uploadFileSuccceed() happens through a different browser window and thus also a different UI instance, which means that the changes would be pushed in the context of the wrong UI.
For exactly these reasons, UI.getCurrent().access(...) is generally an anti pattern, even though it's unfortunately quite widely used in old examples.
You can check whether this is the cause of your problem by logging the value of UI.getCurrent() in the beginning of the update method, and comparing that to the value of UI.getCurrent() e.g. in the constructor of InformationComponent.
To properly fix the problem, you should pass the correct UI instance through the entire chain of events originating from whatever triggers the background processing to start. You should also note that it might be tempting to use the getUI() method that is available in any Component subclass, but that method is not thread safe and should thus be avoided in background threads.
As a final notice, I would recommend using the Span or Text component instead of Label in cases like this. In Vaadin 10, the Label component has been changed to use the <label> HTML element, which means that it's mainly intended to be used as the label of an input component.
Based on information provided by Leif you should do something like the following example.
At runtime, when this HorizontalLayout subclass object is attached to a parent UI object, its onAttach method is called. At that point we can remember the UI by storing its reference is a member variable named ui. Actually, an Optional<UI> is returned rather than a UI object, so we need to test for null, though it should never be null at point of onAttach.
public class InformationComponent extends HorizontalLayout {
UI ui;
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
this.ui.access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
} catch (UIDetachedException e) {
// Do here what is needed to do if UI is no longer attached, user has closed the browser
}
#Override // Called when this component (this `HorizontalLayout`) is attached to a `UI` object.
public void onAttach() {
ui = this.getUI().orElseThrow( () -> new IllegalStateException("No UI found, which should be impossible at point of `onAttach` being called.") );
}
In my team we're doing cross platform UI testing using Appium and the Appium Java-Client.
The current structure of our project is something like:
mobile
pages
SignInPage
steps
SignInSteps
The steps are "glued" together using Cucuember.
SignInPage looks something like this:
public class SignInPage {
public SignInPage(AppiumDriver driver) {
PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);
}
// region Identifiers
final String IOS_USERNAME_FIELD = "SignInUsernameField";
final String ANDROID_USERNAME_FIELD = "new UiSelector().resourceIdMatches(\".*id/username.*\")";
final String IOS_PASSWORD_FIELD = "SignInPasswordField";
final String ANDROID_PASSWORD_FIELD = "new UiSelector().resourceIdMatches(\".*id/password_editText.*\")";
final String IOS_SIGN_IN_BUTTON = "SignInButton";
final String ANDROID_SIGN_IN_BUTTON = "new UiSelector().resourceIdMatches(\".*id/signInButton.*\")";
// endregion
#iOSFindBy(accessibility = IOS_USERNAME_FIELD)
#AndroidFindBy(uiAutomator = ANDROID_USERNAME_FIELD)
private MobileElement usernameField;
#iOSFindBy(accessibility = IOS_PASSWORD_FIELD)
#AndroidFindBy(uiAutomator = ANDROID_PASSWORD_FIELD)
private MobileElement passwordField;
#iOSFindBy(accessibility = IOS_SIGN_IN_BUTTON)
#AndroidFindBy(uiAutomator = ANDROID_SIGN_IN_BUTTON)
private MobileElement signInButton;
public MobileElement getUsernameField() {
return usernameField;
}
public MobileElement getPasswordField() {
return passwordField;
}
public MobileElement getSignInButton() {
return signInButton;
}
public void tapUsernameField() {
getUsernameField().click();
}
public void tapSignInButton() {
getSignInButton().click();
}
public void clearUsernameEditText() {
getUsernameField().clear();
}
}
We're not sure in terms of performance and elements lookup where is it best to create an instance of the SignInPage. Currently we have a #Before method in our SignInSteps that is executed before each Gherkin scenario starts (which is not ideal) but it helps us having a SignInPage property in the SignInSteps class that is reused by all the steps.
public class SignInSteps {
private SignInPage signInPage;
AppiumDriver driver;
#Before()
public void setUp() throws MalformedURLException {
driver = TestBase.getInstance().getDriver();
signInPage = new SignInPage(driver);
}
#Given("I fill in the username and password")
public void fill_username_and_password() throws Throwable {
signInPage.tapUsernameField();
signInPage.clearUsernameEditText();
fillEditText(signInPage.getUsernameField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_USERNAME));
fillEditText(signInPage.getPasswordField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_PASSWORD));
}
// Other sign in steps below
}
However I feel that a cleaner approach would be to create the SignInPage as a local variable inside each step method in SignInSteps. Is there any performance impact in creating the page(s) you need in each step?
Also, it's not clear to me, with our current approach (the #Before approach) why exactly does it work even when you create a page for some steps that will be executed later on (so the screen is not even visible at this point).
So maybe the larger question would be how are the elements looked up? Is it when calling PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); or when actually accessing the annotated properties (which would be some kind of lazy initialization approach that from my knowledge Java doesn't have, unless my understanding of Java annotations is wrong).
Sorry for the long post, but these are some things that I want to understand thoroughly. So any help is highly appreciated.
Thank you!
I did some more research (debugging) and I've found the answer:
When you call PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); the annotated properties from the page are set (decorated) via reflection (see AppiumFieldDecorator) with a proxy (ElementInterceptor) that wraps a MobileElement. Each time you call a method on the annotated property you actually call the proxy that looks up the element and forwards the method call. There is no cache in between (as opposed to WidgetInterceptor which I didn't figured out yet where it is used).
So in my case, creating the page once, or in each step doesn't really make a difference because the element lookup is performed each time you interact with it (which I guess it's good, but it might have a performance impact also).
I've also attached a few screenshots below:
Stacktrace when you call PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);
Stacktrace when you call click on an element
Hope this helps others as well understand how the tool works.
I have a task that runs in a different thread and requires the session. I've done:
public GenerateDocList(LLStatistics.DocLists.DocList docs)
{
this.docs = docs;
context = HttpContext.Current;
}
and
public void StartTask()
{
//this code runs in a separate thread
HttpContext.Current = context;
/* rest of the code */
}
Now the thread has knowledge of the session and it works for a while but at some point in my loop HttpContext.Current.Session becomes null. Any ideas what can I do about this?
public static LLDAC.DAL.DBCTX LLDB
{
get
{
LLDAC.DAL.DBCTX currentUserDBContext = HttpContext.Current.Session["LLDBContext"] as LLDAC.DAL.DBCTX;
if (currentUserDBContext == null)
{
currentUserDBContext = new LLDAC.DAL.DBCTX();
HttpContext.Current.Session.Add("LLDBContext", currentUserDBContext);//this works only for a few loop iterations
}
return currentUserDBContext;
}
}
In general, this is a very fragile pattern for a multi-threaded operation. Long-running tasks (which I assume this is) are best suited to instance methods in a class rather than static methods such that the class can maintain any dependent objects. Also, since the session state is not thread safe and can span multiple requests you are getting into some very risky business by cashing your DB context in the session at all.
If you are convinced this is best done with static methods and stored in the session, you may be able to do something like this:
public static HttpSessionState MySession { get; set; }
public GenerateDocList(LLStatistics.DocLists.DocList docs)
{
this.docs = docs;
MySession = HttpContext.Current.Session;
}
Then:
public static LLDAC.DAL.DBCTX LLDB
{
get
{
LLDAC.DAL.DBCTX currentUserDBContext = MySession["LLDBContext"] as LLDAC.DAL.DBCTX;
if (currentUserDBContext == null)
{
currentUserDBContext = new LLDAC.DAL.DBCTX();
if (MySession == null)
{
thow new InvalidOperaionException("MySession is null");
}
MySession.Add("LLDBContext", currentUserDBContext);
}
return currentUserDBContext;
}
}
Note that you could still run into issues with the session since other threads could still modify the session.
A better solution would probably look something like this:
public class DocListGenerator : IDisposable
{
public LLDAC.DAL.DBCTX LLDB { get; private set; }
public DocListGenerator()
{
LLDB = new LLDAC.DAL.DBCTX();
}
public void GenerateList()
{
// Put loop here.
}
public void Dispose()
{
if (LLDB != null)
{
LLDB.Dispose();
}
}
}
Then your calling code looks like this:
public void StartTask()
{
using (DocListGenerator generator = new DocListGenerator()
{
generator.GenerateList();
}
}
If you really want to cache something, you could cache your instance like this:
HttpContext.Current.Sesssion.Add("ListGenerator", generator);
However, I still don't think that is a particularly good idea since your context could still be disposed or otherwise altered by a different thread.
Using anything related to the HttpContext.Current on anything besides the main Request thread is generally going to get you into trouble in ASP.net.
The HttpContext is actually backed on a thread belonging to a Thread Pool and the thread may very well get reused on another request.
This is actually a common issue with using the new Async/Await keywords in ASP.net as well.
In order to help you, it would help to know why you're attempting this in the first place?
Is this a single server or a web farm with multiple load balanced servers?
Are you hosting it yourself, or is it the site hosted by a provider?
What is the SessionState implementation (SQL Server, State Server, In-Process, or something custom like MemCached, Redis, etc...)
What version of ASP .net?
Why are you starting a new thread instead of just doing the processing on the request thread?
If you really can't (or shouldn't) use session. Then you could use something like a correlation ID.
Guid correlationID = Guid.NewGuid();
HttpContext.Current.Session["DocListID"] = correlationID;
DocList.GoOffAndGenerateSomeStuffOnANewThread(correlationID);
... when process is done, store the results somewhere using the specified ID
// Serialize the result to SQL server, the file system, cache...
DocList.StoreResultsSomewhereUnderID();
... later on
DocList.CheckForResultsUnderID(HttpContext.Current.Session["DocListID"]);
Our company has the need to log certain things each time one of our action methods of our ASP.NET WebApi controllers gets called. Since we use Ninject for the DI right now, we'd like to use it also for this purpose. This is what I have tried so far.
I have Ninject, Ninject.Extensions.Interception and Ninject.Extensions.Interception.DynamicProxy installed through NuGet and I have the following module
public class InterceptAllModule : InterceptionModule
{
public override void Load()
{
Kernel.Intercept(p => p.Request.Service.Name.EndsWith("Controller")).With(new TimingInterceptor());
}
}
Where TimingInterceptor is
public class TimingInterceptor : SimpleInterceptor
{
readonly Stopwatch _stopwatch = new Stopwatch();
protected override void BeforeInvoke(IInvocation invocation)
{
_stopwatch.Start();
}
protected override void AfterInvoke(IInvocation invocation)
{
_stopwatch.Stop();
string message = string.Format("[Execution of {0} took {1}.]",invocation.Request.Method,_stopwatch.Elapsed);
Log.Info(message + "\n");
_stopwatch.Reset();
}
}
Now, when I try to hook the module up with ninject kernel, and run my site
var kernel = new StandardKernel(new InterceptAllModule());
However, whenever there is a call coming in to one of the action method, it throws an error saying
Cannot instantiate proxy of class: MyApiController.
Could someone with experience point out what I'm doing wrong please? Thanks.
Update
So using your Code and Remo's excellent point about needing the action methods to be virtual and putting in an empty default constructor (just to placate dynamic proxy, keep your other constructor still) I have got both the action filter and the interception approach working.
I would say that as it stands your code will intercept potentially unwanted methods on the ApiController so you will probably also need to put some code in place to filter these out e.g. ExecuteAsync and Dispose.
My only other point is performance. Huge disclaimer these are just very basic tests (using the action filter approach each time to log the stats), I invite you to do your own(!)... but using the DynamicProxy interceptor I was getting a time of around 4 milliseconds per get request
[Execution of Get took 00:00:00.0046615.]
[Execution of Get took 00:00:00.0041988.]
[Execution of Get took 00:00:00.0039383.]
Commenting out the Interception code and using an Action filter I was getting sub millisecond performance:
[Execution of Get took 00:00:00.0001146.]
[Execution of Get took 00:00:00.0001116.]
[Execution of Get took 00:00:00.0001364.]
It is up to you whether this is actually an issue or concern but I thought I would point this out.
Previous Response
Have you rulled out using ActionFilters? This is the natural extension point for AOP on an MVC action.
If you were interested in methods other than the actual action on the controller then I would understand but I thought I would post a suggestion anyway.
Inspired by Are ActionFilterAttributes reused across threads? How does that work? and Measure Time Invoking ASP.NET MVC Controller Actions.
Updated to show the exclusion of the timer when method tagged. Inspiration from core WebApi framework specifically AllowAnonymousAttribute and AuthorizeAttribute
Register this globally so that all actions are monitored by this:
GlobalConfiguration.Configuration.Filters.Add(new TimingActionFilter());
Then:
public class TimingActionFilter : ActionFilterAttribute
{
private const string Key = "__action_duration__";
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (SkipLogging(actionContext))
{
return;
}
var stopWatch = new Stopwatch();
actionContext.Request.Properties[Key] = stopWatch;
stopWatch.Start();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (!actionExecutedContext.Request.Properties.ContainsKey(Key))
{
return;
}
var stopWatch = actionExecutedContext.Request.Properties[Key] as Stopwatch;
if(stopWatch != null)
{
stopWatch.Stop();
var actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
Debug.Print(string.Format("[Execution of {0} took {1}.]", actionName, stopWatch.Elapsed));
}
}
private static bool SkipLogging(HttpActionContext actionContext)
{
return actionContext.ActionDescriptor.GetCustomAttributes<NoLogAttribute>().Any() ||
actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<NoLogAttribute>().Any();
}
}
And
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class NoLogAttribute : Attribute
{
}
Now you can exclude the global filter using:
public class ExampleController : ApiController
{
// GET api/example
[NoLog]
public Example Get()
{
//
}
}
For anyone still lurking, the reason I wanted to use Ninject was so I could inject a logger (or anything else) into the interceptor, but I wanted to intercept all actions.
Mark's answer is perfect, but instead of registering globally using
GlobalConfiguration.Configuration.Filters.Add(new TimingActionFilter());
bind your filter with Ninject using
Kernal.BindHttpFilter<TimingActionFilter>(FilterScope.Action).
You'll need to create an appropriate contructor in the TimingActionFilter class.
I've read several related posts and even posted and answer here but it seems like I was not able to solve the problem.
I have 3 Activities:
Act1 (main)
Act2
Act3
When going back and forth Act1->Act2 and Act2->Act1 I get no issues
When going Act2->Act3 I get no issues
When going Act3->Act2 I get occasional crashes with the following error: java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor#.... This is a ListView cursor.
What I tried:
1. Adding stopManagingCursor(currentCursor);to the onPause() of Act2 so I stop managing the cursor when leaving Act2 to Act3
protected void onPause()
{
Log.i(getClass().getName() + ".onPause", "Hi!");
super.onPause();
saveState();
//Make sure you get rid of the cursor when leaving to another Activity
//Prevents: ...Unable to resume activity... trying to requery an already closed cursor
Cursor currentCursor = ((SimpleCursorAdapter)getListAdapter()).getCursor();
stopManagingCursor(currentCursor);
}
When returning back from Act3 to Act2 I do the following:
private void populateCompetitorsListView()
{
ListAdapter currentListAdapter = getListAdapter();
Cursor currentCursor = null;
Cursor tournamentStocksCursor = null;
if(currentListAdapter != null)
{
currentCursor = ((SimpleCursorAdapter)currentListAdapter).getCursor();
if(currentCursor != null)
{
//might be redundant, not sure
stopManagingCursor(currentCursor);
// Get all of the stocks from the database and create the item list
tournamentStocksCursor = mDbHelper.retrieveTrounamentStocks(mTournamentRowId);
((SimpleCursorAdapter)currentListAdapter).changeCursor(tournamentStocksCursor);
}
else
{
tournamentStocksCursor = mDbHelper.retrieveTrounamentStocks(mTournamentRowId);
}
}
else
{
tournamentStocksCursor = mDbHelper.retrieveTrounamentStocks(mTournamentRowId);
}
startManagingCursor(tournamentStocksCursor);
//Create an array to specify the fields we want to display in the list (only name)
String[] from = new String[] {StournamentConstants.TblStocks.COLUMN_NAME, StournamentConstants.TblTournamentsStocks.COLUMN_SCORE};
// and an array of the fields we want to bind those fields to (in this case just name)
int[] to = new int[]{R.id.competitor_name, R.id.competitor_score};
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter tournamentStocks = new SimpleCursorAdapter(this, R.layout.competitor_row, tournamentStocksCursor, from, to);
//tournamentStocks.convertToString(tournamentStocksCursor);
setListAdapter(tournamentStocks);
}
So I make sure I invalidate the cursor and use a different one. I found out that when I go Act3->Act2 the system will sometimes use the same cursor for the List View and sometimes it will have a different one.
This is hard to debug and I was never able to catch a crashing system while debugging. I suspect this has to do with the time it takes to debug (long) and the time it takes to run the app (much shorter, no pause due to breakpoints).
In Act2 I use the following Intent and expect no result:
protected void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
Intent intent = new Intent(this, ActivityCompetitorDetails.class);
intent.putExtra(StournamentConstants.App.competitorId, id);
intent.putExtra(StournamentConstants.App.tournamentId, mTournamentRowId);
startActivity(intent);
}
Moving Act1->Act2 Act2->Act1 never gives me trouble. There I use startActivityForResult(intent, ACTIVITY_EDIT); and I am not sure - could this be the source of my trouble?
I would be grateful if anyone could shed some light on this subject. I am interested in learning some more about this subject.
Thanks,D.
I call this a 2 dimensional problem: two things were responsible for this crash:
1. I used startManagingCursor(mItemCursor); where I shouldn't have.
2. I forgot to initCursorAdapter() (for autocomplete) on onResume()
//#SuppressWarnings("deprecation")
private void initCursorAdapter()
{
mItemCursor = mDbHelper.getCompetitorsCursor("");
startManagingCursor(mItemCursor); //<= this is bad!
mCursorAdapter = new CompetitorAdapter(getApplicationContext(), mItemCursor);
initItemFilter();
}
Now it seems to work fine. I hope so...
Put this it may work for you:
#Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
orderCursor.requery();
}
This also works
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
startManagingCursor(Cursor);
}