转载

Xamarin 实现 Android 无限循环展示, FlipView

先发个图, 让你们知道我说的是什么:

Xamarin 实现 Android 无限循环展示, FlipView

在这之前,  写过一个用于 Xamarin.Form (以下简称 XF ) 的 FlipView,  Android 下是用 HorizontalScrollView 模拟的.

上上周, 无意间看到了 ViewPager 如何实现无限循环的方法 , 于是捉摸在 Xamarin 下把它给实现一下.

在 XF 下, 你可以看到从网络加载的 大图  显示的很流畅 , 因为 XF 下, UriImageSource 这个图片源有这么两个属性:

CacheValidity缓存多长时间

CachingEnabled是否启用缓存

这说明在 XF 下, 已经封装好了类似于 Android 的 LRUCacheDiskLRUCache , 注意, 这仅仅是在 XF 下才有这个功能. 

一开始不了解这个个梗, 在 Android 项目(不是 XF 项目) 遇到了这几个问题:

1, 在主线程上无法加载网络图片

不了解这个的原因, 查到的资料说在 Android 4.0 以后 (未验证) , 不允许阻塞主线程.

直接从网络加载图片明显会有阻塞, 所以运行肯定是没有结果的等待, 直至崩溃.

2, OOM

这个问题, 对搞 Android 开发的人来说, 在普通不过了.全称是 Out Of Memory,  就是内存溢出.

OOM 的解决办法介绍最多的就是用缓存, 也就是上面提到的 LRUCache (这个Android SDK 中提供的有) 和 DiskLRUCache (SDK中没有, 但是有源码).

LRUCache 是放到内存中的, 应用一关闭, 缓存的数据就丢失了.

DiskLRUCache 是把文件存放到手机的 "硬盘" (区分于内存)中.

3, Adapter 的数据源为 IEnumerable

自定义的 Adapter,  如果数据源是一个 IEnumerable , 如果传给 Adapter 之前, 没有 ToList, 在执行的时候, 会一直的去调用这个 IEnumerable 的生成函数.

如这样:

1         private IEnumerable<AV.View> GetChildrenViews() { 2             foreach (var v in this.Element.Children) { 3                 var render = RendererFactory.GetRenderer(v); 4                 var c = new AW.FrameLayout(this.Context); 5                 c.SetBackgroundColor(Color.Blue.ToAndroid()); 6                 c.AddView(render.ViewGroup, LayoutParams.MatchParent, LayoutParams.MatchParent); 7                 yield return c; 8             } 9         }

如果不 ToList 就把这个函数的结果传入 Adapter, foreach 这块会一直的被调用.

4, System.IO.IOException: Sharing violation on path XXX

报这个问题, 是因为使用了 Mono 的 IsolatedStorage, 在 Stream.CopyToAsync 时如果不指定 bufferSize 就会报这个错

诡异的是, 在公司的电脑上如果指定 bufferSize , 就没有这个错误, 在家里的电脑上指不指定 bufferSize 都会报这个错.

但是放try..catch.. 之中, 文件又可以写成功 (从调试输出的内容看, 第二次运行,不会在从网络上加载图片).

是不是我写法有问题?

 1         public async Task WriteStream(string file, Stream stm) {  2             var path = this.GetPath(file);  3   4             try {  5                 using (var fs = ISF.OpenFile(path, FileMode.OpenOrCreate, FileAccess.Write)) {  6                     //await stm.CopyToAsync(fs); 如果不指定 buff size , 会报错  7                     await stm.CopyToAsync(fs, 16384);  8                 }  9             } catch { 10  11             } 12         }

5, 如何实现无限循环

这部分是参考别人的 (来源找不到了), 通俗来说, 是这样的:

A, Adapter 的 Count 属性返回真实数据条数的整数, 假如我只有3条数据, 我会欺骗 Adapter , 我有6条.

B, 在确定要显示哪一条数据的时候, 要获取给出 position 对应的真实的数据条目. 用这个 position 求余 真实数据的条目.

即在 Adapter 的 InstantiateItem 方法中, 用 position %= this.Items.Count() 来取出真正的要显示哪条数据. 假如有 3 条数据, 当前的 position 是 5, 其实要显示的就是第2条数据.

C, Adapter 的 FinishUpdate 方法.

 1         public override void FinishUpdate(ViewGroup container) {  2             var vp = container as ViewPager;  3             var pos = vp.CurrentItem;  4   5             if (pos == 0) {  6                 pos = this.Items.Count();/////////////  7             } else if (pos == this.Count - 1) {  8                 pos = this.Items.Count() - 1;///////////////  9             } 10             //System.Diagnostics.Debug.WriteLine("====> pos {0}", pos); 11             vp.SetCurrentItem(pos, false); 12         }

如果真实条数是 3, Adapter 的 Count 被设为 6, 就会这样:

0 1 2 0 1 2

如果当前的 pos 是 0 , 就设置 pos 为第4位上的那个0, 即第二轮的第0位 (下标从0开始啊).

如果 pos 为 5 (下标从0开始), 就设置 pos 为第一轮的最后一个, 即第一个2.

-----------------

OK , 就这些, 照例, 上源码:

直接的 Android 项目: https://github.com/gruan01/Xamarin-Example/tree/master/FlipView

用于 Xamarin.Form 的: https://github.com/gruan01/FlipView

另外, 我并没有实现网上流传的那个 DiskLruCache , 而是用 IsolatedStorage 实现了个简单的. 很大可能隐藏其它问题.

正文到此结束
Loading...