Mikel的技术博客专注于大数据分析、人工智能行业应用及企业级应用软件开发Mikel
  • 开发笔记
    • JavaScript
    • ASP.NET
    • C#
    • ASP.NET MVC
    • iOS开发
    • Android
    • AR
    • Java
    • PHP
    • Delphi
    • Debug
    • 数据库
    • 架构设计
    • 项目管理
    • Flash
  • 网站运营
    • 建站经验
    • 网络营销
    • 搜索优化
    • 电子商务
    • 互联网
  • 源码下载
  • 人工智能
    • 机器学习
  • C#
  • Java
  • Python
  • JavaScript
  • PHP
  • 数据库
  • Debug
  • 微信小程序开发
  • 关注我们
    • 威客
Hi, 请登录     我要注册     找回密码
分享到: 更多 (0)

开发笔记 第601页

记录了我开发过程中遇到的问题和资料

[转载]向设计师推荐20款漂亮的免费英文字体

2011-05-03mikel阅读(1074)

[转载]向设计师推荐20款漂亮的免费英文字体 – 梦想天空 – 博客园.

本文收集了20款非常漂亮的免费字体,特别适合网页设计师,平面设计师和电脑艺术人员。 如果你正在寻找漂亮的字体,那么这份清单正是为你准备的。

1. Fertigo Professional Free Font

2. Lost in Space

3. Font Cube

4. Just Old Fashion

5. Quadranta

6. Museo Slab

7. Obitron

8. Cyclo

9. Square Type B

10. Oblik

11. Sweet confusion

12. Gabrielle

13. Melbourne

14. Piron

15. Steiner

16. Telegrafico

17. Caprica

18. Butter

19. Diavlo

20. File

(编译来源:梦想天空 原文来自:20 free fonts for web designers)

[转载]InstallShield 部署安装包整理(3)

2011-05-03mikel阅读(996)

[转载]InstallShield 部署安装包整理(3) – zhaodyun – 博客园.

InstallShield 调用批处理部署MySQL数据库

说明:InstallShield版本: 2010

需求:自动部署mySQL数据库

实现方法:先给客气机安装mySQL的ODBC,以便测试客户输入的用户名密码正确,调用批处理自动部署数据库

由于用ODBC执行mysql脚本导入数据时中文为乱码,这个一直没解决,所以没办法只有想到调用批处理实现Mysql自动部署了!导入需要三个文件,从MySql安装根目录下的Mysql.exe,和你自己的写的导入数据的批处理,要导入的sql脚本文件。

一.InstallShield调用外部mysql odbc msi安装包实现mysql odbc部署

1>在Behavior and Logic->Support Files/Billboards

Support Files->Language Independent下添加要调用的外部msi文件

在OnBegin事件里添加代码判断mysql odbc是否存在并安装mysql的odbc。

szKey="\\SOFTWARE\\ODBC\\ODBCINST.INI\\MySQL ODBC 3.51 Driver";   nResult=RegDBKeyExist(szKey);   if(nResult<0) then   szParam="/i "+SUPPORTDIR^"MyODBC.msi"+" /qb";   if(LaunchAppAndWait("msiexec.exe",szParam,WAIT)<0) then   MessageBox("Mysql ODBC Install failed!",INFORMATION);   endif;   endif;

二.InstallShield调用外部程序

1>在Behavior and Logic->Support Files/Billboards

Support Files->Language Independent下添加要调用的外部可执行文件

此处为执行安装数据库的批处理文件

2>在setup.rul脚本文件的OnSQLLogin的事件后面添加代码向批处理

传递服务器IP,用户名,数据库密码这三个参数

if( bNext ) then //此处添加安装数据库代码 szParam= szServer+" "+szUser+" "+szPassword; //MessageBox(szParam,MB_OK); LaunchAppAndWait(SUPPORTDIR^"bat.bat",szParam,WAIT); return NEXT; else return BACK; endif;

这样当用户在安装时的数据库登陆界面里点击下一步时便执行此处的代码安装数据库实现mysql数据库的自动部署。

[转载]InstallShield 部署安装包整理(2)

2011-05-03mikel阅读(1069)

[转载]InstallShield 部署安装包整理(2) – zhaodyun – 博客园.

说明:InstallShield 版本:2010

部署要求:小组考试系统教师端与学生端WebService,根据客户服务器设置配置Web.config,项目是基于.Net 2.0

说明:由于WebService的部署与Web Site部署一样所以这里掌握InStallShield的Web Site部署就行了

一.设置项目基本信息

略

二.添加网站对应Feture,添加Feture下面对应Components

->在Files and Folders下面添加对应文件夹并在其目录下面添加网站发布文件,

保证他们对应关系一致.

->在Server Configuration->Internet Information Services->Web Sites

右键单击Add Web Site

->对添加的Web Site属性进行设置

*Identification

Name:网站的名称

IP Address:IP地址

TCP Port Number:在此处设置你想设置网站的端口号

Host Header Name:如果网站有域名的话,在这设置

Site Number:默认为0,帮助文档上面看和不是很懂,这里一般不用设置

*General

Component:这里指定你设置网站的组件,注意这里你得切换到Components标签下把这里的这个组件的Destination属性设置成你存放网站的那个目录。

ASP.NET Version:如果是.Net项目在 这里设置项目版本

ASP.NET Platform:应该这里是设置部署目标系统的

Delete on Uninstall:Yes/No是否在卸时删除Web Site

Default Document:一般也不用设置

*Home Directory

Content Source Path(Local or UNC):设置你网站默认的文件夹,这个设置发布网站所在的文件夹

以下是对主目录的一些设置(IIS6里主目录选项卡里的设置)

Script Source Acess:是否允许脚本资源访问

Read Access:读取

Write Access:写入

Drictory Browsing:目录浏览

Log Vists:记录访问

Index Resource:索引资源

*Application Settings

Application Pool:应用程序池一般就先默认的DefaultAppPool

Application Mapping:默认

Session Timeout:默认

Asp ScriptTimeout:默认

*Security/Advanced

这个里面没用到,有用到的可以再看帮助文档

三.Web Site设置

New Application:建立网站

这个还没试过

New Virtual Directory:建立虚拟目录

其设置属性与Web Site的差不多,大多有重复,这里和上面一样

这里发现其实你不添加这两项的话也可以发布你的Web项目

四.权限设置

这个在添加发布网站的时候可以设置文件夹或Component的属性

具体操作:File and Folder选中存放发布网站的文件夹右键Properties->Permissions可以在这个界面里对要发布的网站进行权限设置。

五.数据库部署

见上一篇用的是MySQL

六.动态修改Web Site的配置文件

1>在System ConfigurationXML file Change里在指定的Feture下添加或导入Web Config文件,修改配置文件的连接字符串节点的

server=[IS_SQLServer_SERVER];database=数据库名;Userid=[IS_SQLServer_USERNAME];Pwd=[IS_SQLSERVER_PASSWORD];

这里将自动把客户输入的服务器ip,数据库用户名和密码写入到这个文件.

2>下面就是如何把把这个文件关联到网站文件夹的目录

选中web.config文件,选中General选项卡,

在XML File Destination为你网站的文件目录

在Select Features the XML file belong to:配置文件所在的Feture

最后没解决的问题:InstallShield里用ODBC部署MySql数据库时执行插入数据的sql脚本后生成的数据为乱码!

下面上传我部署WebService的例子文件,由于里面文件是项目里WebService,所以文件都删除了,有需要的可以看看,希望对你有帮助!如果有更多要求的话,建议自己再多看看帮助文档!

Deploy WebService

[转载]基于Lodop控件的Web打印

2011-05-03mikel阅读(984)

[转载]基于Lodop控件的Web打印 – Vincent.Q – 博客园.

最近项目组的打印控件有所改变,已经换成Lodop控件,使用以后发现,功能确实非常强大.可以打印Web页面内某个控件的内容.下面,还是通过一个实例 来说明下吧,医院系统有个模块,是院内感染模块,它需要填写各种报卡,并且填写完以后,要将它打印出来,而且打印出来的效果要和纸制的报卡近乎一致.额, 这个要求就比较高喽,如图-1所示,这是其中一张报卡的纸制扫描效果图,我们打印出来的效果要和这个几乎一样.

clip_image002

图-1

现在我们来分析一下这里的打印展示类型.

类型1:患者姓名,卡片编号等,直接取自Db栏目值,不需要额外加工.不过,有的需要增加下划线功能.

类型2:出生日期,需要对日期进行拆分,增加汉字:年,月和日

类型3:户籍属于,全部复选框,将其中某一数据选中

类型4:户籍地址,是Db中多个栏目拼接而成.而且都是将数据值替换为显示值

OK,经过以上的分析,上述这些打印类型是可以通过配置的方式实现.新建一XML配置文件,如图-2所示

clip_image004

图-2

字段说明:

字段描述 描述
itemname 打印模板中被替换关键字,同时也是Db表中某列名称
itemparename 若打印类型是comboitem这种组合方式,它用来定义包括哪些子itemname
printstyle 打印类型,目前包括:textbox,dropdownlist,datetime,checkboxlist和comboitem(组合方式,即由其他多个字段组合而成)
printformat 打印格式,日期型的输出格式在此处定义
bottomline 是否对文字增加下划线
datasource 下拉菜单等的数据源,专门测试使用

然后我们看看打印模板文件是如何制作的,如图-3所示

clip_image005

图-3

现在,我们就要通过编码的方式来实现将这些关键字替换掉,简单说,是根据不同的打印格式分别处理.比较核心的代码如图-4所示

clip_image007

图-4

经过上述代码的编写,我们看看最终的效果图,如图-5所示

clip_image009

图-5

打印控件本身非常强大,可以连续打印.在我提供的示例文件中,已经提供代码实现方式.大家可以直接参考.

再说明一点,这个控件,是在客户端需要安装的.好了,有什么问题欢迎留言!

示例代码

基于Lodop控件的Web打印.Files

[转载]提供一个网页抓取hao123手机号码归属地的例子

2011-05-02mikel阅读(1057)

[转载]提供一个网页抓取hao123手机号码归属地的例子 – 苏飞—Perky Su – 博客园.

有段时间不写博客了,最近工作压力比较大,大家在忙什么,新近安装了Win7的操作系统,感觉很不错,还体验了一把IE9,里面的开发人员工具很好用

说到这个大家可以用火狐的谷歌的都行,在这个例子中我主要使用IE9自带的分析一下hao123的手机号码归属地查询的问题。

我们先来看看下面的图片吧

在hao123的这个界面里我们只要输入一个手机号不管是移动,联通,电信的都可以,单击查询就可以直接查询到归属地,和号码类型,网上这样的

网站很多,我就以这个为例子吧,那我们怎么样把这些信息放到我们自己的网站上呢?

我们先来分析一下,其实很方便,我们在IE9下打开这个界面然后在工具—开发人员工具,或是直接安f12也是一样的效果,我们安界面定位到如下图

我们先单击网络然后单击开始捕获,这个时候我们再单击一下查询按钮看看会出现什么情况

是不是出现两个整个,第一个很明显是加载我们所输入号归属地信息,第一个是加载一个图片,对我们没有任何用处,这里不管它,现在我们

来单击一下第一个方法看看捕获到了什么

URL http://vip.showji.com/locating/?m=13888888888&outfmt=json&callback=phone.callBack 很明显这是一个GEt请求,只要请求这个地址就能得到下面的结果

phone.callBack({“Mobile”:”13888888888″,”QueryResult”:”True”,”Province”:” 云南”,”City”:”昆明”,”AreaCode”:”0871″,”PostCode”:”650000″,”Corp”:”中国移 动”,”Card”:”GSM”});

用手机号,省,市,还有邮编,号码类型等信息。这样看的话是不是我们直接把这个地区复制到地址栏里就行了,那咱们一起来看看效果吧

果然没错就是我们想要的东西,大家别急,其它还可以更简单,我们来看一下这个URL

http://vip.showji.com/locating/?m=13888888888&outfmt=json&callback=phone.callBack

如果现在我把这个RUles号码后面的删除只保留http://vip.showji.com/locating/?m=13888888888这些会出现什么情况呢?

直接放到地址栏里试试效果

呵呵,很神奇吧,居然得到的是一个Xml文件

这就像是我们在调用WebServces一样简单了,我们只要写一个程序请求这个地址就可以得到我们想要的效果了。

随便新建一个项目,一起来看一下

我就不一步一步的分析了大家直接看我的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Security.Cryptography;
using System.Xml;

namespace ccbText
{
public partial class Form2 : Form
{

public Form2()
{
InitializeComponent();
}

private void Form2_Load(object sender, EventArgs e)
{
}
这个方法在这里没有用到,大家可以做为参考
///
/// 传入URL返回网页的html代码
///
///
<span> </span>URL         ///
public string GetUrltoHtml(string Url)
{
StringBuilder content = new StringBuilder();

try
{
// 与指定URL创建HTTP请求
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.KeepAlive = false;
// 获取对应HTTP请求的响应
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// 获取响应流
Stream responseStream = response.GetResponseStream();
// 对接响应流(以"GBK"字符集)
StreamReader sReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
// 开始读取数据
Char[] sReaderBuffer = new Char[256];
int count = sReader.Read(sReaderBuffer, 0, 256);
while (count &gt; 0)
{
String tempStr = new String(sReaderBuffer, 0, count);
content.Append(tempStr);
count = sReader.Read(sReaderBuffer, 0, 256);
}
// 读取结束
sReader.Close();
}
catch (Exception)
{
content = new StringBuilder("Runtime Error");
}

return content.ToString();

}

///
/// 好123查询,符合下列规则也可使用
/// 返回xml
/// 需要顺序的节点:
/// QueryResult(查询结果状态True,False)
/// Province(所属省份)
/// City(所属地区)
/// Corp(服务商)
/// Card(卡类型 GSM)
/// AreaCode(区号)
/// PostCode(邮编)
///
///
<span> </span> ///
///
public static string[] GetInfoByxml(string url, string mobileNum)
{
try
{
XmlDocument xml = new XmlDocument();
// xml.LoadXml("

<!--?xml version='1.0' encoding='utf-8' ?-->15890636739True
河南郑州0371
450000中国移动GSM");
xml.Load(string.Format(url, mobileNum));
XmlNamespaceManager xmlNm = new XmlNamespaceManager(xml.NameTable);
xmlNm.AddNamespace("content", "http://api.showji.com/Locating/");
XmlNodeList nodes = xml.SelectNodes("//content:QueryResult|//content:Mobile|//content:Province|//content:City|//content:Corp|//content:Card|//content:AreaCode|//content:PostCode", xmlNm);
if (nodes.Count == 8)
{
if ("True".Equals(nodes[1].InnerText))
{

return new string[] { nodes[0].InnerText, nodes[2].InnerText + nodes[3].InnerText, nodes[6].InnerText + nodes[7].InnerText, nodes[4].InnerText, nodes[5].InnerText };
}
}
return new string[] { "FALSE" };
}
catch
{
return new string[] { "FALSE" };
}
}

//调用方法查询数据
private void button1_Click(object sender, EventArgs e)
{
foreach (string item in GetInfoByxml(" http://vip.showji.com/locating/?m={0}", txtMobile.Text.Trim()))
{
richTextBox1.Text += "__" + item;
}
}
}
}

运行一下看看效果吧

我是用Winfrom做的测试,大家如果想用Asp。Net也是一样的,把我的方法复制到你的Web页面的Cs代码下就OK了。

好了我们的分析到这里就算是结束了,

在这里我再给大空补充一个关于调用带有证书的网站的调用 方法

因为带证书的都是在要验证证书文件的,我们在这里直接让他在本地回调验证,这样的话就要吧重写方法了,下在看一下回调的方法吧

//回调验证证书问题
public bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{   // 总是接受
return true;
}

其它很简单只要在 我们上面的方法GetUrltoHtml()中加入几行代码就行了,修改后的方法

///
/// 传入URL返回网页的html代码
///
///
<span> </span>URL         ///
public string GetUrltoHtml(string Url)
{
StringBuilder content = new StringBuilder();
try
{
// 与指定URL创建HTTP请求
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);//验证

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
request.KeepAlive = false;
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; MS-RTC LM 8; .NET4.0C; .NET4.0E)";
request.Method = "GET";
request.Accept = "*/*";

//创建证书文件
X509Certificate objx509 = new X509Certificate(Application.StartupPath + "\\123.cer");

//添加到请求里
request.ClientCertificates.Add(objx509);

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// 获取对应HTTP请求的响应
// 获取响应流
Stream responseStream = response.GetResponseStream();
// 对接响应流(以"GBK"字符集)
StreamReader sReader = new StreamReader(responseStream, Encoding.GetEncoding("GBK"));
// 开始读取数据
Char[] sReaderBuffer = new Char[256];
int count = sReader.Read(sReaderBuffer, 0, 256);
while (count &gt; 0)
{
String tempStr = new String(sReaderBuffer, 0, count);
content.Append(tempStr);
count = sReader.Read(sReaderBuffer, 0, 256);
}
// 读取结束
sReader.Close();
}
catch (Exception)
{
content = new StringBuilder("Runtime Error");
}

return content.ToString();

}

欢迎大家转载,如有转载请注明文章来自:   http://sufei.cnblogs.com/

签名:做一番一生引以为豪的事业;在有生之年报答帮过我的人;并有能力帮助需要帮助的人;

QQ:361983679 Email:sufei.1013@163.com MSN:sufei.1013@163.com

[转载]详解ASP.NET MVC的请求生命周期

2011-04-29mikel阅读(800)

[转载]详解ASP.NET MVC的请求生命周期 – twfx7758的日志 – 网易博客.

本文的目的旨在详细描述ASP.NET MVC请求从开始到结束的每一个过程。我希望能理解在浏览器输入URL并敲击回车来请求一个ASP.NET MVC网站的页面之后发生的任何事情。
为什么需要关心这些?有两个原因。首先是因为ASP.NET MVC是一个扩展性非常强的框架。例如,我们可以插入不同的ViewEngine来控制网站内容呈现的方式。我们还可以定义控制器生成和分配到某个请求的 方式。因为我想发掘任何ASP.NET MVC页面请求的扩展点,所以我要来探究请求过程中的一些步骤。
其次,如果你对测试驱动开发佷感兴趣,当为控制器写单元测试时,我们就必须理解控制器的依赖项。在写测试的时候,我们需要使用诸如Typemock Isolator或Rhino Mocks的Mock框架来模拟某些对象。如果不了解页面请求生命周期就不能进行有效的模拟。
生命周期步骤概览
当我们对ASP.NET MVC网站发出一个请求的时候,会发生5个主要步骤:
步骤1:创建RouteTable
当ASP.NET应用程序第一次启动的时候才会发生第一步。RouteTable把URL映射到Handler。
步骤2:UrlRoutingModule拦截请求
第二步在我们发起请求的时候发生。UrlRoutingModule拦截了每一个请求并且创建和执行合适的Handler。
步骤3:执行MvcHandler
MvcHandler创建了控制器,并且把控制器传入ControllerContext,然后执行控制器。
步骤4:执行控制器
控制器检测要执行的控制器方法,构建参数列表并且执行方法。
步骤5:调用RenderView方法
大多数情况下,控制器方法调用RenderView()来把内容呈现回浏览器。Controller.RenderView()方法把这个工作委托给某个ViewEngine来做。
现在让我们来详细研究每一个步骤:
步骤1:创建RouteTable
当我们请求普通ASP.NET应用程序页面的时候,对于每一个页面请求都会在磁盘上有这样一个页面。例如,如果我们请求一个叫做SomePage.aspx的页面,在WEB服务器上就会有一个叫做SomePage.aspx的页面。如果没有的话,会得到一个错误。
从技术角度说,ASP.NET页面代表一个类,并且不是普通类。ASP.NET页面是一个Handler。换句话说,ASP.NET页面实现了 IhttpHandler接口并且有一个ProcessRequest()方法用于在请求页面的时候接受请求。ProcessRequest()方法负责 生成内容并把它发回浏览器。
因此,普通ASP.NET应用程序的工作方式佷简单明了。我们请求页面,页面请求对应磁盘上的某个页面,这个页面执行ProcessRequest()方法并把内容发回浏览器。
ASP.NET MVC应用程序不是以这种方式工作的。当我们请求一个ASP.NET MVC应用程序的页面时,在磁盘上不存在对应请求的页面。而是,请求被路由转到一个叫做控制器的类上。控制器负责生成内容并把它发回浏览器。
当我们写普通ASP.NET应用程序的时候,会创建很多页面。在URL和页面之间总是一一对应进行映射。每一个页面请求对应相应的页面。
相反,当我们创建ASP.NET MVC应用程序的时候,创建的是一批控制器。使用控制器的优势是可以在URL和页面之间可以有多对一的映射。例如,所有如下的URL都可以映射到相同的控制器上。
http://MySite/Products/1
http://MySite/Products/2
http://MySite/Products/3
这些URL映射到一个控制器上,通过从URL中提取产品ID来显示正确的产品。这种控制器方式比传统的ASP.NET方式更灵活。控制器方式可以产品更显而易见的URL。
那么,某个页面请求是怎么路由到某个控制器上的呢?ASP.NET MVC应用程序有一个叫做路由表(Route Table)的东西。路由表映射某个URL到某个控制器上。
一个应用程序有一个并且只会有一个路由表。路由表在Global.asax文件中创建。清单1包含了在使用Visual Studio新建ASP.NET MVC Web应用程序时默认的Global.asax文件。
清单 1 – Global.asax
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace TestMVCArch
{
public class GlobalApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
// Note: Change the URL to “{controller}.mvc/{action}/{id}” to enable
// automatic support on IIS6 and IIS7 classic mode
routes.Add(new Route(“{controller}/{action}/{id}”, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { action = “Index”, id = “” }),
});
routes.Add(new Route(“Default.aspx”, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = “Home”, action = “Index”, id = “” }),
});
}
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
}
}
应用程序的路由表由RouteTable.Routes的静态属性表示。这个属性表示了路由对象的集合。在清单1列出的Global.asax文件中,我 们在应用程序首次启动时为路由表增加两个路由对象(Application_Start()方法在第一次请求网站页面的时候被调用一次)。
路由对象负责把URL映射到Handler。在清单1中,我们创建了两个路由对象。这2个对象都把URL映射到MvcRouteHandler。第一个路 由映射任何符合{controller}/{action}/{id}模式的URL到MvcRouteHandler。第二个路由映射某个URL Default.aspx到MvcRouteHandler。
顺便说一下,这种新的路由构架可以脱离ASP.NET MVC独立使用。Global.asax文件映射URL到MvcRouteHandler。然而,我们可以选择把URL路由到不同类型的Handler 上。这里说的路由构架包含在一个叫做System.Web.Routing.dll的独立程序集中。我们可以脱离MVC使用路由。
步骤2:UrlRoutingModule拦截请求
当我们对ASP.NET MVC应用程序发起请求的时候,请求会被UrlRoutingModule HTTP Module拦截。HTTP Module是特殊类型的类,它参与每一次页面请求。例如,传统ASP.NET包含了FormsAuthenticationModule HTTP Module用来使用表单验证实现页面访问安全性。
UrlRoutingModule拦截请求后做的第一件事情就是包装当前的HttpContext为HttpContextWrapper2对象。 HttpContextWrapper2类和派生自HttpContextBase的普通HttpContext类不同。创建的HttpContext的 包装可以使使用诸如Typemock Isolator或Rhino Mocks的Mock对象框进行模拟变得更简单。

接着,Module把包装后的HttpContext传给在之前步骤中创建的RouteTable。HttpContext包含了URL、表单参数、查询 字符串参数以及和当前请求关联的cookie。如果在当前请求和路由表中的路由对象之间能找到匹配,就会返回路由对象。
如果UrlRoutingModule成功获取了RouteData对象,Module然后就会创建表示当前HttpContext和 RouteData的RouteContext对象。Module然后实例化基于RouteTable的新HttpHandler,并且把 RouteContext传给Handler的构造函数。
对于ASP.NET MVC应用程序,从RouteTable返回的Handler总是MvcHandler(MvcRouteHandler返回MvcHandler)。只 要UrlRoutingModule匹配当前请求到路由表中的路由,就会实例化带有当前RouteContext的MvcHandler。
Module进行的最后一步就是把MvcHandler设置为当前的HTPP Handler。ASP.NET应用程序自动调用当前HTTP Handler的ProcessRequest()方法然后转入下一步。
步骤3:执行MvcHandler
在之前的步骤中,表示某个RouteContext的MvcHandler被设置作为当前的HTTP Handler。ASP.NET应用程总是会发起一系列的事件,包括Star、BeginRequest、 PostResolveRequestCache、 PostMapRequestHandler、PreRequestHandlerExecute和EndRequest事件(非常多的应用程序事件—— 对于完整列表,请查阅Visual Studio 2008文档中的HttpApplication类)。
之前内容中描述的所有东西都在PostResolveRequestCache和PostMapRequestHandler中发生。当前HTTP Handler的ProcessRequest()方法在PreRequestHandlerExecute事件之后被调用。
当之前内容中创建的MvcHandler对象的ProcessRequest()被调用的时候,会创建一个新的控制器。控制器由 ControllerFactory创建。由于我们可以创建自己的ControllerFactory,所以这又是一个可扩展点。默认的 ControllerFactory名字相当合适,叫做DefaultControllerFactory。
RequestContext以及控制器的名字被传入ControllerFactory.CreateController()方法来获得一个控制器。 然后,从RequestContext和控制器构造ControllerContext对象。最后,调用控制器类的Execute()方法。在调用 Execute()方法的时候会给方法传入ControllerContext。
步骤4:执行控制器
Execute()方法首先创建TempData对象(在Ruby On Rails中叫做Flash对象)。TempData可以用于保存下次请求必须的临时数据(TempData和会话状态差不多,不长期占用内存)。
接着,Execute()方法构建请求的参数列表。这些参数从请求参数中提取,将会被作为方法的参数。参数会被传入执行的控制器方法。
Execute()通过对控制器类进行反射来找到控制器的方法。控制器类是我们写的。Execute()方法找到了我们控制器类中的方法后就执行它。Execute()方法不会执行被装饰NonAction特性的方法。
至此,就进入了自己应用程序的代码。
步骤5:调用RenderView方法
通常,我们的控制器方法最后会调用RenderView()或RedirectToAction()方法。RenderView()方法负责把视图(页面)呈现给浏览器。
当我们调用控制器RenderView()方法的时候,调用会委托给当前ViewEngine的RenderView()方法。 ViewEngine是另外一个扩展点。默认的ViewEngine是WebFormViewEngine。然而,我们可以使用诸如Nhaml的其它 ViewEngine。
WebForm的ViewEngine.RenderView()方法创建了一个叫做ViewLocator的类来寻找视图。然后,它使用 BuildManager来创建ViewPage类的实例。然后,如果页面有ViewData就会设置ViewData。最后,ViewPage 的RenderView()方法被调用。
ViewPage类从System.Web.UI.Page基类(和用于传统ASP.NET的页面一样)派生。RenderView()方法做的最后一个 工作就是调用页面类的ProcessRequest()。调用视图的ProcessRequest()生成内容的方式和普通ASP.NET页面生成内容的 方式一致。
可扩展点
ASP.NET MVC生命周期在设计的时候包含了很多可扩展点。我们可以自定义通过插入自定义类或覆盖既有类来自定义框架的行为。下面是这些扩展点的概要:
路由对象:当我们创建路由表的时候,调用RouteCollection.Add()方法来增加新的路由对象。Add()方法接受了RouteBase对象。我们可以通过派生RouteBase基类来实现自己的路由对象。
MvcRouteHandler :当创建MVC应用程序的时候,我们把URL映射到MvcRouteHandler对象上。然而,我们可以把URL映射到实现IRouteHandler 接口的任何类上。路由类的构造函数接受任何实现IRouteHandler接口的对象。
MvcRouteHandler.GetHttpHandler() : MvcRouteHandler 类的GetHttpHandler()方法是virtual方法。默认情况下,MvcRouteHandler返回MvcHandler。如果愿意的话, 我们可以覆盖GetHttpHandler()方法来返回不同的Handler。
ControllerFactory :我们可以通过System.Web.MVC.ControllerBuilder.Current.SetControllerFactory()方法 指定一个自定义类来创建自定义的控制器工厂。控制器工厂负责为某个控制器名和RequestContext返回控制器。
控制器:我们可以通过实现Icontroller接口来实现自定义控制器。这个接口只有一个Execute(ControllerContext controllerContext)方法。
ViewEngine:我们可以为控制器指定自定义的ViewEngine。通过为公共的 Controller.ViewEngine属性指定ViewEngine来把ViewEngine指定给控制器。ViewEngine必须实现 IviewEngine接口,接口只有一个方法:RenderView(ViewContext viewContext)。
ViewLocator :ViewLocator把视图名映射到实际视图文件上。我们可以通过WebFormViewEngine.ViewLocator的属性来执行自定义的ViewLocator。

[转载]Android平台下实现一个进程管理器

2011-04-29mikel阅读(881)

[转载]Android平台下实现一个进程管理器 – 疯狂の小石子 – 博客园.

在本人的博客文章《枚举Android系统的进程、任务和服务的息》http://www.cnblogs.com/crazypebble/archive/2011/03/29/1999151.html中, 实现了一个简单的监控Android平台下的系统进程,任务,服务信息的小工具。在本文中,我将对这个小工具中的系统进程信息部分,进一步的完善。从用户 的角度出发,将系统的任务信息Task和服务信息Service全部显示出来的意义不是很大,因此本文将不会对任务和服务两部分内容对任何更新。
介绍之前,先给大家看看程序执行后的界面,首先了解大致的功能,然后理解起来,会更加得心应手。
1、  获取系统进程列表,并加载进程名、CPU占用情况、内存使用情况


2、  点击某一个进程之后,让用户选择操作:“查看详情”和“结束进程”


3、  显示进程的详细信息:包括了进程的安装包路径、版权信息、用户权限、拥有的服务、和拥有的活动,等


4、  程序退出的方式


5、  任务列表 和 服务列表


在对界面和主要功能有一个大致了解之后,我们就开始编写我们的代码了。
一、界面布局
本文对整个功能界面采用了选项卡式的布局,布局文件如下:

<!--?xml version="1.0" encoding="utf-8"?-->

每一个选项卡的内容都是一个列表ListView,分别用于显示系统的进程、任务和服务列表,布局文件我们就此略过了。

在进程的详情中,我们使用不同背景色的TextView作为一个数据部分的标题,这样给人视觉上一个比较清晰的层次感,代码如下:

整个详情信息是一个ScrollView,在第一行中嵌入了一个Button,其他行的数据显示都比较简单,大家看看我的控件ID就差不多知道这个控件的意思了。

<!--?xml version="1.0" encoding="utf-8"?-->

<button></button>

二、获取进程的图标、进程名、Application名字、和CPU内存信息

我在程序中使用了一个类BasicProgramUtil来存放进程列表中显示的摘要信息,包括了进程图标、进程名、Application名、CPU和内存信息。

/**
* 应用程序包的简要信息
*/
package crazypebble.sysassist.procmgr;

import android.graphics.drawable.Drawable;

public class BasicProgramUtil{

/*
* 定义应用程序的简要信息部分
*/
private Drawable icon; // 程序图标
private String programName; // 程序名称
private String processName;

private String cpuMemString;

public BasicProgramUtil() {
icon = null;
programName = "";
processName = "";
cpuMemString = "";
}

public Drawable getIcon() {
return icon;
}

public void setIcon(Drawable icon) {
this.icon = icon;
}

public String getProgramName() {
return programName;
}

public void setProgramName(String programName) {
this.programName = programName;
}

public String getCpuMemString() {
return cpuMemString;
}

public void setCpuMemString(String cpuMemString) {
this.cpuMemString = cpuMemString;
}

public String getProcessName() {
return processName;
}

public void setProcessName(String processName) {
this.processName = processName;
}
}

1、进程图标

每一个进程,都属于一个应用程序,每个应用程序都有一个图标信息。我们通过 ApplicationInfo.loadIcon(PackageManager)方法返回一个Drawable对象实例,可以获取到一个应用程序的图 标,这里我们直接作为进程的图标进行显示。

2、进程名和Application名字


首先要弄清进程名和Application名字的区别。在Android平台 下,一个进程的进程名实际上以“.”作为分隔符的,类似包名的字符串,这个字符串并不能被普通用户所理解。而Application名字,就是我们刚开始 新建工程时,填入Application部分的内容,是可以被用户接受的应用程序的名字。


由于Application Name更容易被用户接受和读懂,因此我们将Application Name作为进程信息的主显部分。

通过ActivityManager.getRunningAppProcesses()方法可以得到当前正在运行的所有进程列表,该方法返回一个 List<RunningAppProcessInfo>,在RunningAppProcessInfo对象中存放有进程名信息;再通过进 程名获取到ApplicationInfo,通过方法 ApplicationInfo.loadLabel(PackageManager).toString()就返回了应用程序的名字。

3、CPU和内存信息

获取每个进程的CPU和内存信息,可能就没有API函数给我们使用了。我们需要通过执行adb shell指令,进入shell命令模式,执行命令”top –n 1”来获取所有进程运行状态的列表。

Android平台下的很多系统信息可能是无法通过API函数获取到的,这时通过执行shell命令,并解析输出结果。相关链接:《Android的CPU、硬盘、内存、网络设置、系统信息、硬件信息》(http://www.cnblogs.com/crazypebble/archive/2011/04/07/2007916.html)

先来看看top –n 1(这个地方不是字母L,是数字1,请各位小心)命令执行的结果吧。


第一行:CPU的总的使用情况

第二行:总内存的使用情况

从第三行开始,就是每个进程所占用内存和CPU的情况

PID:进程ID,CPU%:CPU占用比例,#THR:进程的线程数,VSS:虚拟内存,RSS:物理内存,PCY:浮云,我也不知道什么意思,UID:用户ID,Name:进程名

了解了上面这些信息之后,想必大家也知道怎么获取这个进程的CPU和内存信息了。要是大家有兴趣,还是好好看看《Android的CPU、硬盘、内存、网络设置、系统信息、硬件信息》,相信这个文章对大家有有用的。

好了,这一部分的功能就做好了,接下来编码了,这里放出主要的代码,其他的代码,希望同学们自己去完善了。

/**
* PackageUtils 用于某进程的ApplicationInfo对象,目的为了获取图标和应用程序名称
*/
package crazypebble.sysassist.procmgr;

import java.util.List;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;

public class PackageUtil {
// ApplicationInfo 类,保存了普通应用程序的信息,主要是指Manifest.xml中application标签中的信息
private List allAppList;

public PackageUtil(Context context) {
// 通过包管理器,检索所有的应用程序(包括卸载)与数据目录
PackageManager pm = context.getApplicationContext().getPackageManager();
allAppList = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
pm.getInstalledPackages(0);
}

/**
* 通过一个程序名返回该程序的一个ApplicationInfo对象
* @param name 程序名
* @return ApplicationInfo
*/
public ApplicationInfo getApplicationInfo(String appName) {
if (appName == null) {
return null;
}

for (ApplicationInfo appinfo : allAppList) {
if (appName.equals(appinfo.processName)) {
return appinfo;
}
}
return null;
}
}

/**
* 获取某进程的CPU和内存使用情况
*/
package crazypebble.sysassist.procmgr;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import android.util.Log;
import crazypebble.sysassist.common.CMDExecute;

public class ProcessMemoryUtil {

private static final int INDEX_FIRST = -1;
private static final int INDEX_PID = INDEX_FIRST + 1;
private static final int INDEX_CPU = INDEX_FIRST + 2;
private static final int INDEX_STAT = INDEX_FIRST + 3;
private static final int INDEX_THR = INDEX_FIRST + 4;
private static final int INDEX_VSS = INDEX_FIRST + 5;
private static final int INDEX_RSS = INDEX_FIRST + 6;
private static final int INDEX_PCY = INDEX_FIRST + 7;
private static final int INDEX_UID = INDEX_FIRST + 8;
private static final int INDEX_NAME = INDEX_FIRST + 9;
private static final int Length_ProcStat = 9;

private List PMUList = null;

public ProcessMemoryUtil() {

}

private String getProcessRunningInfo() {
Log.i("fetch_process_info", "start. . . . ");
String result = null;
CMDExecute cmdexe = new CMDExecute();
try {
String[] args = {"/system/bin/top", "-n", "1"};
result = cmdexe.run(args, "/system/bin/");
} catch (IOException ex) {
Log.i("fetch_process_info", "ex=" + ex.toString());
}
return result;
}

private int parseProcessRunningInfo(String infoString) {
String tempString = "";
boolean bIsProcInfo = false;

String[] rows = null;
String[] columns = null;
rows = infoString.split("[\n]+"); // 使用正则表达式分割字符串

for (int i = 0; i &lt; rows.length; i++) {
tempString = rows[i];
if (tempString.indexOf("PID") == -1) {
if (bIsProcInfo == true) {
tempString = tempString.trim();
columns = tempString.split("[ ]+");
if (columns.length == Length_ProcStat) {
PMUList.add(columns);
}
}
} else {
bIsProcInfo = true;
}
}

return PMUList.size();
}

// 初始化所有进程的CPU和内存列表,用于检索每个进程的信息
public void initPMUtil() {
PMUList = new ArrayList();
String resultString = getProcessRunningInfo();
parseProcessRunningInfo(resultString);
}

// 根据进程名获取CPU和内存信息
public String getMemInfoByName(String procName) {
String result = "";

String tempString = "";
for (Iterator iterator = PMUList.iterator(); iterator.hasNext();) {
String[] item = (String[]) iterator.next();
tempString = item[INDEX_NAME];
if (tempString != null &amp;&amp; tempString.equals(procName)) {
result = "CPU:" + item[INDEX_CPU]
+ " Mem:" + item[INDEX_RSS];
break;
}
}
return result;
}

// 根据进程ID获取CPU和内存信息
public String getMemInfoByPid(int pid) {
String result = "";

String tempPidString = "";
int tempPid = 0;
int count = PMUList.size();
for (int i = 0; i &lt; count; i++) { String[] item = PMUList.get(i); tempPidString = item[INDEX_PID]; if (tempPidString == null) { continue; } tempPid = Integer.parseInt(tempPidString); if (tempPid == pid) { result = "CPU:" + item[INDEX_CPU] + " Mem:" + item[INDEX_RSS]; break; } } return result; } } 
 /* * 为进程获取基本的信息 */ public BasicProgramUtil buildProgramUtilSimpleInfo(int procId, String procNameString) { BasicProgramUtil programUtil = new BasicProgramUtil(); programUtil.setProcessName(procNameString); // 根据进程名,获取应用程序的ApplicationInfo对象 ApplicationInfo tempAppInfo = packageUtil.getApplicationInfo(procNameString); if (tempAppInfo != null) { // 为进程加载图标和程序名称 programUtil.setIcon(tempAppInfo.loadIcon(packageManager)); programUtil.setProgramName(tempAppInfo.loadLabel(packageManager).toString()); } else { // 如果获取失败,则使用默认的图标和程序名 programUtil.setIcon(getApplicationContext().getResources().getDrawable(R.drawable.unknown)); programUtil.setProgramName(procNameString); Log.v(ProcMgrActivity.TAG_SYSTEMASSIST, procNameString); } String str = processMemoryUtil.getMemInfoByPid(procId); Log.v(TAG_SYSTEMASSIST, "Time --- &gt; " + Calendar.getInstance().getTimeInMillis());
programUtil.setCpuMemString(str);
return programUtil;
}

三、获取进程的详细信息

我将进程的详细信息封装在一个类DetailProgramUtil中,主要 包括了进程ID,进程名,版权信息、程序的安装目录和数据目录,安装时间和更新时间、应用程序的权限、应用程序包含的活动Activity、应用程序包含 的服务Service、和安装包的大小信息。


/**
* 应用程序包的详细信息
*/
package crazypebble.sysassist.procmgr;

import java.io.Serializable;
import java.text.DecimalFormat;

import android.content.pm.ActivityInfo;
import android.content.pm.ServiceInfo;
import android.text.format.DateFormat;

public class DetailProgramUtil implements Serializable{

private static final long serialVersionUID = 1L;
/*
* 定义应用程序的扩展信息部分
*/
private int pid;
private String processName; // 程序运行的进程名

private String companyName; // 公司名称
private int versionCode; // 版本代号
private String versionName; // 版本名称

private String dataDir; // 程序的数据目录
private String sourceDir; // 程序包的源目录

private String firstInstallTime; // 第一次安装的时间
private String lastUpdateTime; // 最近的更新时间

private String userPermissions; // 应用程序的权限
private String activities; // 应用程序包含的Activities
private String services; // 应用程序包含的服务

// android.content.pm.PackageState类的包信息
// 此处只是安装包的信息
private String codeSize;
private long dataSize;
private long cacheSize;
private long externalDataSize;
private long externalCacheSize;
private long externalMediaSize;
private long externalObbSize;

public DetailProgramUtil() {
pid = 0;
processName = "";
companyName = "";
versionCode = 0;
versionName = "";
dataDir = "";
sourceDir = "";
firstInstallTime = "";
lastUpdateTime = "";
userPermissions = "";
activities = "";
services = "";

initPackageSize();
}

private void initPackageSize() {
codeSize = "0.00";
dataSize = 0;
cacheSize = 0;
externalCacheSize = 0;
externalDataSize = 0;
externalMediaSize = 0;
externalObbSize = 0;
}

public int getPid() {
return pid;
}

public void setPid(int pid) {
this.pid = pid;
}

public int getVersionCode() {
return versionCode;
}

public void setVersionCode(int versionCode) {
this.versionCode = versionCode;
}

public String getVersionName() {
return versionName;
}

public void setVersionName(String versionName) {
this.versionName = versionName;
}

public String getCompanyName() {
return companyName;
}

public void setCompanyName(String companyString) {
this.companyName = companyString;
}

public String getFirstInstallTime() {
if (firstInstallTime == null || firstInstallTime.length() &lt;= 0) {
firstInstallTime = "null";
}
return firstInstallTime;
}

public void setFirstInstallTime(long firstInstallTime) {
this.firstInstallTime = DateFormat.format(
"yyyy-MM-dd", firstInstallTime).toString();
}

public String getLastUpdateTime() {
if (lastUpdateTime == null || lastUpdateTime.length() &lt;= 0) {
lastUpdateTime = "null";
}
return lastUpdateTime;
}

public void setLastUpdateTime(long lastUpdateTime) {
this.lastUpdateTime = DateFormat.format(
"yyyy-MM-dd", lastUpdateTime).toString();
}

public String getActivities() {
if (activities == null || activities.length() &lt;= 0) {
activities = "null";
}
return activities;
}

public void setActivities(ActivityInfo[] activities) {
this.activities = Array2String(activities);
}

public String getUserPermissions() {
if (userPermissions == null || userPermissions.length() &lt;= 0) {
userPermissions = "null";
}
return userPermissions;
}

public void setUserPermissions(String[] userPermissions) {
this.userPermissions = Array2String(userPermissions);
}

public String getServices() {
if (services == null || services.length() &lt;= 0) {
services = "null";
}
return services;
}

public void setServices(ServiceInfo[] services) {
this.services = Array2String(services);
}

public String getProcessName() {
if (processName == null || processName.length() &lt;= 0) {
processName = "null";
}
return processName;
}

public void setProcessName(String processName) {
this.processName = processName;
}

public String getDataDir() {
if (dataDir == null || dataDir.length() &lt;= 0) {
dataDir = "null";
}
return dataDir;
}

public void setDataDir(String dataDir) {
this.dataDir = dataDir;
}

public String getSourceDir() {
if (sourceDir == null || sourceDir.length() &lt;= 0) { sourceDir = "null"; } return sourceDir; } public void setSourceDir(String sourceDir) { this.sourceDir = sourceDir; } /* * 三个重载方法,参数不同,调用不同的方法,用于将object数组转化成要求的字符串 */ // 用户权限信息 public String Array2String(String[] array) { String resultString = ""; if (array != null &amp;&amp; array.length &gt; 0) {
resultString = "";
for (int i = 0; i &lt; array.length; i++) {
resultString += array[i];
if (i &lt; (array.length - 1)) { resultString += "\n"; } } } return resultString; } // 服务信息 public String Array2String(ServiceInfo[] array) { String resultString = ""; if (array != null &amp;&amp; array.length &gt; 0) {
resultString = "";
for (int i = 0; i &lt; array.length; i++) {
if (array[i].name == null) {
continue;
}
resultString += array[i].name.toString();
if (i &lt; (array.length - 1)) { resultString += "\n"; } } } return resultString; } // 活动信息 public String Array2String(ActivityInfo[] array) { String resultString = ""; if (array != null &amp;&amp; array.length &gt; 0) {
resultString = "";
for (int i = 0; i &lt; array.length; i++) {
if (array[i].name == null) {
continue;
}
resultString += array[i].name.toString();
if (i &lt; (array.length - 1)) {
resultString += "\n";
}
}
}
return resultString;
}

public String getCodeSize() {
return codeSize;
}

public void setCodeSize(long codeSize) {
DecimalFormat df = new DecimalFormat("###.00");
this.codeSize = df.format((double)(codeSize/1024.0));
}

public long getDataSize() {
return dataSize;
}

public void setDataSize(long dataSize) {
this.dataSize = dataSize;
}

public long getCacheSize() {
return cacheSize;
}

public void setCacheSize(long cacheSize) {
this.cacheSize = cacheSize;
}

public long getExternalDataSize() {
return externalDataSize;
}

public void setExternalDataSize(long externalDataSize) {
this.externalDataSize = externalDataSize;
}

public long getExternalCacheSize() {
return externalCacheSize;
}

public void setExternalCacheSize(long externalCacheSize) {
this.externalCacheSize = externalCacheSize;
}

public long getExternalMediaSize() {
return externalMediaSize;
}

public void setExternalMediaSize(long externalMediaSize) {
this.externalMediaSize = externalMediaSize;
}

public long getExternalObbSize() {
return externalObbSize;
}

public void setExternalObbSize(long externalObbSize) {
this.externalObbSize = externalObbSize;
}

public String getPackageSize() {
String resultString = "";
resultString = "Code Size: " + codeSize + "KB\n"
+ "Data Size: " + dataSize + "KB\n"
+ "Cache Size: " + cacheSize + "KB\n"
+ "External Data Size: " + externalDataSize + "KB\n"
+ "External Cache Size: " + externalCacheSize + "KB\n"
+ "External Media Size: " + externalMediaSize + "KB\n"
+ "External Obb Size: " + externalObbSize + "KB";
return resultString;
}
}

目录信息:通过进程的ApplicationInfo对象获取,获取进程ApplicationInfo的方法在类PackageUtil.java中。

版权信息、权限、活动、服务信息:通过PackageInfo对象获取,获取进程PackageInfo的方法:PackageManager.getPackageInfo(packageName, flags)。这个方法需要一定flags信息,我在代码中已经用注释写明了所需要的flags,请各位还是查阅一下SDK的开发文档,里面会有更详细的解释。

方法buildProgramUtilComplexInfo用于为需要查看详情的进程生成一个DetailProgramUtil对象,通过Bundle.putSerializable(key, (Serializable)DetaiProgramUtil),将这个对象传递给另一个活动进行显示。所以在上面DetailProgramUtil.java文件的一开始,该类实现了Serializable的接口。


/*
* 为进程获取安装包的详情
*/
public DetailProgramUtil buildProgramUtilComplexInfo(String procNameString) {

DetailProgramUtil complexProgramUtil = new DetailProgramUtil();
// 根据进程名,获取应用程序的ApplicationInfo对象
ApplicationInfo tempAppInfo = packageUtil.getApplicationInfo(procNameString);
if (tempAppInfo == null) {
return null;
}

PackageInfo tempPkgInfo = null;
try {
tempPkgInfo = packageManager.getPackageInfo(
tempAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_ACTIVITIES
| PackageManager.GET_SERVICES | PackageManager.GET_PERMISSIONS);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
if (tempPkgInfo == null) {
return null;
}

complexProgramUtil.setProcessName(procNameString);
complexProgramUtil.setCompanyName(getString(R.string.no_use));
complexProgramUtil.setVersionName(tempPkgInfo.versionName);
complexProgramUtil.setVersionCode(tempPkgInfo.versionCode);
complexProgramUtil.setDataDir(tempAppInfo.dataDir);
complexProgramUtil.setSourceDir(tempAppInfo.sourceDir);

// 以下注释部分的信息暂时获取不到
// complexProgramUtil.setFirstInstallTime(tempPkgInfo.firstInstallTime);
// complexProgramUtil.setLastUpdateTime(tempPkgInfo.lastUpdateTime);

// complexProgramUtil.setCodeSize(packageStats.codeSize);
// complexProgramUtil.setDataSize(packageStats.dataSize);
// complexProgramUtil.setCacheSize(packageStats.cacheSize);
// complexProgramUtil.setExternalDataSize(0);
// complexProgramUtil.setExternalCacheSize(0);
// complexProgramUtil.setExternalMediaSize(0);
// complexProgramUtil.setExternalObbSize(0);

// 获取以下三个信息,需要为PackageManager进行授权(packageManager.getPackageInfo()方法)
complexProgramUtil.setUserPermissions(tempPkgInfo.requestedPermissions);
complexProgramUtil.setServices(tempPkgInfo.services);
complexProgramUtil.setActivities(tempPkgInfo.activities);

return complexProgramUtil;
}

四、实现进程列表的刷新

进程列表的刷新是一个比较费时的操作,我们将其放在一个独立的线程中执行,并且在刷新过程进行时使用一个ProgressDialog进度对话框覆盖住主视图,等待刷新完成后再返回到主视图。

这一部分使用到了Handler类和线程的相关知识,各位可以参考文章《在Android中使用Handler和Thread线程执行后台操作》。这些不做过多解释,直接上代码,相信大家都能够懂的。


private void updateProcessList() {
// 新建一个进度对话框,在更新列表时,覆盖在父视图之上
pd = new ProgressDialog(ProcMgrActivity.this);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setTitle(getString(R.string.progress_tips_title));
pd.setMessage(getString(R.string.progress_tips_content));

// 启动新线程,执行更新列表操作
handler = new RefreshHandler();
RefreshThread thread = new RefreshThread();
thread.start();

// 显示进度对话框
pd.show();
}

private class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// TODO : Update your UI
getListView().setAdapter(procListAdapter);
// 取消进度框
pd.dismiss();
}
}

class RefreshThread extends Thread {
@Override
public void run() {
// TODO : Do your Stuff here.
procListAdapter = buildProcListAdapter();
Message msg = handler.obtainMessage();
handler.sendMessage(msg);
}
}

五、结束其他进程和退出本程序

这一部分的内容,也已经在我的博客中写了一篇文章《Android下结束进程的方法》,我们在这个任务管理器中使用到的“退出”按钮的实现,强制结束其他进程的方法,都是来自这篇文章。为了方便那些不想点击链接的同学们,我们还是再贴一下代码吧。

退出本程序,主要是通过方法returnToHome方法,该方法将直接退出到主屏幕,请清除当前的活动:


private void returnToHome() {
Intent home = new Intent(Intent.ACTION_MAIN);
home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
home.addCategory(Intent.CATEGORY_HOME);
startActivity(home);
}

结束其他进程,主要是通过ActivityManager.killBackgroundProcesses(PackageName)方法来实现,还是强烈建议各位看看SDK的开发文档,或者上面的那篇文章。

六、任务列表和服务列表

任务列表和服务列表的信息获取,已经在之前的一篇博客中讲到了,这些再不厌其烦的介绍一下方法,至于原理部分,请各位去看看开发文档吧。

1、任务列表

任务列表功能所显示的全部信息都来自一个类RunningTaskInfo。

ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);

taskList = activityManager.getRunningTasks(maxTaskNum);

2、服务列表

服务列表功能所显示的全部信息都来自一个类RunningServiceInfo。

ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);

serviceList = activityManager.getRunningServices(maxServiceNum);

好了,这个任务管理到这里就告一段落了。这个程序算是本人自学习Android开发以来的处女作,完全是自己动手开发的一个小工具,写下总结,以留作纪 念,也希望可以与更多的同道中人交流技术。如果在文章中,有错误之处,还希望各位可以批评指正,本人一定悉心接受,轻点砸砖~。

===============================优雅的分割线===============================

【声明】本文系本人原创,转载请注明文章出处:http://www.cnblogs.com/crazypebble/archive/2011/04/09/2010196.html

[转载]Android应用开发框架结构

2011-04-29mikel阅读(827)

[转载]Android应用开发框架结构 – bitfairyland – 博客园.

1.Android的应用开发与传统的Win32应用开发的区别
1)Android是一种松散的逻辑对象体
(Win32应用)
(Android应用)
P1-P2-P3B2;P1-P2-P3-B3;P1-P2-P3-B2-B3;B1-V1;B1-V2…等等组新的应用集合,应用之间的逻辑讲究的是复用,是一个松散的集合,Android讲究的是这种散的概念。
2)Android是事务先于实体而存在的,传统的Win32是一个实体逻辑通过消息组成事务,就存在实体可以做什么通过win平台消息告诉对方做什么。而Android的平台是告诉平台我想做什么,平台才去找对应的Activity,而并不一定能找到对应的逻辑体。
2.Android的应用开发主要包括四个部分
  • Activity
  • Intent
  • Service
  • Content Provier
1)Activity
Activity构成Android应用的基本单元,就是一个逻辑单元,也就是一个对象,或者说是一个类,处理一部分工作逻辑。主要完成2部分工作,接收平台传过来的消息或发生到平台消息消息,然后画图,得到给用户提供的交换界面,也就是形成所谓的手机窗体。
An Activity is an application component that provides a screen with which users can interact in order to do something, such as dial the phone, take a photo, send an email, or view a map. Each activity is given a window in which to draw its user interface. The window typically fills the screen, but may be smaller than the screen and float on top of other windows.(官方文档的定义)
2)Intent
Intent是Android应用平台的消息体,负责携带命令和数据传给新的Activity。
intent receiver是在AndroidManifest.xml注册的过滤器,启到广播给其它Activity的作用。
Three of the core components of an application — activities, services, and broadcast receivers — are activated through messages, called intents. Intent messaging is a facility for late run-time binding between components in the same or different applications. The intent itself, an Intent object, is a passive data structure holding an abstract description of an operation to be performed — or, often in the case of broadcasts, a description of something that has happened and is being announced. There are separate mechanisms for delivering intents to each type of component:(官方文档的定义)
3)Service
Service是跑在Android平台的服务,提供类似于系统提醒消息的等

A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.

A service can essentially take two forms:

Started
A service is “started” when an application component (such as an activity) starts it by calling startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed. Usually, a started service performs a single operation and does not return a result to the caller. For example, it might download or upload a file over the network. When the operation is done, the service should stop itself.
Bound
A service is “bound” when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.
(官方文档的定义)
4)Content Provider
Content Provider是Android平台提供的一个数据共享的中间层
Content providers store and retrieve data and make it accessible to all applications. They’re the only way to share data across applications; there’s no common storage area that all Android packages can access(官方文档定义)

[转载]C#操作Sqlite快速入门及相关工具收集

2011-04-28mikel阅读(1048)

[转载]C#操作Sqlite快速入门及相关工具收集 – 大气象学习园地 – 博客园.

SQLite不需要安装即可使用。Access还需要安装Office组件。
SQLite是不是那个System.Data.SQLite.DLL临时创建了数据库引擎?

1.新建一个WinForm项目,引用System.Data.SQLite.DLL.界面如下

1.1  SQLiteConnection.CreateFile(“D:/Data.db3”);
这样就可以创建一个数据库文件,名称随意。
封装成一个函数

//创建一个数据库文件,保存在当前目录下HyData文件夹下
//CreateDB("HyData.db3");
private void CreateDB(string dbName)
{
string databaseFileName = System.Environment.CurrentDirectory + @"/HyData/" + dbName;

SQLiteConnection.CreateFile(databaseFileName);
}

1.2  数据库连接字符串

string connStr = @"Data Source=" + System.Environment.CurrentDirectory + @"\HyData\HyData.db3;Initial Catalog=sqlite;Integrated Security=True;Max Pool Size=10";

这里新建了一个HyData目录存放数据库。

1.3  执行Sql语句

//执行Sql语句
//创建一个表:  ExecuteSql("create table HyTest(TestID TEXT)");
//插入些数据:  ExecuteSql("insert into HyTest(TestID) values('1001')");
private void ExecuteSql(string sqlStr)
{
using (DbConnection conn = new SQLiteConnection(connStr))
{
conn.Open();
DbCommand comm = conn.CreateCommand();
comm.CommandText = sqlStr;
comm.CommandType = CommandType.Text;
comm.ExecuteNonQuery();
}
}

执行查询语句

//执行查询
//ExecQuery("select * from HyTest");
private void ExecQuery(string sqlStr)
{
using (DbConnection conn = new SQLiteConnection(connStr))
{
conn.Open();
DbCommand comm = conn.CreateCommand();
comm.CommandText = sqlStr;
comm.CommandType = CommandType.Text;

using (IDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
MessageBox.Show(reader[0].ToString());
}
}
}
}

//执行查询返回DataSet
private DataSet ExecDataSet(string sqlStr)
{
using (SQLiteConnection conn = new SQLiteConnection(connStr))
{
conn.Open();
SQLiteCommand cmd = conn.CreateCommand();
cmd.CommandText = sqlStr;
cmd.CommandType = CommandType.Text;

SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);

return ds;
}
}

本文示例项目源码:HySqlite.rar http://revit.5d6d.com/thread-799-1-1.html

2.Sqlite相关工具

2.1 Sqlite数据库可以到www.sqlite.org下载,非常小
或sqlite-shell-win32-x86-3070600.zip
http://revit.5d6d.com/thread-800-1-1.html

2.2 C#操作Sqlite的官方示例代码,一时忘了url
或http://revit.5d6d.com/thread-801-1-1.html包括
SQLite-1.0.66.0-source.zip
SQLite-1.0.66.0-binaries.zip
Debug.rar

2.3 Sqlite两个界面工具

SQLiteExpertSetup.exe
http://revit.5d6d.com/thread-802-1-1.html这个比较好用,破解版
SQLite Database Browser.exe
http://revit.5d6d.com/thread-803-1-1.html这个据说用在手机上

[转载]InstallShield 部署安装包整理(1)

2011-04-28mikel阅读(1146)

[转载]InstallShield 部署安装包整理(1) – zhaodyun – 博客园.

InStallShield界面简单认识

一.安装助手(InstallShield Assistant)

1>Application Information:设置安装包的一些信息,如公司名称,安装包版本号,公司网址

2>Installatin Architecture:设置安装包的主体结构,一般用来设置安装包中有多少个安装项目

3>Application Files:指定安装路径与所需要的安装文件夹

4>Application Redistributables:用于添加第三方组件

5>Application Shortcuts:创建程序启动的快捷方式,

6>Application Registry:添加对注册表的操作

7>Installation Interview:一些简单的对话框选择操作

8>Installation Localization:安装包界面语言的选择

9>Build Installation:选择安装包的格式并编译安装包

通过安装助手都可以制作一般的安装项目。

二.安装设计师(Installation Designer)

1>Installation Information

Setup Languages:设置安装包的语言种类,可以设置多种语言,在运行安装包时会出现安装语言选择界面;

2>General Information

Project Properties:工程属性;

Add or Remove Programs

Disable Change Button:隐藏该安装包在添加删除程序列表中的更改按钮;

3>Organization

Feature:特征,每个Feature可包含子Feature及若干个Component,每个Feature都会出现在Feature选择界面中,一旦Feature被选择安装其包含的Component就    会被安装到系统中去;

Component:组件,每个Component可设置需要安装的文件、写入的注册表信息、创建的快捷方式等等;通常在这里指定是否卸 载、是否注册、安装策略(如果遇          到旧版本是全部覆盖还是部分覆盖,是先版本后时间覆盖还是只按版本高低覆盖等);

Setup Type:安装类型,一般默认有Minimal(压缩)、Typical(典型)、Custom(自定义),每种安装类型包含若干个Feature;

Setup Design:设置Features、Components(组件)及Files(安装文件)等等。

4>Application Data

Files and Folders:管理安装文件夹及文件,基本上每次打包都要使用;

Redistributables:可分发组件包,可以增加自己想程序运行前需要的组件(Setup Prerequisite安装先决条件),用.Net Framework也有ODBC,ODBC就是在这里添     加的

Objects:选择需要安装的系统运行库。

5>Server Configuration

Internet Information Service:配置IIS网站及虚拟目录

Component Services:

SQL Scripts:这是引入要部署的SQL脚本,可以支持Microsoft SQL Server, MySQL, and Oracle数据库;这个可以看帮助文档!

Shortcuts:创建快捷方式;

Registry:向注册表中添加键值;

XML File Changes:添加或更改XML文件。

6>Behavior and Logic

InstallScript:编写安装程序的脚本,这是制作复杂的基于InstallScript的安装包的最常使用的部分;

Support Files/Billboards:添加安装过程中需要的文件及安装背景(图片);

7>User Interface

Dialogs:这里可以对安装界面的对话框进行皮肤,自定义设置;

8>Media

Path Variables:编辑安装路径变量;

Releases:制作安装媒体。

9>Additional Tools

Dependency Scanners:搜索工具;

Direct Editor:命令编辑器,在这里可以查看或编辑安装程序的各类信息。

通过上面的基本描述,要制作一个安装包,通过最常用的是

Installation Information

Organization->Component

Organization->Setup Type

Application Data->Files and Folders

System Configuration->Shortcuts

Behavior and Logic->InstallScript

Media->Releases等部分。

这里可以对简单安装包进一步进行设置!

InstallShield部署MySql数据库初探

1>首先在InstallShield designer->Server Configuration->SQL Scripts

2>其次保证目标机器上有mysql odbc,mysql 的脚本在is里是调用这个完成,帮助文档添加mysql odbc的方法:

To add the MySQL Connector ODBC 3.51 setup prerequisite to your system so that you can add it to your projects:

Open Windows Explorer and browse for the setup prerequisite template folder. The default location is:

C:\Program Files\Macrovision\IS2008\SetupPrerequisites\Templates

Copy the MySQL Connector ODBC 3.51.prq file that is in the Templates folder, and paste it in the setup prerequisite folder. The default location is:

C:\Program Files\Macrovision\IS2008\SetupPrerequisites

Visit http://dev.mysql.com/downloads/connector/odbc/3.51.html and download the MSI installer for the MySQL Connector/ODBC 3.51 driver for Windows.

Save the file in the following location:

InstallShield Program Files Folder\Objects\MySQL\Redist

The next time that you launch InstallShield, the MySQL Connector ODBC setup prerequisite is available in the Redistributables view.

If you want to change the location on your machine where you store the installer for the MySQL Connector/ODBC 3.51 driver, you can do so by opening the MySQL Connector ODBC 3.51.prq file in the Setup Prerequisite Editor. To open the Setup Prerequisite Editor, click Prerequisite Editor on the Tools menu. For more information, see Specifying Files for a Prerequisite.

注意:这个地方InstallShield在复制文件时的文件名和我们下载的不一样,所以注意复制完文件后更改odbc安装程序的名称,我这里用的InstallShield 2008。

3>在SQL Scripts里添加一个新链接

(1)设置基本信息:

上面Catalog Name:为默认连接数据库的数据库名称,

下面的复选框Create Catalog if AbSent的意思如果你连接的数据库不存在,则创建数据库(好多教程里建议不让选这个,我有点不明白)。

Default Targe Server Name:默认连接的服务器名

Connect using:连接设置,和我们平常连接数据差不多,一个是本地验证,一个是用户名密码验证。

Comments:译过来就是注释了,呵呵!

(2)设置需求:

Requirments(这里选择数据库类型,注意一定要托下面的横向滚动条才可以看到复选框,靠,这里忽悠了哥半天,小组用的是mysql,这里选这个)

(3)Advanced:这里没搞清什么用!

(4)右击添加sql脚本

蛋疼的问题开始出现,这里添加从mysql导出的脚本后脚本中中文显示为乱码,而且这里mysql貌似一个sql脚本文件只能包含一条可执行的sql语句。就算脚本能执行,但Insert into 语句插入的数据中中文数据依然在数据库中是乱码。乱码问题整了我一天。起先以为是mysql 数据库配置问题,查看了下字符集是UTF8没错,数据库没问题,结果这里都无解了(如果哪位同学把这个整出来,请一定要告诉我)。

这里用InStallShield部署实现的功能只有能实现创建数据库,创建表格!但执行插入数据这里数据库就是乱码(解决不了)唉!

接着整理!

推荐学习InstallShield打包的几个链接:

1.论坛www.appinstall.cn

2.入门www.cnblogs.com/Cindy_weiwei

3.提高www.cnblogs.com/installshield

  • 上一页
  • 1
  • ···
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • ...
  • 下一页
  • 共 882 页

热门标签

C# (826)ASP.NET MVC (621)Android (588)ASP.NET (448)数据库 (300)JavaScript (287)JQuery (221)PHP (210)SQLServer (197)程序开发 (156)架构设计 (156)源价值 (155)SQL (128)Java (116)EasyUi (85)教程 (76)网站 (67)人工智能 (66)Debug (63)互联网 (63)MySQL (61)Flash (56)搜索优化 (54)创意 (53)SEO (51)ASP.NET MVC3 (51)电子商务 (50)建站经验 (49)实例代码 (49)源码下载 (47)

分类

  • 开发笔记 (5,970)
  • 源码下载 (9)
  • 网站运营 (279)
  • 图书下载 (115)
  • 创意应用 (108)
  • 动画视频 (75)
  • 琐事杂记 (292)
  • Android (1,011)
  • Java (206)
  • iOS开发 (150)
  • ASP.NET MVC (881)
  • ASP.NET (670)
  • C# (2,018)
  • JavaScript (1,047)
  • Delphi (56)
  • Flash (94)
  • Debug (840)
  • 数据库 (849)
  • 架构设计 (870)
  • 项目管理 (239)
  • AR (27)
  • Android源码 (2)
  • C#源码 (2)
  • Java源码 (4)
  • PHP (402)
  • PHP源码 (2)
  • Python (49)
  • 互联网 (244)
  • 产品 (75)
  • 人工智能 (153)
  • 人工智能 (31)
  • 建站经验 (186)
  • 微信小程序开发 (58)
  • 搜索优化 (130)
  • 机器学习 (28)
  • 游戏 (10)
  • 电子商务 (82)
  • 网站 (56)
  • 网站模板 (1)
  • 网络营销 (133)

链接表

  • 威客宝

© 2025 Mikel   网站地图 备案号:冀ICP备17031416号