[Xamarin]我的Xamarin填坑之旅(二)
上一篇交代了我Xamarin填坑的背景,大概聊了聊第一步环境配置,第二步创建项目和开发框架选择。如果有一个可用的梯子,这部分基本不会出错。
接下来就具体聊一聊写代码的过程中遇到的一些事儿。
第三步是码代码:
①Http相关:
我做的项目是一个校园助手,目前提供的功能绝大多数是查询功能。或者说,就是简单的爬虫,从校园服务器上爬取相关网页。因此,结合校园网站以及我的自身需求,我写了一个简单的用于发送Http请求的服务类HttpService,封装了一些Request方法:
public async Task<string> SendRequst(string uri, HttpMethod method, IDictionary<string, string> dic = null, string referUri = "", CancellationToken cancellation = new CancellationToken())
{
HttpResponseMessage response = null;
Encoding encoding = Encoding.UTF8;
try
{
if (!string.IsNullOrEmpty(referUri))
{
_client.DefaultRequestHeaders.Referrer = new Uri(referUri);
} if (method == HttpMethod.Get)
{
response = await _client.GetAsync(uri, cancellation);
}
else
{
FormUrlEncodedContent content = new FormUrlEncodedContent(dic); response = await _client.PostAsync(uri, content, cancellation);
}
var mediaTypeHeaderValue = response.Content.Headers.ContentType;
if (mediaTypeHeaderValue != null && mediaTypeHeaderValue.CharSet != null)
{
if (mediaTypeHeaderValue.CharSet.Contains("gb2312"))
{
encoding = Encoding.GetEncoding("gb2312");
}
}
using (var stream = await response.Content.ReadAsStreamAsync())
{
byte[] buffer = new byte[stream.Length];
await stream.ReadAsync(buffer, , buffer.Length);
var str = encoding.GetString(buffer,,buffer.Length); return str;
}
}
catch
{
throw;
}
finally
{
response?.Dispose();
}
}
这段代码本身没有问题,但是在Xamarin中有个坑。由于需要用到gb2312编码方式,但是我在调试安卓项目的时候,却遇到类似“not support 936 code page”错误,解决的办法就是在安卓项目属性中添加CJK编码方式支持。
这儿有一个最佳实践,分享自周岳老师:
一般所有的Http请求通过HttpClient发起,每一个HttpClient的对象都帮我们维护了Http请求的一些基本信息,包括本地缓存,Cookie等。那默认的,如果Xamarin中直接使用HttpClient,它的实现完全是.net的实现方式。在这儿,可以通过ModernHttpClient来完成一些优化。
在创建HttpClient的时候,可以传入一个ModernHttpClient.NativeMessageHandler实例,作为默认的Handler。这样在Android平台会使用OKHttp来执行一些Http请求,细节可以看作者的Github
HttpClient client=new HttpClient(new ModernHttpClient.NativeMessageHandler() );Nuget:ModernHttpClient
GitHub:ModernHttpClient
在Http请求这块儿,除了上面这个最佳实践,其他部分可以100%重用我UWP项目中的代码。基本无需任何修改。
②HTML Parse:
因为校内网站很少有直接提供REST API服务,所以必须自己从各个页面解析数据。对于Dom的分析,我选择使用AngleSharp这个工具。这个工具现在已经可以支持Xamarin了。
值得高兴的是,个别站点使用了JSON传送数据,针对JSON的解析,目前.Net平台最权威的就是Newtonsoft.Json这个库了,配合Newtonsoft.Json以及.Net的dynamic动态类型,很容易能完成Json的解析。Xamarin完全支持!所以这部分的代码也是100%重用。
官网:AngleSharp
③XXXService:
在上面介绍的Http相关请求中,为了使用方便,我封装了一个基本的HttpBaseService类,主要就是这层各种XXXService获取数据。校园助手目前是以查询为主,包括查询成绩,课表等教务相关的信息,查询一卡通余额,消费,解/挂失等简单的个人信息。于是针对不同的功能大类别,我封装了诸如EduService,InfoService等类,在类中实现了一些方法,用来完成获取数据,解析数据的功能。对这些方法的调用,都是由ViewModel层来完成,所以这部分代码和UWP项目中的也是所差不多。
④ViewModel:
根据MVVM的特点,原则上是一个View对应一个ViewModel。ViewModel层和我UWP项目中的一样,变动不多。但是,在UWP项目中,我使用的是MVVMLight这个框架,而在Xamarin中选择了微软自家的Prism,所以在消息通知,页面导航等方面会有一些不同。下面列举一些使用Prism MVVM时的一些内容。
- 关于页面导航:Prism在页面导航方面,提供了一个接口Prism.Navigation.INavigationService,采用构造函数注入的方式。
- 关于加载数据的问题:每当创建一个ViewModel,我们希望去获取一些数据,可能是存储在本地的,也可能要从网络上获取的。但是考虑到性能问题,这部分数据不能放在构造函数里面。
1.比较好的办法就是当导航到ViewModel对应的View的时候,再去加载数据,Prism框架提供了这样一个接口来实现相关的功能
public interface INavigationAware
{
void OnNavigatedFrom(NavigationParameters parameters);//从当前页面离开时
void OnNavigatedTo(NavigationParameters parameters);//导航到当前页面时
}
可以通过实现该接口,然后在OnNavigationTo方法中去加载一些数据。当然这个接口的作用不限于此,主要作用还是处理页面导航时传递的参数。
2.还有一个我在UWP中常用的办法,就是自定义一个OnLoad方法,然后绑定到View的Loaded事件上面。但这儿有一个很尴尬的问题,Xamarin的Page中并没有一个Loaded事件,相对变通的是它有一个Appearing事件,可以当作Loaded来用。具体的绑定方法如下:
public partial class XXXPage : ContentPage
{
public XXXPage ()
{ InitializeComponent();
this.Appearing += XXXPage _Appearing;
} private void XXXPage _Appearing(object sender, System.EventArgs e)
{
LoadedCommand?.Execute(null);
} public static readonly BindableProperty LoadedCommandProperty = BindableProperty.Create("LoadedCommand", typeof(ICommand), typeof(CampusCardPage), defaultBindingMode: BindingMode.OneWay);//用于绑定的依赖属性
public ICommand LoadedCommand
{
get { return (ICommand)GetValue(LoadedCommandProperty); }
set { SetValue(LoadedCommandProperty, value); }
}
}
上述代码大致在Page中实现一个自定义的LoadedCommand,然后在页面触发Apearing事件的时候,调用该命令的Excute方法,命令则通过数据绑定进行赋值,与ViewModel中的LoadedCommand相相绑定,这也是为什么把LoadedCommand定义为依赖属性的原因。
通过上面提到的1,2两点,就可以在导航到页面以后加载一些数据了,如果配合.net的async/await异步编程模型,就能更加流畅的实现数据加载了。
④Views:
针对View的编写是这次踏坑Xamarin最耗时的部分。虽然Xamarin.Forms可以用Xaml来编写页面,但是和UWP的XAML比起来,功能上差不多,体验上却很不好,尤其是自动补全和智能感知等方面。所以写代码会写的很累。这些其实还好解决,毕竟熟悉一段时间后就基本没有障碍了。唯一欠缺的就是针对XAML代码的Previewer了,虽然今年的Connect()2016大会上,Xamarin Studio里面已经集成了初步的Previewer,但目前离正式发布还有一段距离,尤其是在VS里面。针对这点,给出一个稍微便捷的应对办法。使用工具Gorilla-Player,在真机上预览。具体使用可以看他的WIKI,下面展示一个使用该工具的截图
当然目前这个工具问题还挺多,比如不支持静态资源的引用等。在吐槽的同时,还是需要静静的等待官方的previewer正式发布。
针对View也有一个最佳实践:
因为现在XAML编辑器还不能很好的提供智能感知和自动补全等功能,所以在自己写一些属性的时候,很容易出现拼写错误的问题。往往这种错误在编译的时候,并不会被编译器检查到,于是错误就会发生在运行时,往往耗时耗力。Xamarin为我们提供了一个特性,叫做XamlCompilationAttribute,用来提供编译程序集时候的XAML拼写检查等任务。他可以应用到整个程序集,也可以之应用在单个的View上。只需要指定其参数为XamlCompilationOptions.Compile即可。
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]//用于整个程序集
[XamlCompilation(XamlCompilationOptions.Compile)]//只用于单个Page/View当然XamlCompilation怎么可能会只提供这么一点特性呢?它可以提升整个XAML的性能,通过预编译为IL代码的方式,减少加载XAML的时间。具体看官方文档:
XamlCompilation(https://developer.xamarin.com/guides/xamarin-forms/xaml/xamlc/)
⑤数据存储:
一个完整的App,必须有本地存储,无论是缓存一些文件,还是存储一些必要配置信息。Xamarin跨平台提供了统一的数据存储方式,但是在不同的平台上,具体实现是不同的。数据存储方面,我选择了SQLite这个轻量级的数据库,这也是移动开发本地存储最适合的数据库之一了。好在现在也有比较成熟的ORM工具来支持SQLite了。
Xamarin官方实例(https://developer.xamarin.com/guides/xamarin-forms/working-with/databases/)
nuget:sqlite-net-pcl(https://www.nuget.org/packages/sqlite-net-pcl)
补几张图结束本篇
在码代码的过程中,还遇到过一些其他的坑,以后慢慢更,因为这是连载系列......
[Xamarin]我的Xamarin填坑之旅(二)的更多相关文章
- bootstrap-table填坑之旅<二>事件
接着研究bootstrap-table... ... 这一篇研究bootstrap-table的事件及回调函数 先上一个demo HTML <div class="alert aler ...
- Git 深度学习填坑之旅二(文件三种状态、打标签)
0x01 三种状态 Git 有三种状态,你的文件可能处于其中之一: 已提交(committed).已修改(modified)和已暂存(staged). 已提交表示数据已经安全的保存在本地数据库中. 已 ...
- bootstrap-table填坑之旅<一>认识bootstrap-table
应公司需求,改版公司ERP的数据显示样式.由于前期开发的样式是bootstrap,所以选bootstrap-table理所当然(也是因为看了bootstrap-table官网的example功能强大, ...
- React Native填坑之旅--与Native通信之iOS篇
终于开始新一篇的填坑之旅了.RN厉害的一个地方就是RN可以和Native组件通信.这个Native组件包括native的库和自定义视图,我们今天主要设计的内容是native库方面的只是.自定义视图的使 ...
- React Native填坑之旅--Flow篇(番外)
flow不是React Native必会的技能,但是作为正式的产品开发优势很有必要掌握的技能之一.所以,算是RN填坑之旅系列的番外篇. Flow是一个静态的检查类型检查工具,设计之初的目的就是为了可以 ...
- React Native填坑之旅--布局篇
代码在这里: https://github.com/future-challenger/petshop/tree/master/client/petshop/src/controller 回头看看RN ...
- 使用vue开发微信公众号下SPA站点的填坑之旅
原文发表于本人博客,点击进入使用vue开发微信公众号下SPA站点的填坑之旅 本文为我创业过程中,开发项目的填坑之旅.作为一个技术宅男,我的项目是做一个微信公众号,前后端全部自己搞定,不浪费国家一分钱^ ...
- https填坑之旅
Boss说,我们买了个权威证书,不如做全站式的https吧,让用户打开主页就能看到受信任的绿标.于是我们就开始了填坑之旅. [只上主域好不好?] 不好...console会报出一大堆warning因为 ...
- stm32填坑之旅 - stm32f103c8t6点亮板载贴片蓝色LED
转载请注明:https://www.cnblogs.com/rockyf/p/11691622.html 开篇 开篇一定要精彩,不然路人不理睬!下述是笔者作为arm小白的填坑之旅 没错,这个之前一直从 ...
随机推荐
- html&css精华总结
1.标题标签 h标签 2.段落标签 p 3.换行 br 4.空格 5.大于号,小于号 > < 6.双引号 " 7.版权符号 © 8.注册符 ® --------------- ...
- 349. Intersection of Two Arrays 是否重复
不重复的: 方法一 [一句话思路]:排序之后用归并. [一刷]: 根据返回方法的类型来判断corner case.判断空.0数组的corner case还不一样,得分开写 由于先排序了,nums1[i ...
- [leetcode]403. Frog Jump青蛙过河
A frog is crossing a river. The river is divided into x units and at each unit there may or may not ...
- 全屏API
by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=2679 二.相关文章以 ...
- Can not find the tag library descriptor for "/struts-tags"`
1.查看struts.xml路径是否错误,要放在src下, 2.缺少struts-tags.tld (1)查找方式: (2)找到此包,然后右键用解压缩文件打开. (3)然后你会看到很多的源码,找到红圈 ...
- Stacktraces java.lang.NoSuchMethodException: com.liuyang.action.UserAction.add()
Struts Problem Report Struts has detected an unhandled exception: Messages: com.liuyang.action.UserA ...
- joint python文件拼接
# -*- coding:utf-8 -*- import os import re p1=r"([0-9][0-9][AB])\.\w{3}$" p2=r"^.+\,( ...
- MATLAB实现最优低通滤波器的函数
MATLAB实现最优低通滤波器的函数 % Fs --Data rate % Fpass --pass band % Fstop --Cutoff frequencies % Apass ...
- day13(反射,BeanUtils包)
反射, 获取字节码文件的方式: 方式一: 对象.getClass(); 方式二: 类名.Class; 方式三: Class.forName(String Class); 通过字节码文件获取对象 定 ...
- 几个经典的数学库之一学习---VCGlib(1)
1. VCG Libary是Visulization and Computer Graphics Libary(可视化与计算机图形学库)的缩写,是一个开源的C++模板库,用于三角网格和四面体网格的控制 ...