跨过几个坑,终于完成了我的第一个Xamarin Android App!
时间过得真快,距离上次发随笔又是一年多。作为上次发的我的第一个WP8.1应用总结的后继,这次同样的主要功能,改为实现安卓版APP。前几个月巨硬收购Xamarin,把Xamarin集成到VS里了,大大方便了我广大.net码农。由于年初脱了WP的坑,换了个安卓低端机,想着什么时候装Xamarin开发个App玩玩。
上个月笔记本100G的C盘莫名其妙快满了,趁着重装系统的机会,安装了VS2015 with sp3,下载开发Android App需要的各种东东。这里要感谢【C#】VS2015开发环境的安装和配置系列文章,2016-07-03更新的,已经算是最新的vs2015 with update3的安装说明了。可惜看到这篇文章还是有点相见恨晚,文章里的流程是先下载安装JDK和Android SDK等,最后安装VS,我反过来做,浪费了一些时间。PS:对于使用Hyper-V的同学,可以使用VS自带的安卓模拟器,省却了下载和安装GOOGLE模拟器的一堆时间,据说GOOGLE模拟器还挺坑。。。
================================扯得太多,言归正传======================================
App项目用的是VS里的Android Blank App,先上个图让大家看看我手机上的显示效果,自己用就不需要那么华丽丽了(关键是不会。。。)。
Android App使用的是显示与逻辑分离的设计模式,虽然我基本是做Winform的,也是基本能看懂的。Resources\layout文件夹里放视图文件,而代码逻辑文件放在最外层,整个项目的结构如下图:
这个App主界面使用的是GridLayout进行垂直布局,用法类似于HTML中的Table和WPF中的Grid,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:rowCount="6"
android:columnCount="2">
<TextView
android:id="@+id/tvMachineCode"
android:layout_width="wrap_content"
android:layout_marginRight="5dp"
android:textSize="20sp"
android:layout_marginTop="50dp"
android:text="机器码" />
<EditText
android:id="@+id/txtMachineCode"
android:textSize="20sp"
android:maxLength ="20"
android:layout_marginTop="50dp"
android:layout_width="fill_parent" />
<TextView
android:id="@+id/tvActiviationCode"
android:layout_width="wrap_content"
android:layout_marginRight="5dp"
android:textSize="20sp"
android:layout_marginTop="30dp"
android:text="激活码" />
<EditText
android:id="@+id/txtActiviationCode"
android:textSize="20sp"
android:layout_marginTop="30dp"
android:layout_width="fill_parent" />
<Button
android:id="@+id/btnGetActiviationCode"
android:layout_marginTop="30dp"
android:layout_columnSpan="2"
android:layout_width="match_parent"
android:text="获取激活码" />
<Button
android:id="@+id/btnScanQRCode"
android:layout_columnSpan="2"
android:layout_width="match_parent"
android:text="扫描二维码" />
<Button
android:id="@+id/btnReadQRCode"
android:layout_columnSpan="2"
android:layout_width="match_parent"
android:text="读取二维码" />
<Button
android:id="@+id/btnCopy"
android:layout_columnSpan="2"
android:layout_width="match_parent"
android:text="复制激活码" />
<Button
android:id="@+id/btnShare"
android:layout_columnSpan="2"
android:layout_width="match_parent"
android:text="发送激活码" />
<Button
android:id="@+id/btnClear"
android:layout_columnSpan="2"
android:layout_width="match_parent"
android:text="清除" />
</GridLayout>
Main.axml
界面设计好之后,开始写逻辑代码。App默认是从MainActivity开始启动(JAVA开发可以在Properties\AndroidManifest.xml中修改,有谁知道Xamarin里是怎么改的?)。开始实现第一个按钮的功能,自我感觉还是比较容易的,基本可以直接复制粘贴我Winform里的代码,然而,我发现掉到第一个坑里去了。先看看从Winform里复制来的字符串取MD5的代码,这个在VS自带的模拟器中执行是正常的,得到的结果与Winform一致,但安装到手机里得到的就不对了。
private string MD5(string str, bool clearsplitter = true, bool islower = true)
{
var md5 = MD5CryptoServiceProvider.Create();
var output = md5.ComputeHash(Encoding.Default.GetBytes(str));
StringBuilder strbvalue = new StringBuilder(BitConverter.ToString(output).Replace("-", string.Empty).Substring(, ));
if (!clearsplitter)
strbvalue.Insert(, '-').Insert(, '-').Insert(, '-');
return islower ? strbvalue.ToString().ToLower() : strbvalue.ToString().ToUpper();
}
上网查了下,也问了下别人,电脑里Encoding.Default用的编码是GB2312,而手机里可能是ASCII。由于不能修改之前的代码,只能改这个了,把Encoding.Default改成了Encoding.GetEncoding("gb2312"),结果出乎预料,竟然闪退了。。。又上网搜了下,需要引用Xamarin安装自带的I18N.CJK,总算是搞定了第一个按钮。以下是【获取激活码】和【清除】的代码:
private void Btngetactiviationcode_Click(object sender, EventArgs e)
{
string strerr = ValidateFormat(txtMachineCode.Text);
if (strerr != string.Empty)
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("输入的机器码格式不正确!\n" + strerr);
dlg.Show();
Btnclear_Click(this, null);
return;
}
txtActiviationCode.Text = GetActiveCode(txtMachineCode.Text);
} private void Btnclear_Click(object sender, EventArgs e)
{
txtMachineCode.Text = txtActiviationCode.Text = string.Empty;
} private string GetActiveCode(string machinecode)
{
string guid = "cd89e66c-b897-4ed8-a19f-ef5a30846f0a";
return MD5(machinecode + MD5(guid, false, false), false, false);
} private string MD5(string str, bool clearsplitter = true, bool islower = true)
{
var md5 = MD5CryptoServiceProvider.Create();
var output = md5.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(str));
StringBuilder strbvalue = new StringBuilder(BitConverter.ToString(output).Replace("-", string.Empty).Substring(, ));
if (!clearsplitter)
strbvalue.Insert(, '-').Insert(, '-').Insert(, '-');
return islower ? strbvalue.ToString().ToLower() : strbvalue.ToString().ToUpper();
}
【获取激活码】和【清除】
这个App的主要便利用途就是能够扫描和识别二维码,上网搜了下,使用ZXing库会比较简单,它有个.net移动开发版本叫ZXing.Net.Mobile,可以使用Nuget直接下载添加引用,由于它依赖于Xamarin.Android.Support.v4,所以也要一起下载安装。直接按照ZXing.Net.Mobile官网上的扫描二维码示例代码,就做好了最简单的二维码扫描功能。注意:要在OnCreate方法里先初始化一下:
MobileBarcodeScanner.Initialize(Application);
private async void Btnscanqrcode_Click(object sender, EventArgs e)
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
if (result == null)
return;
txtMachineCode.Text = result.Text.Trim();
Btngetactiviationcode_Click(this, null);
}
完成扫描二维码的功能,顿时信心大增,以为识别图片中的二维码也很简单,结果发现又掉第二个坑里去了。原来,ZXing.Net.Mobile里没有现成简单的识别二维码的方法,只查到可以用IBarcodeReader.Decode()方法来识别,然而它第一个参数byte[] rawRGB是个什么鬼?为毛不能提供一个Bitmap让我爽一下?!去网上搜JAVA版的都是传递Bitmap对象,再去看了下ZXing.Net.Mobile的源码,竟然是有些项目类型是Bitmap对象,有些是byte[]。没时间深究,我还是自己来弄个byte[]吧。
印象中看到过一篇教程里介绍过这个方法,说rawRGB参数指的是每个像素点的RGB值数组,而不是图像文件的二进制数组,这就要读取图像中的所有点的颜色值到数组里里再传递了。
private void Btnreadqrcode_Click(object sender, EventArgs e)
{
Intent = new Intent();
//从文件浏览器和相册等选择图像文件
Intent.SetType("image/*");
Intent.SetAction(Intent.ActionGetContent);
StartActivityForResult(Intent, );
} protected override void OnActivityResult(int requestCode, [GeneratedEnum] Android.App.Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(requestCode == && resultCode == Android.App.Result.Ok && data != null)
{
// create a barcode reader instance
IBarcodeReader reader = new BarcodeReader();
// load a bitmap
int width = , height = ;
//像素颜色值列表(注意:一个像素的每个颜色值都是一个列表中单独的元素,
//后面将会把像素颜色值转换成ARGB32格式的颜色,每个像素颜色值就有4个元素加入到列表中)
List<byte> pixelbytelist = new List<byte>();
try
{
//根据选择的文件路径生成Bitmap对象
using (Bitmap bmp = Android.Provider.MediaStore.Images.Media.GetBitmap(ContentResolver, data.Data))
{
width = bmp.Width; //图像宽度
height = bmp.Height; //图像高度
// detect and decode the barcode inside the bitmap
bmp.LockPixels();
int[] pixels = new int[width * height];
//一次性读取所有像素的颜色值(一个整数)到pixels
bmp.GetPixels(pixels, , width, , , width, height);
bmp.UnlockPixels();
for (int i = ; i < pixels.Length; i++)
{
int p = pixels[i]; //取出一个像素颜色值
//将像素颜色值中的alpha颜色(透明度)添加到列表
pixelbytelist.Add((byte)Color.GetAlphaComponent(p));
//将像素颜色值中的红色添加到列表
pixelbytelist.Add((byte)Color.GetRedComponent(p));
//将像素颜色值中的绿色添加到列表
pixelbytelist.Add((byte)Color.GetGreenComponent(p));
//将像素颜色值中的蓝色添加到列表
pixelbytelist.Add((byte)Color.GetBlueComponent(p));
}
}
//识别
var result = reader.Decode(pixelbytelist.ToArray(), width, height, RGBLuminanceSource.BitmapFormat.ARGB32);
if (result != null)
{
txtMachineCode.Text = result.Text.Trim();
Btngetactiviationcode_Click(this, null);
}
else
Toast.MakeText(this, "未能识别到二维码!", ToastLength.Short).Show();
}
catch (Exception ex)
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("获取图像时发生错误!\n" + ex.ToString());
dlg.Show();
}
}
}
上面就完成了识别二维码的功能,不过上面红色文字那里又出现个只在手机上出现的诡异问题,识别出来的二维码后面会多出一个不可见的字符,它会影响EditText中Text的长度,但不影响Text的值,可以被删除,删除前后计算出的激活码是相同的。没有去看源码,不知道怎么产生的,有人知道吗?
后面的复制激活码和发送激活码比较简单,都是直接找的网上的代码,调用系统功能来做。
private void Btncopy_Click(object sender, EventArgs e)
{
ClipboardManager clip = (ClipboardManager)GetSystemService(ClipboardService);
StringBuilder strbcontent = new StringBuilder();
strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
.AppendLine("激活码:" + txtActiviationCode.Text);
ClipData clipdata = ClipData.NewPlainText("激活码", strbcontent.ToString());
clip.PrimaryClip = clipdata;
Toast.MakeText(this, "激活码已复制到剪贴板", ToastLength.Short).Show();
} private void Btnshare_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtActiviationCode.Text))
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("请先获取激活码!");
dlg.Show();
return;
}
string strerr = ValidateFormat(txtMachineCode.Text);
if (strerr != string.Empty)
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("输入的机器码格式不正确!\n" + strerr);
dlg.Show();
return;
}
Intent intent = new Intent(Intent.ActionSend);
intent.SetType("text/plain");//所有可以分享文本的app
StringBuilder strbcontent = new StringBuilder();
strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
.AppendLine("激活码:" + txtActiviationCode.Text);
intent.PutExtra(Intent.ExtraText, strbcontent.ToString());
StartActivity(Intent.CreateChooser(intent, "发送激活码"));
} private string ValidateFormat(string str)
{
if(str.Length<)
return "输入的格式不正确";
if (str.Length != )
str = str.Substring(, );
string[] strs = str.Split('-');
if (strs.Length != )
return "不能分隔为4组";
foreach (string s in strs)
{
if (s.Length != )
return s + "的长度不是4";
if (!System.Text.RegularExpressions.Regex.IsMatch(s, "^[A-F0-9]{4}$"))
return s + "的格式不正确";
}
return string.Empty;
}
【复制激活码】和【发送激活码】
断断续续写了几个晚上,终于写完这篇随笔了。在眼睛彻底睁不开之前赶紧贴上完整代码。
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using System.Text;
using System.Security.Cryptography;
using ZXing.Mobile;
using Android.Graphics;
using ZXing;
using Android.Database;
using System.Collections.Generic; namespace FMSKeygen_Android
{
[Activity(Label = "流程管理系统注册机", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
private EditText txtMachineCode = null;
private EditText txtActiviationCode = null; protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle); // Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main); // 初始化二维码扫描仪,后面要用到
MobileBarcodeScanner.Initialize(Application); txtMachineCode = FindViewById<EditText>(Resource.Id.txtMachineCode);
//设置自动转换小写字母为大写
txtMachineCode.SetFilters(new Android.Text.IInputFilter[] { new Android.Text.InputFilterAllCaps() });
txtActiviationCode = FindViewById<EditText>(Resource.Id.txtActiviationCode);
//取消对验证码文本框的所有按键监听
txtActiviationCode.KeyListener = null;
Button btnclear = FindViewById<Button>(Resource.Id.btnClear);
btnclear.Click += Btnclear_Click;
Button btngetactiviationcode = FindViewById<Button>(Resource.Id.btnGetActiviationCode);
btngetactiviationcode.Click += Btngetactiviationcode_Click;
Button btnscanqrcode = FindViewById<Button>(Resource.Id.btnScanQRCode);
btnscanqrcode.Click += Btnscanqrcode_Click;
Button btncopy = FindViewById<Button>(Resource.Id.btnCopy);
btncopy.Click += Btncopy_Click;
Button btnreadqrcode = FindViewById<Button>(Resource.Id.btnReadQRCode);
btnreadqrcode.Click += Btnreadqrcode_Click;
Button btnshare = FindViewById<Button>(Resource.Id.btnShare);
btnshare.Click += Btnshare_Click;
} private void Btnshare_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtActiviationCode.Text))
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("请先获取激活码!");
dlg.Show();
return;
}
string strerr = ValidateFormat(txtMachineCode.Text);
if (strerr != string.Empty)
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("输入的机器码格式不正确!\n" + strerr);
dlg.Show();
return;
}
Intent intent = new Intent(Intent.ActionSend);
intent.SetType("text/plain");//所有可以分享文本的app
StringBuilder strbcontent = new StringBuilder();
strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
.AppendLine("激活码:" + txtActiviationCode.Text);
intent.PutExtra(Intent.ExtraText, strbcontent.ToString());
StartActivity(Intent.CreateChooser(intent, "发送激活码"));
} private string ValidateFormat(string str)
{
if(str.Length<)
return "输入的格式不正确";
if (str.Length != )
str = str.Substring(, );
string[] strs = str.Split('-');
if (strs.Length != )
return "不能分隔为4组";
foreach (string s in strs)
{
if (s.Length != )
return s + "的长度不是4";
if (!System.Text.RegularExpressions.Regex.IsMatch(s, "^[A-F0-9]{4}$"))
return s + "的格式不正确";
}
return string.Empty;
} private void Btnreadqrcode_Click(object sender, EventArgs e)
{
Intent = new Intent();
//从文件浏览器和相册等选择图像文件
Intent.SetType("image/*");
Intent.SetAction(Intent.ActionGetContent);
StartActivityForResult(Intent, );
} protected override void OnActivityResult(int requestCode, [GeneratedEnum] Android.App.Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(requestCode == && resultCode == Android.App.Result.Ok && data != null)
{
// create a barcode reader instance
IBarcodeReader reader = new BarcodeReader();
// load a bitmap
int width = , height = ;
//像素颜色值列表(注意:一个像素的每个颜色值都是一个列表中单独的元素,
//后面将会把像素颜色值转换成ARGB32格式的颜色,每个像素颜色值就有4个元素加入到列表中)
List<byte> pixelbytelist = new List<byte>();
try
{
//根据选择的文件路径生成Bitmap对象
using (Bitmap bmp = Android.Provider.MediaStore.Images.Media.GetBitmap(ContentResolver, data.Data))
{
width = bmp.Width; //图像宽度
height = bmp.Height; //图像高度
// detect and decode the barcode inside the bitmap
bmp.LockPixels();
int[] pixels = new int[width * height];
//一次性读取所有像素的颜色值(一个整数)到pixels
bmp.GetPixels(pixels, , width, , , width, height);
bmp.UnlockPixels();
for (int i = ; i < pixels.Length; i++)
{
int p = pixels[i]; //取出一个像素颜色值
//将像素颜色值中的alpha颜色(透明度)添加到列表
pixelbytelist.Add((byte)Color.GetAlphaComponent(p));
//将像素颜色值中的红色添加到列表
pixelbytelist.Add((byte)Color.GetRedComponent(p));
//将像素颜色值中的绿色添加到列表
pixelbytelist.Add((byte)Color.GetGreenComponent(p));
//将像素颜色值中的蓝色添加到列表
pixelbytelist.Add((byte)Color.GetBlueComponent(p));
}
}
//识别
var result = reader.Decode(pixelbytelist.ToArray(), width, height, RGBLuminanceSource.BitmapFormat.ARGB32);
if (result != null)
{
txtMachineCode.Text = result.Text.Trim();
Btngetactiviationcode_Click(this, null);
}
else
Toast.MakeText(this, "未能识别到二维码!", ToastLength.Short).Show();
}
catch (Exception ex)
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("获取图像时发生错误!\n" + ex.ToString());
dlg.Show();
}
}
} private void Btncopy_Click(object sender, EventArgs e)
{
ClipboardManager clip = (ClipboardManager)GetSystemService(ClipboardService);
StringBuilder strbcontent = new StringBuilder();
strbcontent.AppendLine("机器码:" + txtMachineCode.Text)
.AppendLine("激活码:" + txtActiviationCode.Text);
ClipData clipdata = ClipData.NewPlainText("激活码", strbcontent.ToString());
clip.PrimaryClip = clipdata;
Toast.MakeText(this, "激活码已复制到剪贴板", ToastLength.Short).Show();
} private async void Btnscanqrcode_Click(object sender, EventArgs e)
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
if (result == null)
return;
txtMachineCode.Text = result.Text.Trim();
Btngetactiviationcode_Click(this, null);
} private void Btngetactiviationcode_Click(object sender, EventArgs e)
{
string strerr = ValidateFormat(txtMachineCode.Text);
if (strerr != string.Empty)
{
var dlg = new AlertDialog.Builder(this).SetTitle("警告")
.SetMessage("输入的机器码格式不正确!\n" + strerr);
dlg.Show();
Btnclear_Click(this, null);
return;
}
txtActiviationCode.Text = GetActiveCode(txtMachineCode.Text);
} private void Btnclear_Click(object sender, EventArgs e)
{
txtMachineCode.Text = txtActiviationCode.Text = string.Empty;
} private string GetActiveCode(string machinecode)
{
string guid = "cd89e66c-b897-4ed8-a19f-ef5a30846f0a";
return MD5(machinecode + MD5(guid, false, false), false, false);
} private string MD5(string str, bool clearsplitter = true, bool islower = true)
{
var md5 = MD5CryptoServiceProvider.Create();
var output = md5.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(str));
StringBuilder strbvalue = new StringBuilder(BitConverter.ToString(output).Replace("-", string.Empty).Substring(, ));
if (!clearsplitter)
strbvalue.Insert(, '-').Insert(, '-').Insert(, '-');
return islower ? strbvalue.ToString().ToLower() : strbvalue.ToString().ToUpper();
}
}
}
完整代码
碎觉。。
跨过几个坑,终于完成了我的第一个Xamarin Android App!的更多相关文章
- [置顶]
xamarin android toolbar(踩坑完全入门详解)
网上关于toolbar的教程有很多,很多新手,在使用toolbar的时候踩坑实在太多了,不好好总结一下,实在浪费.如果你想学习toolbar,你肯定会去去搜索androd toolbar,既然你能看到 ...
- Java web 开发填坑记 2 -如何正确的创建一个Java Web 项目
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72566261 本文出自[赵彦军的博客] Java web 开发填坑记 1-如何正确 ...
- 《深入理解Java虚拟机》第2版挖的坑终于在第3版中被R大填平了
这是why技术的第34篇原创文章 本周还是在家办公的一周,上面的图就是我在家的工位,和上周<Dubbo Cluster集群那点你不知道的事>这篇文章里面的第一张图片比起来,升级了显示器支撑 ...
- 跨过Django的坑
在最近的Django的学习中,慢慢的开始踩坑,开此栏,专为收纳Django的坑,在以后的学习中以便警示.(使用工具为pycharm专业版2018.2.4,python3.5.2,Django版本2.1 ...
- 网站搭建 - IIS 填坑 - 终于建好站了 linux + Windows
之前的IIS可以运行Windows的网页,但是对于php的网页,还是不能够支持,于是决定重新来一遍. (把踩的坑重新描述一下,在下载完php之后,解压后不要急着改文件,跳到最后的页面去改.) 以便能够 ...
- vue.js 踩坑第一步 利用vue-cli vue-router搭建一个带有底部导航栏移动前端项目
vue.js学习 踩坑第一步 1.首先安装vue-cli脚手架 不多赘述,主要参考WiseWrong 的 Vue 爬坑之路(一)-- 使用 vue-cli 搭建项目 2.项目呈现效果 项目呈现网址:w ...
- 我的新书《Android App开发从入门到精通》终于出版啦
前言 经过了两年多终于完成了这本书,2016年9月份开始写的,到今天为止2年零2个月,本书的内容大部分是去年完成的,看过我去年总结的读者可能知道,去年事情很多太忙了,导致本命年这本书没有上架(有点小小 ...
- [置顶]
Android App引导页这些坑你自己犯过吗?
场景:测试机:华为荣耀6x 今天我自己掉入一个很蠢蠢的坑,一个引导页搞了20多分钟,不管我怎么测试用真机还是模拟器都无法运行,但是我写的demo完全没问题,好无语,我都怀疑我是不是搞android,我 ...
- Android App引导页这些坑你自己犯过吗?
场景:測试机:华为荣耀6x 今天我自己掉入一个非常蠢蠢的坑,一个引导页搞了20多分钟.无论我怎么測试用真机还是模拟器都无法执行,可是我写的demo全然没问题,好无语,我都怀疑我是不是搞android, ...
随机推荐
- c语言中static的用法,包括全局变量和局部变量用static修饰
一.c程序存储空间布局 C程序一直由下列部分组成: 1)正文段--CPU执行的机器指令部分:一个程序只有一个副本:只读,防止程序由于意外事故而修改自身指令: 2)初始化数据段(数据段)--在程序中所有 ...
- ListView addHeaderView 对 position 的影响
1. 在 public View getView(int position, View convertView, ViewGroup parent) 中position 和 是否有headerView ...
- 处理ios webview 更新缓存本地css、js后webview缓存无法更新的问题
项目中需要使用app本地css.js,并且可以根据服务下发自动更新本地css.js.测试发现只要更新后的css或者js和更新前路径一致,webview加载的还是更新前的css.js.怀疑是webvie ...
- Python六大开源框架对比:Web2py略胜一筹
Python是一门动态.面向对象语言.其最初就是作为一门面向对象语言设计的,并且在后期又加入了一些更高级的特性.除了语言本身的设计目的之外,Python标准库也是值得大家称赞的,Python甚至还自带 ...
- POJ 3667 Hotel(线段树 区间合并)
Hotel 转载自:http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html [题目链接]Hotel [题目类型]线段树 ...
- 对话框AlertDialog.Builder使用方法
我们在平时做开发的时候,免不了会用到各种各样的对话框,相信有过其他平台开发经验的朋友都会知道,大部分的平台都只提供了几个最简单的实现,如果我们想实现自己特定需求的对话框,大家可能首先会想到,通过继承等 ...
- SQL Server 2014 SP2发布下载:数十项更新修复
微软发布了数据库工具SQL Server 2014 SP2服务包下载,本次更新集合了数十项更新修复,涉及安全和功能性补丁,使用SQL Server 2014的用户应该及时安装该服务包. 文件内容 版本 ...
- 【原创】ORACLE常见使用问题解决
ORACLE常见使用问题解决 一.安装了oracle客户端后,发现plsql客户端找不到之前已经配置过的TNS连接信息 或许大家再使用ORACLE软件的过程中,经常会遇到这样的问题: 问题现象描述: ...
- R&S学习笔记(三)
1.GRE OVER IPv4 GRE协议栈:IPSEC只支持TCP/IP协议的网络,GRE则支持多协议,不同的网络类型.(如IPX,APPLETALK):通常IPSEC over gre结合使用, ...
- 开源项目大全 >> ...
http://www.isenhao.com/xueke/jisuanji/kaiyuan.php 监控系统-Nagios 网络流量监测图形分析工具-Cacti 分布式系统监视-zabbix 系统 ...