2013年6月30日星期日

C#的线程池的那些事 - shenyuc

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
C#的线程池的那些事 - shenyuc  阅读原文»

最近在做站时发现,线程池的问题很棘手,所以总结了一篇关于线程池的文章,原文地址:http://www.shuonar.com/blog/ac16496b-87ec-4790-a9ea-d69bbffa1a87.html

C#编程语言中,使用线程池可以并行地处理工作,.NETFramework提供了包含ThreadPool类的System.Threading 空间,这是一个可直接访问的静态类,该类对线程池是必不可少的。它是公共线程池设计样式的实现。对于后台运行许多各不相同的任务是有用的。对于单个的后台线程而言有更好的选项。

线程的最大数量。这是完全无须知道的。在.NETThreadPool的所有要点是它自己在内部管理线程池中线程。多核机器将比以往的机器有更多的线程。微软如此陈述线程池通常有一个线程的最大数量,如果所有的线程都忙,增加的任务被放置在队列中直到它们能被服务,才能作为可用的线程。

用法位置

线程池类型能被用于服务器和批处理应用程序中,线程池有更廉价的得到线程的内部逻辑,因为当需要时这些线程已被形成和刚好连接,所以线程池风格代码被用在服务器上。

MSDN表述:线程池经常用在服务器应用程序中,每一个新进来的需求被分配给一个线程池中的线程,这样该需求能被异步的执行,没有阻碍主线程或推迟后继需求的处理。

虽然线程池能大大提高服务器的并发性能,但使用它也会存在一定风险。与所有多线程应用程序一样,用线程池构建的应用程序容易产生各种并发问题,如对共享资源的竞争和死锁。此外,如果线程池本身的实现不健壮,或者没有合理地使用线程池,还容易导致与线程池有关的死锁、系统资源不足和线程泄漏等问题。

1.死锁

任何多线程应用程序都有死锁风险。造成死锁的最简单的情形是,线程A持有对象X的锁,并且在等待对象Y的锁,而线程B持有对象Y的锁,并且在等待对象X的锁。线程A与线程B都不释放自己持有的锁,并且等待对方的锁,这就导致两个线程永远等待下去,死锁就这样产生了。
虽然任何多线程程序都有死锁的风险,但线程池还会导致另外一种死锁。在这种情形下,假定线程池中的所有工作线程都在执行各自任务时被阻塞,它们都在等待某个任务A的执行结果。而任务A依然在工作队列中,由于没有空闲线程,使得任务A一直不能被执行。这使得线程池中的所有工作线程都永远阻塞下去,死锁就这样产生了。

2.系统资源不足

如果线程池中的线程数目非常多,这些线程会消耗包括内存和其他系统资源在内的大量资源,从而严重影响系统性能。

3.并发错误

线程池的工作队列依靠wait()和notify()方法来使工作线程及时取得任务,但这两个方法都难于使用。如果编码不正确,可能会丢失通知,导致工作线程一直保持空闲状态,无视工作队列中需要处理的任务。因此使用这些方法时,必须格外小心,即便是专家也可能在这方面出错。最好使用现有的、比较成熟的线程池。例如,直接使用java.util.concurrent包中的线程池类。

4.线程泄漏

使用线程池的一个严重风险是线程泄漏。对于工作线程数目固定的线程池,如果工作线程在执行任务时抛出 RuntimeException 或Error,并且这些异常或错误没有被捕获,那么这个工作线程就会异常终止,使得线程池永久失去了一个工作线程。如果所有的工作线程都异常终止,线程池就最终变为空,没有任何可用的工作线程来处理任务。

导致线程泄漏的另一种情形是,工作线程在执行一个任务时被阻塞,如等待用户的输入数据,但是由于用户一直不输入数据(可能是因为用户走开了),导致这个工作线程一直被阻塞。这样的工作线程名存实亡,它实际上不执行任何任务了。假如线程池中所有的工作线程都处于这样的阻塞状态,那么线程池就无法处理新加入的任务了。

5.任务过载

当工作队列中有大量排队等候执行的任务时,这些任务本身可能会消耗太多的系统资源而引起系统资源缺乏。

综上所述,线程池可能会带来种种风险,为了尽可能避免它们,使用线程池时需要遵循以下原则。
(1)如果任务A在执行过程中需要同步等待任务B的执行结果,那么任务A不适合加入到线程池的工作队列中。如果把像任务A一样的需要等待其他任务执行结果的任务加入到工作队列中,可能会导致线程池的死锁。

(2)如果执行某个任务时可能会阻塞,并且是长时间的阻塞,则应该设定超时时间,避免工作线程永久的阻塞下去而导致线程泄漏。在服务器程序中,当线程等待客户连接,或者等待客户发送的数据时,都可能会阻塞。可以通过以下方式设定超时时间:

调用ServerSocket的setSoTimeout(int timeout)方法,设定等待客户连接的超时时间,参见本章3.5.1节(SO_TIMEOUT选项);

对于每个与客户连接的Socket,调用该Socket的setSoTimeout(inttimeout)方法,设定等待客户发送数据的超时时间,参见本书第2章的2.5.3节(SO_TIMEOUT选项)。

(3)了解任务的特点,分析任务是执行经常会阻塞的I/O操作,还是执行一直不会阻塞的运算操作。前者时断时续地占用CPU,而后者对CPU具有更高的利用率。预计完成任务大概需要多长时间?是短时间任务还是长时间任务?

根据任务的特点,对任务进行分类,然后把不同类型的任务分别加入到不同线程池的工作队列中,这样可以根据任务的特点,分别调整每个线程池。

(4)调整线程池的大小。线程池的最佳大小主要取决于系统的可用CPU的数目,以及工作队列中任务的特点。假如在一个具有 N 个CPU的系统上只有一个工作队列,并且其中全部是运算性质(不会阻塞)的任务,那么当线程池具有 N 或 N+1 个工作线程时,一般会获得最大的 CPU 利用率。

如果工作队列中包含会执行I/O操作并常常阻塞的任务,则要让线程池的大小超过可用CPU的数目,因为并不是所有工作线程都一直在工作。选择一个典型的任务,然后估计在执行这个任务的过程中,等待时间(WT)与实际占用CPU进行运算的时间(ST)之间的比例WT/ST。对于一个具有N个CPU的系统,需要设置大约N×(1+WT/ST)个线程来保证CPU得到充分利用。

当然,CPU利用率不是调整线程池大小过程中唯一要考虑的事项。随着线程池中工作线程数目的增长,还会碰到内存或者其他系统资源的限制,如套接字、打开的文件句柄或数据库连接数目等。要保证多线程消耗的系统资源在系统的承载范围之内。

5)避免任务过载。服务器应根据系统的承载能力,限制客户并发连接的数目。当客户并发连接的数目超过了限制值,服务器可以拒绝连接请求,并友好地告知客户:服务器正忙,请稍后再试。


本文链接:http://www.cnblogs.com/shuonar/p/3164591.html,转载请注明。

[C# 开发技巧]实现属于自己的截图工具 - Learning hard  阅读原文»

一、引言

之前一直都是写一些C#基础知识的内容的,然而有些初学者可能看完了这些基础知识之后,会有这样一个疑惑的——我了解了这些基础知识之后,我想做一些工具怎么还是不会做的呢?那些基础知识到底有什么用的了?然而我刚开始写这个系列的初衷主要是我想系统地去研究下C#各个阶段的特性的,及时有些特性我知道它是怎么用的,但是每次遇到问题的时候确实百度可以可以解决很多问题,但是自己总是觉得有点“虚”,然而通过写完这个系列之后,我很多知识点都可以串起来了,可以做到一个举一反三的一个效果的,当我遇到实际问题的也不可能完全自己写出来,同样也会百度找解决方案,但是此时我却没有 “虚”的感觉,因为我知道这个东西,并且我也知道如何正确的百度这个问题。所以对于基础知识的学习还是很有必要的,因为系统学完之后,你可以更好地找到你遇到问题的答案,因为我有时候会看到一些朋友在QQ群中提到,遇到某个问题都不知道百度什么的,然而系统地学习基础完全可以帮助你快速地百度,(其实找答案也是一种能力),然而对于第一个疑惑的解答就是——系统学习完,确实刚开始的确开发工具不会做,但是实际写代码是很简单,并且现在大部分应用你百度下都可以找到的,所以代码并不是问题,主要是解决问题的思路,并且实际工具的开发也是对一个基础知识的巩固,从而对问题达到一个举一反三的效果。

上面说了这么多的(可能说的有点多),主要是让大家明白,系统学习C#基础知识是很有必要的,系统学习完C#基础知识之后就是代码量的积累了,也就是自己做一些小工具,积累到一定代码量之后,就可以尝试写写一些大的项目或开源项目等,所以在后面的系列中将会分享一些具体工具的开发,同时这也是我自己的一个学习的计划,这里分享给大家希望对一些迷茫的朋友有所帮助。如果你现在还没有明确或更好地目标,并且也是从事.NET工作或学习的朋友,那就和我一起静下心来学编程,下面是我的一个学习方向图(可能多少有点偏差,相信大致意图大家可以明白):

二、实现思路

�嗦了这么多,下面就具体介绍下实现截图工具的实现思路。

为了让大家更清楚地知道如何去实现自己的截图工具,首先我来描述下截图的一个过程——我们使用QQ的截图工具和Windows 自带的截图工具都可以发现,当我们点击QQ窗体中的截图按钮时,此时我们将看到一个全屏图片,然后我们可以在其上截图,当鼠标左键按下时,即代表开始截图,并我们可以移动鼠标来改变截图的大小,鼠标弹起时即代表结束截图,此时我们可以双击矩形区域完全截图,并且可以通过粘贴操作把截取的图片粘贴到聊天窗口的发送区,鼠标右键点击则是退出截图。这样我们截图的过程描述就是这样的,从这个描述中我们就可以抽象出实现我们截图工具的思路来:

  1. 从 “此时我们将看到一个全屏图片”这句话描述我们应该抽象为——对于QQ截图工具的实现来说,我们看到的这个全屏图片其实并不是一张“图片”(这里最好不要钻空子),而是一个窗体,这个窗体我们命名为 “截图窗体”,只是把窗体的背景图片设置为全屏图片。说到这里,一些没有研究过QQ截图工具的人开始有疑问了——我们看到的是窗体?那为什么边框的,即没有最大化按钮,最下化按钮的呢?(对于这点的解释就是,程序中可以设置Form的BorderStyle属性为none的方式来隐藏掉边框)。
  2. 既然要设置窗体的背景图片为全屏图片,我们知道设置背景图片只需要设置窗体的BackgroundImage属性就好了,但是全屏图片怎么获取呢?既然是全屏图片,自然我就应该使窗体最大化话了,不然我们看到只是一个没有边框的“小图片”了,而不是一个全屏的图片。下面是具体实现这个分析的代码:
// 通过Graphics的CopyFromScreen方法把全屏图片的拷贝到我们定义好的一个和屏幕大小相同的空白图片中,
// 拷贝完成之后,CatchBmp就是全屏图片的拷贝了,然后指定为截图窗体背景图片就好了。
// 新建一个和屏幕大小相同的图片
Bitmap CatchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);

// 创建一个画板,让我们可以在画板上画图
// 这个画板也就是和屏幕大小一样大的图片
// 我们可以通过Graphics这个类在这个空白图片上画图
Graphics g = Graphics.FromImage(CatchBmp);

// 把屏幕图片拷贝到我们创建的空白图片 CatchBmp中
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));

// 创建截图窗体
cutter = new Cutter();

// 指示窗体的背景图片为屏幕图片
cutter.BackgroundImage = CatchBmp;

  3. 从 “然后我们可以在其上截图”这句话中我们抽象为——其实我们截图操作,从程序角度来说就是我们在这个最大化的窗体中画图,可能这个对一些不了解GDI+画图的朋友有些难理解,这里做个比喻——我们会拿笔在纸上画图,我们可以用比画三角形,矩形已经各种图形,此时纸就是我们一个画板,笔是用来画图图形的,同时笔也是有颜色和粗细的,我们可以用红色水笔画,画出来的图就是红色的了,也可以用黑色水笔画,自然画出来的就是黑色的了,同样,在GDI+也就是Graphics Device Interface Plus也就是图形设备接口,在.NET 中也提供了一些这样的类来让我们实现对图像的访问,也就是我们可以使用.NET中提供的类来进行 “画画”要画画当然必须要有画板吧(我们开始比喻中纸就是画板),在.NET 类中Graphics类就是对画板的抽象,画板可以由三种方式创建:(1)从图片或继承自图像对象中创建;(2)从窗体或控件的Paint事件中创建;(3)利用窗体或控件的CreateGraphics方法创建。有了画板之后,当然就需要笔来画画了,在.NET 中Pen类就是起到笔的作用,在构造函数中可以指定笔的颜色和粗细,有了笔之后就是开始画图了,在.NET中也同样提供了一些方法来完成画图,如DrawRectangle方法——画矩形

  4. 从 “当鼠标左键按下时,即代表开始截图,并我们可以移动鼠标来改变截图的大小,鼠标弹起时即代表结束截图,此时我们可以双击矩形区域完全截图,并且可以通过粘贴操作把截取的图片粘贴到聊天窗口的发送区,鼠标右键点击则是退出截图”这些描述中可以抽象为——鼠标的移动,按下,弹起等操作,在程序角度来说,也就是实现截图窗体的MouseMove事件(对应于鼠标移动),MouseDown事件(对应于鼠标左键按下),MouseClick事件(对应于鼠标右键结束截图)、MouseUp(对应于鼠标弹起结束截图)和MouseDoubleClick(鼠标双击矩形区域完全截图,并可以通过粘贴操作把截取的图片粘贴到聊天窗口的发送区,既然可以进行粘贴操作来获得截取图片,所以必须在该事件中对剪切板设置截图图片),3和4的分析过程也是截图功能的核心实现,对应于下面的代码(代码中有详细解释,并且大家理解的时候可以结合3和4的分析):

/// <summary>
/// 鼠标右键点击结束截图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Cutter_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
}

/// <summary>
/// 鼠标按下事件处理程序
/// </summary>
/// <param name="sender"></param>
///阅读更多内容

2013年6月29日星期六

谈中型项目下的编码技巧一

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
谈中型项目下的编码技巧一  阅读原文»

用户名:lilin9105 文章数:32 评论数:43
访问量:12243:629:450:3 注册日期:2013-04-25
谈中型项目下的编码技巧一
andriod中搞稍微大点个软件,写几十个java文件是常有的事。怎么样写思路才不打断影响到效率与耐心。
命名规则是根据团队约定的,每个团队命名规则都有区别,但目地是一样的---提高效率。
这里说的只做参考
包名命名:根据每个activity的作用命名。如订单结算:account,地址管理:addr。有几个主activity就有几个不同的包
包下的java文件命名
主activity文件 包名_Activity
副文件: 包名_功能 包名_adapter

项目公共包名:
如果有activity之间的跳转,那么建议弄个"intent"包名,包下建立一个IntentsUnits.java文件
所有要跳转的都写在这个文件下
  package com.intent;  import com.addr.Addr_list;  import com.item_intent.Item_activity;  import android.app.Activity;  import android.content.Intent;  import android.sax.StartElementListener;  public class IntentsUnits {  public static void toAddrList(Activity activity)  {  Intent intent = new Intent();  intent.setClass(activity, Addr_list.class);  activity.startActivity(intent);  }  public static void toIntentActivity(Activity activity, String type){  Intent intent = new Intent();  intent.setClass(activity, Item_activity.class);  intent.putExtra("type", type);  activity.startActivity(intent);  }  }  
有数据库的建个sqlitedb包名的包,包名下建立的文件名为"数据库名称DB"

有常量的建个"projectConstant"包名,在包名下建立一个ProjectConstant.java,然后把工程有关的所有的常量都写在这里,不写在resource下的string的文件中,是有的时候要用或改麻烦。特别当工程中用到数据库时。
  package com.projectConstant;  import android.R.string;  import android.os.Environment;  public class ProjectConstant {  //file or dir  public static String ProjectDir = Environment.getExternalStorageDirectory().getPath() + "/xinyu_school/";  public static String projectDBDir = ProjectDir + "database";//数据库文件夹名称  public static String projectImageDir = ProjectDir + "image";//图片文件夹  //以下是history的type  public static String HISTORYTYPE_BUYING = "1";//购物车  public static String HISTORYTYPE_BOUGHT = "2";//已经购买  public static String HISTORYTYPE_STORE = "3";//收藏  //以下部分无需理会  public static String projectDBDirName = "/xinyu_school/database/";//此处无需管它  //database  //database at sdcard  public static String DB_PRODUCT = "product_db.db";  //product productParent  picturename productname price number  //开心吧  path 烤猪 30,10只  public static String DB_PRODUCTTABLE = "product";  public static String DB_PARENT = "parent";  public static String DB_PICTURENAME = "picturename";  public static String DB_PRODUCTNAME = "productname";  public static String DB_PRICE = "price";  public static String DB_NUMBER = "number";  public static String DB_TOADDR = "ToAddr_db.db";  public static String DB_TOADDR_TABLE = "ToAddr";  public static String DB_TONAME = "toname";  public static String DB_TOADDRESS = "toaddress";  public static String DB_TOTEL = "totel";  public static String DB_TOCHECKED = "checked";  public static String DB_TODEFAULT = "defaulted";  public static String DB_HISTORY = "history.db";  public static String DB_HSTRYTABLE = "historytable";  public static String DB_HISTORY_TYPE = "type";  public static String DB_CLIENT_ID= "admin";  }  
类包名:在做工程前肯定先把一些数据类化,所以要建一个对象包ProjectClass,低下的文件名根据各个类来命名。

layout下的文件命名,根据activity的功能对应的布局命名。

最关键:layout下的xml内部控件的命名,跟drawable下的文件命名,他们在生成id是都在R.id下:
layout下xml内空间的命名layout_xml名称_功能如地址管理中的电话信息layout_client_addr_tel
drawable下的文件名用draw_所属xml名称_所属控件功能。如draw_client_addr_tel。

另外附上以前写的ecshop 网店雏形的代码下载地址http://pan.baidu.com/share/link?shareid=1333309535&uk=2065228996,这个代码几乎涉及到30%我所学的东西,里面的代码编写风格,跟内容有一定的学习价值。下载后先看"说明.txt"。编码utf-8.
本文出自 "lilin9105" 博客,请务必保留此出处http://7071976.blog.51cto.com/7061976/1232357

理解C# 4 dynamic(1) - var, object, dynamic的区别以及dynamic的使用 - JustRun

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
理解C# 4 dynamic(1) - var, object, dynamic的区别以及dynamic的使用 - JustRun  阅读原文»

阅读目录:

一. 为什么是它们三个

二. 当需求发生变动时,非IoC遭遇到的困境

三. 使用IoC彻底解决问题

四. 总结

一. 为什么是它们三个?

拿这三者比较的原因是它们在使用的时候非常相似。你可以用它们声明的变量赋任何类型的值。

看看下面的示例:

var a = 1;
object b = 1;
dynamic c
= 1;

你还可以使用关键字为它们赋上更加复杂的类型

var a = new string[]{"1"};
object b = new string[]{"1"};
dynamic c
= new string[]{"1"};

二. 能够任意赋值的原因

上面的例子中,看起来三者非常相似,但是背后的原理却是非常不同。

var是C# 3中引入的,其实它仅仅只是一个语法糖. var本身并不是一种类型, 其它两者object和dynamic是类型。

var声明的变量在赋值的那一刻,就已经决定了它是什么类型。

所以如果你这样使用,就会有编译错误:

var a = 1;
a
= "Test";

object之所以能够被赋值为任意类型的原因,其实都知道,因为所有的类型都派生自object. 所以它可以赋值为任何类型:

object a = 1;
a
= "Test";

那么dynamic呢?

它是C#引入的新类型,它的特点是申明为dynamic类型的变量,不是在编译时候确定实际类型的, 而是在运行时。

所以下面的代码是能够通过编译的,但是会在运行时报错:

dynamic a = "test";
a
++;

上面代码内部处理的过程是怎样的呢?

首先, dynamic类型赋值为字符串"test", 运行++操作的时候,.net会去寻找当前的赋值类型string中是否支持++操作,发现不支持,出现异常。

所以,如果这样修改一下,就可以让代码正常运行起来

dynamic a = "test";
a
= 1;
a
++;

三. dynamic的用法

1 直接使用该类型,可以非常方便的插入属性, 方法

static void Main(string[] args)
{
dynamic person
= new System.Dynamic.ExpandoObject();
person.Name
= "cary";
person.Age
= 25;
person.ShowDescription
= new Func<string>(() => person.Name + person.Age);

Console.WriteLine(person.Name
+ person.Age + person.ShowDescription());
Console.ReadLine();
}

2 枚举所有成员

foreach (var property in (IDictionary<String, Object>)dynEO)
{
Console.WriteLine(property.Key
+ ": " + property.Value);
}

3 简化反射

常用的处理反射的例子:

object calc = GetCalculator();
Type calcType
= calc.GetType();
object res = calcType.InvokeMember( "Add", BindingFlags.InvokeMethod, null, new object[] { 10, 20 });
int sum = Convert.ToInt32(res);

使用dynamic之后:

dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);

四,使用dynamic的注意事项

有了dynamic,.net就以及有了动态类型的优势,但是由于对于dynamic类型的所有操作,都是在运行时确定的,所有错误无法在编译时候出现,使用的时候,就需要非常小心。

因为dynamic是类型,所以如果函数接受的是确定类型的参数,是不能传入dynamic类型的,这样会有编译错误。比如:

public int Add(int a, int b){
return a + b;
}
dynamic test1
= 1;
dynamic test2
= 2;
Add(test1, test2);

另外,在我们自己在写函数时,最好不要将dynamic类型作为函数的参数,这就像是使用object作为函数参数一样,会为程序的维护带来后续的麻烦。

没有人能够确定使用者传入的是什么,而且编译时候不会有问题。如果错误出现在运行时,就有可能是灾难。


本文链接:http://www.cnblogs.com/JustRun1983/p/3163350.html,转载请注明。

Android学习笔记6:四大组件之 使用Content Providers方式共享数据 - 飞默  阅读原文»

在Android中一共提供了5种数据存储方式,分别为:

  (1)Files:通过FileInputStream和FileOutputStream对文件进行操作。具体使用方法可以参阅博文《Android学习笔记34:使用文件存储数据》。

  (2)Shared Preferences:常用来存储键值对形式的数据,对系统配置信息进行保存。具体使用方法可以参阅博文《Android学习笔记35:使用Shared Preferences方式存储数据》。

  (3)Content Providers:数据共享,用于应用程序之间数据的访问。

  (4)SQLite:Android自带的轻量级关系型数据库,支持SQL语言,用来存储大量的数据,并且能够对数据进行使用、更新、维护等操作。具体使用方法可以参阅博文《Android学习笔记36:使用SQLite方式存储数据》。

  (5)Network:通过网络来存储和获取数据。

  本篇博文介绍第三种方式,通过Content Providers实现应用程序之间的数据共享。

1.Content Providers简介

  在Android系统中,不存在一个公共的数据存储区供所有的应用程序访问,也就是说数据在各个应用程序中是私有的。那么,如何在一个应用程序中访问另一个应用程序中的数据,实现应用程序之间的数据共享呢?

  当然,你可以通过《Android学习笔记34:使用文件存储数据》一文中讲到的设置openFileOutput()方法中的第二个参数mode为Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE,让别的应用程序可以读写该应用程序中的文件。但是,使用这种方式的弊端也是显而易见的,不仅需要知道该文件的存储路径,而且会将该文件内容完全的暴露出去,对于内容提供者和内容访问者来说都是不方便和不安全的。

  为此,Android系统提供了Content Providers,用以方便安全的实现应用程序间的数据共享。

1.1ContentResolver

  所有的Content Providers都会实现一些共同的接口,包括数据的查询、添加、更改和删除。在应用程序中,我们可以通过使用getContentResolver()方法来取得一个ContentResolver对象,然后就可以通过这个ContentResolver对象来操作你需要的Content Provider了。ContentResolver类提供的用来操作Content Provider的方法主要有insert()、delete()、update()和query()。

  通常,对于开发者而言,并不需要同Content Provider对象直接打交道。系统运行时,会将所有的ContentProvider对象实例化,对于每一种类型的ContentProvider只有一个实例。这个实例可以与在不同的程序或进程中的多个ContentResolver对象进行通信。而这些进程间的交互则是由ContentResolver和ContentProvider类进行处理的。

  对于Content Providers而言,最重要的就是数据存储结构和URI。

2013年6月27日星期四

iPhone 4 酒吧门背后的悲剧主角


  去哪里可以捡到未发布的原型机?酒吧。三年之后,当初在酒吧捡到 iPhone 4 原型机的 Brian Hogan 又回到了媒体的面前。他通过 Reddit 的 “Ask me Anything”栏目讲诉了自己的悲剧遭遇,而一切的罪魁祸首都是因为自己捡到了 iPhone 4 原型机。
  当年的 Brian Hogan 21 岁,在酒醉的昏眩中他偶然拾到了一只看似普通的 iPhone。回家后他对这只手机进行了检查,发现这可能是一只尚未发布的新 iPhone,但没多久这部手机就被锁死成了砖头。Hogan 随后联系了苹果,希望能够将设备归还并领取一些报酬——“接电话那人根本不知道有原型机遗失”,于是 Hogan 开始寻找下一个买家。
  Hogan 联系了一些科技媒体并且最终圈定 Gizmodo,后者承诺先支付 5000 美金,等确认设备属实并且报道见光后再支付 3000 美金。“他们心里很清楚,只要此事一公开,我不可能再去索要 3000 美元”。事实的确如此,报道见光后 Hogan 便遭到苹果起诉,被警方带走。
  那 5000 美元呢?Hogan 表示雇用律师的费用早就超出了 5000 美元,自己还在局子里被调查了 3 周时间。除此之外,由于住宅被媒体包围,他们全家不得不转移到一家酒店内躲了一周时间。更不幸的是,迫于媒体压力,Hogan 的女友和他分手了。
  Hogan 表示,以后如果在酒吧捡到 iPhone,一定丢给酒保,而 Galaxy S3 是自己目前的选择。有关注者问道,当初为何没有将 iPhone 4 卖给三星或者 HTC,Hogan 懊恼地说:TMD 当时太匆忙了。
来自: ifanr 爱范儿

伴随我成长的编程书

一、
这篇文章是应之前在微博上爆过的下个周末某出版社的线下活动而写的。回顾我和C++在这个世纪的第二个春天开始发生过的种种事情,我发现我并不是用一个正常的方法来学会如何正常使用C++的。我的C++学习伴随着很多其他流行或者不流行的语言。现在手中掌握的很多淫荡的技巧正是因为学习了很多编程语言的缘故,不过这并不妨碍我正常地使用C++来在合理的时间内完成我的目标。

经验分享:CSS浮动(float,clear)通俗讲解

 很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程。
       前些天小菜终于搞懂了浮动的基本原理,迫不及待的分享给大家。
      

Javascript执行效率小结

Javascript是一门非常灵活的语言,我们可以随心所欲的书写各种风格的代码,不同风格的代码也必然也会导致执行效率的差异,开发过程中零零散散地接触到许多提高代码性能的方法,整理一下平时比较常见并且容易规避的问题

Java的内存回收机制

 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C/C++直接操作内存的危险。但是,也正因为内存管理完全由JVM负责,所以也使Java很多程序员不再关心内存分配,导致很多程序低效,耗内存。因此就有了Java程序员到最后应该去了解JVM,才能写出更高效,充分利用有限的内存的程序。

怎么看待移动互联网时代

最近一直在做调研分析,以一篇文章来做个总结,谈谈我的看法。
文章也好,书也好,大抵可以分两大类。第一大类的,它可以告诉你你不知道的信息,信息也许不好听,但是是很有效的信息,比如,退休前的任志强写的那些挨骂的博客。另一大类,它的目的就是迎合你的观点,让你来掏钱,楚王爱细腰,宫中多饿死。做分析的话,需要数据,需要概念,需要观点,在分析之前,需要对概念、数据和观点来“去魅”,去掉人们因为各种目的加在这些概念和观点之上的那些会妨碍你进行判断的东西。

项目代码风格要求

代码风格没有正确与否,重要的是整齐划一,这是我拟的一份《项目代码风格要求》,供大家参考。

JavaScript同样的意思,更巧的写法

 今天来介绍一下javascript不一样的写法,很简单哦。
1、当条件成立时执行a方法,当条件失败是执行b方法
通常我们会这样写:
var result;
if(isOk){
  result=funA();
}else{
 result=funB();
}
还可以这样表达:
 var result=isOk? funA():funB()

IIS日志-网站运维的好帮手

对于一个需要长期维护的网站来说,如何让网站长久稳定运行是件很有意义的事情。 有些在开发阶段没有暴露的问题很有可能就在运维阶段出现了,这也是很正常的。 还有些时候,我们希望不断地优化网站,让网站更快速的响应用户请求, 这些事情都发生在开发之后的运维阶段。
与开发阶段不同的,运维阶段不可能让你去调试程序,发现各类问题, 我们只能通过各种系统日志来分析网站的运行状况, 对于部署在IIS上的网站来说,IIS日志提供了最有价值的信息,我们可以通过它来分析网站的响应情况,来判断网站是否有性能问题, 或者存在哪些需要改进的地方。

.NET Web开发技术简单整理

在最初学习一些编程语言、一些编程技术的时候,做的更多的是如何使用该技术,如何更好的使用该技术解决问题,而没有去关注它的相关性、关注它的理论支持,这种学习技术的方式是短平快。其实工作中有时候也是这样,公司要推崇一个新技术、一个解决方案,我们总是短平快的去学习如何使用它,按照固定的解决问题思路按着案例进行,这也是一种应对项目紧急的一些措施。