将MvxBindableSpinner放在MvxBindableListView中时,为什么gref会过高? [英] Why does the gref go too high when I put a MvxBindableSpinner in a MvxBindableListView?
问题描述
我正在使用mvvmcross开发适用于Android的应用程序.
在此应用程序中,我想要一个包含微调框的列表.当我在模拟器上测试应用程序时,它看起来还可以,但是当我滚动时,它很快就会耗尽内存,因为gref超过2000.我知道gref在真实设备上可以更高,但是我仍然认为我一定做错了
BindableList
<cirrious.mvvmcross.binding.android.views.MvxBindableListView
android:id="@+id/propertyHolder"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/obsBtLayout"
android:layout_above="@id/photoframe"
local:MvxBind="
{
'ItemsSource':{'Path':'PPHolders'},
'ItemClick':{'Path':'PropertyClickedCommand'}
}"
local:MvxItemTemplate="@layout/listitem_property"
/>
ListItem_Property.axml(已剥离)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res/AIPApp.UI.Droid"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/ListItemSelector"
android:descendantFocusability="beforeDescendants"
>
<cirrious.mvvmcross.binding.android.views.MvxBindableSpinner
android:layout_gravity="center_horizontal"
android:layout_width="200dip"
android:layout_height="wrap_content"
local:MvxDropDownItemTemplate="@layout/spinneritem_propdropdown"
local:MvxItemTemplate="@layout/spinneritem_prop"
local:MvxBind="
{
'ItemsSource':{'Path':'CodeTableValues'},
'SelectedItem':{'Path':'ObservedCodeTable'},
'Visibility':{'Path':'IsCodeTableValue','Converter':'Visibility'}
}"/>
</LinearLayout>
这是因为每次滚动时都必须重新构建微调器项吗?因为绑定到的列表在列表中的每个项目中都不同.因此,在一个列表项上,微调框列表的长度可以为6个项目,在另一个列表项上则可以为3个项目,以此类推.
我还没有对您所看到的行为进行完整的分析-如果没有完整的代码示例,这很难做到.>
但是,尤其要感谢JonPryor在 Xamarin论坛我相信我现在至少对一般情况下的GREF发生了更好的了解-因此我可以回答您的为什么"问题.
绑定列表的一般情况是GREF递增:
- 每组绑定一次-因为绑定存储在混合C#/Java容器对象中-
这不是一个简单的问题,但我认为我们可以通过几种方法来解决该问题.
首先,我们可以与Xamarin讨论这个问题-可能应该增加可用的GREF的数量-由于这些对象将存储在Java中,因此对于在C#中引用它们来说可能没有任何危害,因为好吗?
第二,我们可以看看改变UI绑定的实现方式,以便不将永久引用存储到所有对象中-例如,如果我们一次知道一个绑定(例如,对于标签),那么我们可以看看不为此功能使用XML数据绑定的路由.例如,我们可以使用新的View来手动执行此绑定.
第三,我们可以考虑更改绑定代码本身,以便对于单向绑定(从ViewModel到View),它在更新时使用
FindViewById<TView>
检索Android视图,而不是使用对视图的保留引用.这样会比较慢,但是会减少所需的GREF数量.在明确声明一次性"绑定的情况下,此功能可能是最可实现的.第四,作为应用程序开发人员,这可能是您最容易使用的解决方案,您可以查看更改UI的实现,以使应用程序不使用这些绑定的子列表-例如而是可以使用标签-仅按需创建微调框(通过处理代码中的Click事件).
我敢肯定,除了此以外,还有其他选择...
我在分析过程中问自己一个问题是该问题是MvvmCross特有的,还是在所有MonoDroid应用程序中都可以看到的问题.
我不确定100%,但是我认为答案是,这是一个普遍问题,会影响所有MonoDroid应用程序.但是,我也认为MvvmCross为问题增加了一些:
- 通过保留对诸如TextViews/labels之类的东西的引用
- 使您更容易编写引用许多Java对象的代码.
我也不认为这完全是MvvmCross或MonoDroid问题.尽管由于MonoDroid的实现而突出显示了此GREF限制,但此处的根本问题实际上是一次尝试做太多事情之一-因此,实际上,您可以通过简化设计/实现来提高应用程序的性能,从而减少使用量意见.尽管可能感觉并不好,但我认为MonoDroid在帮我们一个忙-指出我们的UI实现有点胖",我们应该考虑在应用程序代码中对其进行优化.
随着我发现更多信息,我将更新此答案,但我希望以上信息已经使您对这种情况的原因"有了很好的了解.
I'm developing an app for Android using mvvmcross.
In this application I want to have a list which contains a spinner. It looks ok when I test the app on the emulator, but when I scroll it goes out of memory quickly because the gref goes above 2000. I know the gref can go higher on a real device but I still think I must be doing something wrong.
BindableList
<cirrious.mvvmcross.binding.android.views.MvxBindableListView android:id="@+id/propertyHolder" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_below="@id/obsBtLayout" android:layout_above="@id/photoframe" local:MvxBind=" { 'ItemsSource':{'Path':'PPHolders'}, 'ItemClick':{'Path':'PropertyClickedCommand'} }" local:MvxItemTemplate="@layout/listitem_property" />
ListItem_Property.axml (stripped)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res/AIPApp.UI.Droid" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/ListItemSelector" android:descendantFocusability="beforeDescendants" > <cirrious.mvvmcross.binding.android.views.MvxBindableSpinner android:layout_gravity="center_horizontal" android:layout_width="200dip" android:layout_height="wrap_content" local:MvxDropDownItemTemplate="@layout/spinneritem_propdropdown" local:MvxItemTemplate="@layout/spinneritem_prop" local:MvxBind=" { 'ItemsSource':{'Path':'CodeTableValues'}, 'SelectedItem':{'Path':'ObservedCodeTable'}, 'Visibility':{'Path':'IsCodeTableValue','Converter':'Visibility'} }"/> </LinearLayout>
Is this happening because the spinner items have to be rebuild every time I scroll? Because the list it's bound to is different in every item on the list. So on one listitem the spinner list can be six items long on another it can be 3 items long and so on.
解决方案I've not yet got to a full analysis of the behavior you are seeing - without a full sample of your code it is very hard to do.
However, thanks especially to JonPryor on the Xamarin forums I believe I do now at least have a better understanding of what is happening to GREFs in the general case - and so I can answer your 'why' question.
The general case for bound lists is that the GREFs are incremented:
- once for every set of bindings - because the bindings are stored in a hybrid C#/Java container object - https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Binding.Droid/MvxJavaContainer.cs
- once for every ListView item - because that is used in the list
- once for every View object within the ListView which has a bound property or event - e.g. if you are binding to a
TextView
and aButton
within each ListView item, then the C# will store references to these views
In your example, each list item will itself contain a bound list - and this will lead to multiplication of the number of GREFs required - which is why you are seeing the problems reported.
With this understanding in place, the obvious question might be 'how can we solve this?'
That's not a simple question to answer, but I think there are a few ways we might be able to tackle the problem.
Firstly, we could talk with Xamarin about this issue - it may be that the number of available GREFs should be increased - since these objects will be in memory in Java, then perhaps there is no harm with them being referenced in C# as well?
Secondly, we could look at changing the way our UI binding is implemented so that permanent references are not stored to all objects - e.g if we know a binding in one-time (e.g. for a label), then we might look at a route which does not use XML data-binding for this functionality. For example, we could use a new View to perform this binding manually.
Thirdly, we could look at changing the binding code itself so that for one-way binding (from ViewModel to View) it retrieves the Android Views using
FindViewById<TView>
at update time instead of using retained references to the views. This would be slower, but would reduce the number of GREFs required. This functionality might be most achievable in the case of explicitly stated 'one-time' bindings.Fourthly, this is the solution which might be most accessible to you as an app developer, you could look at changing the UI implementation so that the app doesn't use these bound sublists - e.g. it could instead use a label - which only creates the spinner on-demand (by handling the Click event in your code).
I'm sure there are other options beyond this too...
One question I asked myself during this analysis is whether this problem is unique to MvvmCross, or whether it is a problem which might be seen across all MonoDroid applications.
I'm not 100% sure, but the answer, I think, is that this a general issue which would affect all MonoDroid apps. However, I also think that MvvmCross has added a little to the problem:
- by holding on to references of things like TextViews/labels
- by making it easier for you to write code which does reference a lot of Java objects.
I also don't think this is entirely just an MvvmCross or MonoDroid problem. While this GREF limit is being highlighted because of MonoDroid's implementation, the underlying issue here is really one of trying to do too much at one time - so really you could improve your app's performance by stream-lining the design/implementation so that it uses less views. While it may not feel like it, I think MonoDroid is doing us a favour here - it's pointing out that our UI implementation is a bit 'fat' and we should look at optimising it in our app code.
I will update this answer as I find out more, but I hope the above information already gives you quite a good insight into the 'why' of this situation.
这篇关于将MvxBindableSpinner放在MvxBindableListView中时,为什么gref会过高?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!