Monthly Archives: March 2011

android 如何保存簡單的配置信息(SharedPreferences、File和Properties)

我們知道在android的開發中,保存項目私有數據的存儲方式我們可以使用:SharedPreferences,File,SQLite,Network.四種方式,而要用到應
用程序之間數據的共享要使用ContentProvider 。那今天我們只敘述一下僅僅保存一些我們登錄等的一些配置信息的數據,也就是說用到的數
據量都不是很大,那麼我們就可以選擇SharedPreferences和File的方式。這裡只針對性的結合File和Properties進行敘述。
一。SharedPreferences

1. 它可以保存上一次用戶所做的修改或者自定義參數的設定,當再次啟動程序後依然可以保持原有的設置。這裡只說明一下使用方式。比如下
面的代碼在OnCreate中使用:

SharedPreferences mSharedPreferences = getSharedPreferences(“list”,MODE_PRIVATE);

String mTempString = mSharedPreferences.getString(“config”,”default”);

其中”list”是SharedPreferences的文件的名字,SharedPreferences是以鍵值映射的關係存放數據。不過多解釋,你也可以這樣用:

SharedPreferences mSharedPreferences = getPreferences(MODE_PRIVATE);

這樣默認的文件名是activity的名字。

2. 退出activity的時候保存數據,在OnPause中使用:

SharedPreferences mSharedPreferences = getSharedPreferences(“list”,    MODE_PRIVATE);

mSharedPreferences.edit().putString(“config”,”data” ).commit();

3. SharedPreferences 是以xml文件的方式自動保存的,在DDMS中的FileExplorer中展開/data/data/包名/shared-prefs下面就是SharedPreferences文件。

4. SharedPreferences文件只可以用來存放基本的數據類型。
二。結合File和Properties進行保存。

A Properties object is a Hashtable where the keys and values must be Strings. Each property can have a default Properties list which specifies the default values to be used when a given key is not found in this Properties instance.

1.所以,Properties對象也是一個哈希表,也是一個鍵值對應的關係,因此和上面的操作相似。下面看具體的程序。

public class File_ByProperties extends Activity {

private boolean mStatus;

private TextView mShowStatus;
/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

mShowStatus = (TextView) findViewById(R.id.show);

load();

}
private void load() {

// TODO Auto-generated method stub

Properties mProperties = new Properties();

try {

FileInputStream mInputStream = openFileInput(“configuration”);

mProperties.load(mInputStream);

mStatus = Boolean.valueOf(mProperties.get(“status”).toString());

mShowStatus.setText(“the status is : ” + mStatus);

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

System.out.println(e.toString());

} catch (IOException e) {

System.out.println(e.toString());

}

}
@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

// TODO Auto-generated method stub

if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {

mStatus = !mStatus;

mShowStatus.setText(“the status is : ” + mStatus);

}

return super.onKeyDown(keyCode, event);

}
@Override

protected void onPause() {

// TODO Auto-generated method stub

super.onPause();

Properties mProperties = new Properties();

if (mProperties.containsKey(“status”)) {

mProperties.remove(“status”);

}

mProperties.put(“status”, String.valueOf(mStatus));

try {

FileOutputStream mOutputStream = openFileOutput(“configuration”,     MODE_WORLD_WRITEABLE);

mProperties.store(mOutputStream, null);

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}
}

2. 在DDMS中的FileExplorer中展開/data/data/包名/files,可以查看到該文件。
三。你還可以將一個靜態的文件放到res/raw/下面,然後通過getResources().openRawResource(R.raw.文件);來得到一個InputStream對象,然後讀取文件的內容。

开发 Eclipse 插件

简介: 在本文中,David Gallardo 向您展示了如何使用 Plug-in Development Environment 的代码生成向导来创建 Eclipse 插件。您将学到如何在运行时工作台中运行和调试插件,并且在 Eclipse 中安装完成的插件。David 还研究了与打包插件相关的问题 ― 包括维护版本信息、以插件片段的形式更新功能,以及组合插件来创建完整的功能部件。

 

基于插件的体系结构

Eclipse 平台是 IBM 向开发源码社区捐赠的开发框架,它之所以出名并不是因为 IBM 宣称投入开发的资金总数 ― 4 千万美元 ― 而是因为如此巨大的投入所带来的成果:一个成熟的、精心设计的以及可扩展的体系结构。Eclipse 的价值是它为创建可扩展的集成开发环境提供了一个开放源码平台。这个平台允许任何人构建与环境和其它工具无缝集成的工具。

工具与 Eclipse 无缝集成的关键是插件。除了小型的运行时内核之外,Eclipse 中的所有东西都是插件。从这个角度来讲,所有功能部件都是以同等的方式创建的。从这个角度来讲,所有功能部件都是以同等的方式创建的。

但是,某些插件比其它插件更重要些。Workbench 和 Workspace 是 Eclipse 平台的两个必备的插件 ― 它们提供了大多数插件使用的扩展点,如图 1 所示。插件需要扩展点才可以插入,这样它才能运行。
图 1. Eclipse Workbench 和 Workspace:必备的插件支持
Eclipse Workbench

Workbench 组件包含了一些扩展点,例如,允许您的插件扩展 Eclipse 用户界面,使这些用户界面带有菜单选择和工具栏按钮;请求不同类型事件的通知;以及创建新视图。Workspace 组件包含了可以让您与资源(包括项目和文件)交互的扩展点。

当然,其它插件可以扩展的 Eclipse 组件并非只有 Workbench 和 Workspace。此外,还有一个 Debug 组件可以让您的插件启动程序、与正在运行的程序交互,以及处理错误 ― 这是构建调试器所必需的。虽然 Debug 组件对于某些类型的应用程序是必需的,但大多数应用程序并不需要它。

还有一个 Team 组件允许 Eclipse 资源与版本控制系统(VCS)交互,但除非您正在构建 VCS 的 Eclipse 客户机,否则 Team 组件,就象 Debug 组件一样,不会扩展或增强它的功能。

最后,还有一个 Help 组件可以让您提供应用程序的联机文档和与上下文敏感的帮助。没有人会否认帮助文档是专业应用程序必备的部分,但它并不是插件功能的必要部分。

上述每个组件提供的扩展点都记录在 Eclipse Platform Help 中,该帮助在 Platform Plug-in Developer 指南的参考部分中。乍一看,尤其是 API 参考大全的 Workbench 部分,一开始会令人望而却步。我们不会深入了解众多可用扩展点的详细信息,而只是粗略地看一个简单插件及其组件。

插件简介

创建插件最简单的方法是使用 Plug-in Development Environment(PDE)。PDE 和 Java Development Tooling(JDT)IDE 是 Eclipse 的标准扩展。PDE 提供了一些向导以帮助创建插件,包括我们将在这里研究的“Hello, world”示例。

从 Eclipse 菜单,选择 File=>New=>Other(或按 Ctrl-N),然后选择 Select 对话框左边的 Plug-in Development 向导。在 Select 对话框的右边,选择 Plug-in Project。按 Next。在下一屏上,输入项目名称;我使用了 com.example.hello。再次按 Next。在下一屏上,请注意,插件标识就与项目名称相同。使用项目名称作为插件标识可以将该插件与另一个插件的名称发生冲突的机会减到最小。再按一次 Next。下一屏让您选择是手工创建初始插件代码,还是运行代码生成向导。保留代码生成向导的缺省选项,选择“Hello, World”,然后按 Next,如图 2 所示。
图 2. 选择“Hello, World”代码生成向导
新插件

下一屏要求一些附加信息。请注意这一屏上的信息:它包含了插件名称、版本号、提供者名称和类名。这些是关于插件的重要信息,我们将在稍后研究。可以接受向导提供的缺省值。按 Next。在下一屏幕上,接受包名、类名和消息文本的缺省值。选择“Add the action set to the resource perspective”复选框。按 Finish。

如果接到通知:向导需要启用某些其它插件才能完成,那么按 OK。

过一会儿,向导将完成,而在您的工作区中将会有一个新的项目,名为 com.example.hello,如图 3 所示。
图 3. PDE 透视图:Welcome to Hello Plug-in
PDE 透视图

在 Package Explorer 中,工作台的左边是向导创建的一些东西的概述。大多数项都不引人关注:包括项目类路径中的许多 .jar 文件(这些包括插件和 Java 运行时所需的 Eclipse 类)、一个图标文件夹(包含了工具栏按钮的图形),以及 build.properties 文件(包含自动构建脚本所使用的变量)。

这里最有意思的东西是 src 文件夹,它包含了插件和 plugin.xml 文件的源代码 ― plug-in.xml 是插件的清单文件。我们将先查看 plugin.xml。

插件清单文件

插件清单文件 plugin.xml 包含了 Eclipse 将插件集成到框架所使用的描述信息。缺省情况下,当第一次创建插件时,会在清单编辑器区域中打开 plugin.xml。编辑器底部的选项卡让您可以选择关于插件的不同信息集合。Welcome 选项卡显示了消息“Welcome to Hello Plug-In”,并且简要讨论了所使用的模板和关于使用 Eclipse 实现插件的提示。选择“Source”选项卡可以让您查看 plugin.xml 文件的完整源代码。

让我们看看插件清单文件的各个部分。首先是关于插件的常规信息,包括它的名称、版本号、实现它的类文件的名称和 .jar文件名。
清单 1. 插件清单文件 ― 常规信息

<?xmlversion="1.0" encoding="UTF-8"?>
<plugin
   id="com.example.hello"
   name="Hello Plug-in"
   version="1.0.0"
   provider-name="EXAMPLE"
  >

   <runtime>
      <library name="hello.jar"/>
   </runtime>

 

接着,列出了我们的插件所需的插件:
清单 2. 插件清单文件 ― 必需的插件

   <requires>
      <import plugin="org.eclipse.core.resources"/>
      <import plugin="org.eclipse.ui"/>
   </requires>

 

列出的第一个插件 org.eclipse.core.resources 是工作区插件,但实际上我们的插件并不需要它。第二个插件 org.eclipse.ui 是工作台。我们需要工作台插件,因为我们将扩展它的两个扩展点,正如后面的 extension 标记所指出的。

第一个 extension 标记拥有点属性 org.eclipse.ui.actionSets。操作集合是插件添加到工作台用户界面的一组基值 ― 即,菜单、菜单项和工具栏。操作集合分组了基值,这样用户可以更方便地管理它们。例如,我们的 Hello 插件的菜单和工具栏项将出现在 Resource 透视图中,因为当在运行代码生成向导时,我们做了这样的选择。如果用户要更改它,可以使用 Window=>Customize Perspective 菜单选项从要在 Resource 透视图中显示的项中除去“Sample Action Set”。
图 4. 定制 Resource 透视图
Resource 透视图

操作集合包含了两个标记:menu 标记(描述菜单项应该出现在工作台菜单的什么位置,以及如何出现)和action 标记(描述它应该做什么)― 尤其是 action 标记标识了执行操作的类。注:这个类不是上面列出的插件类。
清单 3. 操作集合

   <extension
         point="org.eclipse.ui.actionSets">
      <actionSet
            label="Sample Action Set"
            visible="true"
            id="com.example.hello.actionSet">
         <menu
               label="Sample &Menu"
               id="sampleMenu">
            <separator
                  name="sampleGroup">
            </separator>
         </menu>
         <action
               label="&Sample Action"
               icon="icons/sample.gif"

               tooltip="Hello, Eclipse world"
               menubarPath="sampleMenu/sampleGroup"
               toolbarPath="sampleGroup"
               id="com.example.hello.actions.SampleAction">
         </action>
      </actionSet>
   </extension>

 

许多菜单和操作属性的目的相当明显 ― 例如,提供工具提示文本和标识工具栏项的图形。但还要注意 action 标记中的menubarPath:这个属性标识了 menu 标记中定义的哪个菜单项调用 action 标记中定义的操作。有关这个和其它工作台扩展点的详细信息,请参考 Platform Plug-in Developer Guide,尤其是“Plugging into the workbench”章节(可以从 Eclipse 的帮助菜单中获取该指南)。

由于我们选择了将插件添加到 Resource 透视图,于是生成了第二个 extension 标记。这个标记会导致当 Eclipse 第一次启动并装入我们的插件时,将插件添加到 Resource 透视图。
清单 4. extension 标记

   <extension
         point="org.eclipse.ui.perspectiveExtensions">
      <perspectiveExtension
            targetID="org.eclipse.ui.resourcePerspective">
         <actionSet
               id="com.example.hello.actionSet">
         </actionSet>
      </perspectiveExtension>
   </extension>
</plugin>

 

如果忽略这最后一个 extension,用户就需要使用 Window=>Customize Perspective 将插件添加到 Resource(或其它)透视图。

插件源代码

代码生成向导生成了两个 Java 源文件,打开 PDE Package Explorer 中的 src 文件夹就可以看到它们。第一个文件HelloPlugin.java 是插件类,它继承了 AbstractUIPlugin 抽象类。HelloPlugin 负责管理插件的生命周期,在更为扩展的应用程序中,它负责维护诸如对话框设置和用户首选项等内容。HelloPlugin 要做的事就这么多:
清单 5. HelloPlugin

packagecom.example.hello.actions;

import org.eclipse.ui.plugin.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.resources.*;
import java.util.*;

/**
 * The main plugin class to be used in the desktop.
 */
public class HelloPlugin extends AbstractUIPlugin {
      //The shared instance.
      private static HelloPlugin plugin;
      //Resource bundle.
      private ResourceBundle resourceBundle;

      /**
       * The constructor.
       */
      public HelloPlugin(IPluginDescriptor descriptor) {
            super(descriptor);
            plugin = this;
            try {
                  resourceBundle= ResourceBundle.getBundle(
                       "com.example.hello.HelloPluginResources");
            } catch (MissingResourceException x) {
                  resourceBundle = null;
            }
      }

      /**
       * Returns the shared instance.
       */
      public static HelloPlugin getDefault() {
            return plugin;
      }

      /**
       * Returns the workspace instance.
       */
      public static IWorkspace getWorkspace() {
            return ResourcesPlugin.getWorkspace();
      }

      /**
       * Returns the string from the plugin's resource bundle,
       * or 'key' if not found.
       */
      public static String getResourceString(String key) {
            ResourceBundle bundle= HelloPlugin.getDefault().getResourceBundle();
            try {
                  return bundle.getString(key);
            } catch (MissingResourceException e) {
                  return key;
            }
      }

      /**
      * Returns the plugin's resource bundle,
      */
      public ResourceBundle getResourceBundle() {
          return resourceBundle;
      }
}

 

第二个源文件 SampleAction.java 包含的类将执行在清单文件的操作集合中指定的操作。SampleAction 实现了IWorkbenchWindowActionDelegate 接口,它允许 Eclipse 使用插件的代理,这样不是在万不得已的情况下,Eclipse 就无需装入插件(这项优化工作使在装入插件时发生内存和性能方面的问题降到最低)。IWorkbenchWindowActionDelegate 接口方法使插件可以与代理进行交互:
清单 6. IWorkbenchWindowActionDelegate 接口方法

package com.example.hello.actions;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.jface.dialogs.MessageDialog;

/**
 * Our sample action implements workbench action delegate.
 * The action proxy will be created by the workbench and
 * shown in the UI. When the user tries to use the action,
 * this delegate will be created and execution will be
 * delegated to it.
 * @see IWorkbenchWindowActionDelegate
 */
public class SampleAction implements IWorkbenchWindowActionDelegate {
      private IWorkbenchWindow window;
      /**
       * The constructor.
       */
      public SampleAction() {
      }

      /**
       * The action has been activated. The argument of the
       * method represents the 'real' action sitting
       * in the workbench UI.
       * @see IWorkbenchWindowActionDelegate#run
       */
      public void run(IAction action) {
            MessageDialog.openInformation(
                  window.getShell(),
                  "Hello Plug-in",
                  "Hello, Eclipse world");
      }

      /**
       * Selection in the workbench has been changed. We
       * can change the state of the 'real' action here
       * if we want, but this can only happen after
       * the delegate has been created.
       * @see IWorkbenchWindowActionDelegate#selectionChanged
       */
      public void selectionChanged(IAction action, ISelection selection) {
      }

      /**
       * We can use this method to dispose of any system
       * resources we previously allocated.
       * @see IWorkbenchWindowActionDelegate#dispose
       */
      public void dispose() {
      }

      /**
       * We will cache window object in order to
       * be able to provide parent shell for the message dialog.
       * @see IWorkbenchWindowActionDelegate#init
       */
      public void init(IWorkbenchWindow window) {
            this.window = window;
      }
}

 

运行和调试插件

当开发 Eclipse 的插件时,必须停止 Eclipse 并用新的插件重新启动它以便进行测试和调试,这很笨拙。幸好,Eclipse PDE 提供了一个自托管(self-hosted)的开发环境,它让您无需将插件安装在工作台的单独实例中即可运行。

要运行 Hello 插件,选择 Run=>Run As=>Run-time Workbench 来启动另一个 Workbench 实例,而该实例添加了插件的菜单选项和工具栏,如图 5 所示。
图 5. 在运行时工作台中运行的 Hello 插件
Hello 插件

我们可以通过单击工具栏按钮或从“Sample Menu”菜单激活插件。任何一种方法都会生成一个框,其标题是“Hello Plug-in”,内容是“Hello, Eclipse world”,以及一个 OK 按钮,按该按钮可以关闭这个框。

通过选择 Run=>Debug As=>Run-time Workbench,按类似的方法调试插件。这次,当插件在第二个工作台实例中运行时,我们可以在最初的工作台中单步执行源代码,以及检查变量等。

一旦插件经过测试并准备发布,我们就需要将它适当打包,以便在 Eclipse 中安装。

打包插件

Eclipse 在启动时会查看其插件目录来确定要装入哪些插件。要安装插件,我们需要在插件目录中创建一个子目录,并将程序文件和清单文件复制到那里。建议目录名称能表示插件的标识,并且后面跟下划线和版本号,但是这种做法不是必需的。假设 Eclipse 安装在 C:\eclipse 中;我们要创建一个目录:

C:\eclipse\plugins\com.example.hello_1.0.0.

按照 Java 程序的标准,我们的程序文件需要归档到 .jar文件中 — 我们的插件清单文件,您也许记得它包含这个项:

   <runtime>
      <library name="hello.jar"/>
   </runtime>

 

要创建 hello.jar 文件,我们可以通过突出显示项目名称,并从 Eclipse 菜单选择 File=>Export,以导出插件文件。选择 JAR 文件作为导出方式,按 Next,然后浏览到我们为它创建的目录。下一步,我们还需要将 plugin.xml 文件复制到这个目录。也可以使用File=>Export 菜单选项(但请要记住选择 File System 作为导出目的地)。

这就是安装插件所需的全部操作,但您将需要停止并重新启动 Eclipse,以便能识别这个新的插件。从帮助菜单中选择“About Eclipse Platform”,可以找到关于已安装插件的信息,包括版本号。在出现的屏幕上有一个按钮是 Plug-in Details;向下滚动列表来寻找 Hello 插件及其版本号。

更新插件版本

在目录名称中包含版本号的目的是允许在同一台机器上共存某个插件的多个版本(每次只装入一个版本)。我们可以通过创建一个 Hello 插件的已更新版本来看看这是如何工作的:例如,将 plugin.xml 文件中的版本号更改成“1.0.1”,然后将 SampleAction.java 中的文本更改成“New and improved Hello, Eclipse world”。从 Eclipse 菜单中选择 Project=> Rebuild All。下一步,将项目文件以 JAR 形式导出到新的插件目录,例如,com.example.hello_1.0.1。将修订过的 plugin.xml 文件复制到同一个目录中。当停止并重新启动 Eclipse 时,只会装入已更新的插件。

插件片段和功能部件

Eclipse 由插件组成,但在开发 Eclipse 的插件时,还要慎重考虑另外两个级别的组件 ― 插件片段和功能部件。

插件片段(如名称所暗示的)是完整插件的组成部分 ― 目标插件。片段提供的功能与目标插件的功能合并。片段可以用于将插件本地化成各种语言;在无需形成一个全新发行版的情况下,以增量形式将功能部件添加到现有插件,或者提供特定于平台的功能。在许多方面,片段与插件一样。主要的区别就是片段没有插件类 ― 片段的生命周期由其目标插件管理。此外,片段的清单文件叫作 fragment.xml,它列出了目标插件的标识和版本号,以及片段的标识和版本号。

另一方面,插件功能部件根本不包含编码。在 Eclipse 体系结构术语中,功能部件是将一组相关插件打包到完整的产品中。例如,JDT 是包含了象 Java 编辑器、调试器和控制台这样的插件的功能部件。名为 feature.xml 的清单文件描述了一个功能部件归档文件。在其中,该清单文件包含了对该功能部件所包含的插件和其它资源的引用、关于如何更新该功能部件的信息、版权信息和许可证信息。

在 Eclipse 中,主功能部件设置了 Eclipse 平台的外观。主功能部件旨在确定诸如给予 Eclipse 其身份的闪屏和其它特征之类的东西。Eclipse 只允许一个主功能部件。用这种方式,通过创建一组插件,将它们打包到功能部件中,并且使这个功能部件成为主功能部件,就可以重新创建 Eclipse 的品牌,并将它用于创建全新且不同的产品。如果从 Eclipse.org 下载,缺省主功能部件是eclipse.org.platform

后续步骤

在插件的介绍里我们只是稍微了解一些插件的必要用法。学习插件的更多知识的最佳参考资料是 Plug-in Developer’s Guide,可以从 Eclipse 中的帮助菜单中获得该指南。该文档包含了编程指南、Eclipse API 和插件扩展点的参考大全、Eclipse.org 上可用的编程示例的指南,以及常见问题列表。另一个优秀参考资料是 Eclipse 本身的源代码。根据您的兴趣,您也许想要查找一些示例,以了解不同工作台功能部件(如视图和编辑器)是如何扩展的,或者如何使用 SWT(Eclipse 图形 API)。此外,下面的参考资料可以帮助您学到更多知识。

 

参考资料

关于作者

David Gallardo 是一名独立软件顾问和作家,他的专长是软件国际化、Java Web 应用程序和数据库开发。他成为专业软件工程师已经有十五年了,他拥有许多操作系统、编程语言和网络协议的经验。他最近在一家企业对企业电子商业公司 TradeAccess, Inc 从事先进的数据库和国际化开发。在这之前,他是 Lotus Development Corporation 的 International Product Development 组中的高级工程师,负责开发为 Lotus 产品(包括 Domino)提供 Unicode 和国际语言支持的跨平台库。可以通过 david@gallardo.org与 David 联系。

 

原文地址:http://www.ibm.com/developerworks/cn/java/os-ecplug/

说说Stack Overflow和Quora

今天看到一个新闻,Quora的中国克隆“知乎”得到了创新工场的投资。我之前从创新工场的投资经理张亮那里要到了一个知乎邀请码,最近一直泡知乎,觉得Quora类的产品有很多创新的亮点,所以比较感兴趣这类产品,忍不住就谈谈。

Stack Overflow(以下简称SO)和Quora虽然都是知识问答类的网站,但是他们有共同的成功基因,也有本质的差别。

先说SO和Quora共同成功基因,那就是:用户身份的真实性和唯一性。

我看过不少关于SO和Quora如何成功的很多讨论,各种说法都有:如说SO的SEO很好,SO的积分激励机制如何如何,Quora的种子用户运营如何如何等等。其实这些原因都对,但不是最根本的原因。真正根本的原因在于:用户身份的真实性和唯一性。

我们国内做社区网站,特别是知识型社区网站,核心的竞争力就是高质量的内容。如何获取高质量内容的手段自然多种多样,但是当社区成长起来以后,特 别是用户量急剧膨胀以后,很难避免社区的水化,大量低水平用户,特别是不负责任的用户随意的发帖、发言和评论,会破坏整个社区的内容质量,造成劣币驱逐良 币的现象,最终毁掉这个社区。

这个现象是社区特别是BBS型社区的发展宿命,JavaEye也面临这个问题,早先几年采取的运营手段可以称之为“堵”,惩罚低水平用户的发帖, 恐吓不负责任的行为。但是随着社区规模不断的扩大,注册用户数量越来越多(已经超过70万注册用户,每天UV有25万以上),堵的手段成本越来越高,有效 性越来越低,因此必须改变运营方式。我想到的一个办法就是BBS产品创新,而且是大胆的产品创新。不过这个话题不是本文的主题,我以后会另外撰文。总之这 是一个社区需要解决的大问题。

而SO和Quora很巧妙的解决了这个问题,办法就是:不提供网站账号注册功能,必须通过你在互联网的得到公认的唯一身份标识来登录网站,例如必 须使用你的Google帐户,Facebook帐户,或者Twitter帐户登录。这样的做法就保证了用户使用真实的身份,而且身份是唯一的。

真实而且唯一的身份保证了你必须对自己的发言负责任,保证了你不可能养很多马甲,保证了你必须深思熟虑的行为,确保你自己的网络身份和信誉。特别 是通过Facebook帐户登录以后,可以连带你的好友关系一起导入进来,让你在这个网站的种种行为在你的众多好友的注视之下,更加不可能胡作非为,而且 有了好友关系以后,天然的可以增加网站的用户关系和黏性。

很多人可能以为外国人就是网络素质高,不会像中国人那样网络随地大小便。其实不然,我去过很多国外的小论坛,用phpbb搭建的BBS里面,包括 TSS,照样是Help! Urgent!满天飞,和国内的论坛标题党绝对有的一比。但是一旦用你的真实和唯一身份登录,老外也马上规规矩矩起来,特别是Facebook,外国很多 人就是拿Facebook当作个人的网络通讯录来用的,这个东西有点像国内的MSN。你敢在你的MSN上面对着好友说那些很不着调的话吗? 所以那些SO和Quora上面的人确实就不会乱来。这就是真实而且唯一身份带来的威力。

不过可惜的是,明知这一点,但国内的网站是绝对抄不到手的,因为国内没有一个具有像Facebook这种占据统治地位的真实身份和用户关系,并且 彻底开放的SNS好友关系平台的存在。这也是国内互联网行业的悲哀之处,国外的互联网基础设施实在太好了,AWS,PAAS,连SNS平台的海量用户都现 成,你只要有想法,会写代码,一堆基础设施拿来就用,三两下,一个创新型应用平地而起,这也是为什么硅谷创业公司这么流行Ruby on rails的原因(呀,跑题了)。

总之,你没有这种海量的真实唯一用户导入,就算你的运营水平和产品做很好,也长不成SO和Quora。说到这里,Facebook现在真的成长为 下一代互联网应用的基础设施了,以后做网站真没有必要搞自己的帐户系统了,直接Facebook账号登录搞定,所以Facebook估值到800亿美刀不 算夸张,什么叫基础设施啊朋友,baidu这种烂货都400亿刀了。(又跑题了)

所以,我并不太看好知乎这个产品的前景,目前严格的邀请准入制迟早要改变的,到时候用什么手段来解决这个问题呢? 我认为根本无解,或者说如果有解的话,产品形态必须做出重大的改变,那样的话,从一开始就不应该照着Quora的样子去长。

然后说说SO和Quora的差异在于:知识的组织方式:以内容组织结构为基础,还是以用户关系为基础

其实SO和Quora的差异还是很大的,从目前Google Adplanner来看,SO的UV和PV大致是Quora的5倍,考虑到SO只是一个纯技术网站,这个差距不可谓不小。但是这个不重要,重要的你怎么理解“知识”的组织方式:

SO是一个标准的内容型社区,不需要登录就可以访问,用tag和search良好的组织整个网站的知识体系,在这个基础上添加用户关系和用户身 份。而Quora是一个标准的Social型的社区,不登录对不起,什么都看不到,登录以后你没有用户关系,还是对不起,什么都看不到,你获取信息要依赖 于你的用户关系之上,用户关系决定了你获取信息的效率。

我们说问答这种知识沉淀的方式包含了两种需求: 沉淀知识需求和快需求:

什么是快需求? 我就是来找答案的,别TMD的让我自己搜索半天,然后自己摸索,我就是等着你喂我,我不想费任何力气自己去找答案。其实绝大多数中国的论坛充斥的都是这种 快需求的帖子,而满足这种快需求最好的产品形态就是百度知道,没有唯二的了。我不知道如何形容我对百度知道的仰慕之情,以致于我抄袭了百度知道,做了一个 JavaEye问答频道,而且强迫性的不允许JavaEye用户在论坛发提问贴,必须给我到问答频道提问,而且我还老搞问答大赛,刺激答题者的热情,重点 不在于问题是否重复的问,而在于你答题是否及时有效,这就是旗帜鲜明的满足快需求而去的。

SO也好,Quora也罢,可以满足一部分的快需求,但是从产品形态来说,他们主要不是为了满足快需求而量身打造的产品。快需求有一个很大的特 点,就是并不需要回答的内容是高质量的,反而对实效性要求可能稍微高一些,因此这种产品真的不需要特别的追求回答的质量多高,只要能够快速满足提问者的需 求就OK了。

那么沉淀型需求呢? 沉淀型需求做的最好的产品其实是wikipedia,基本上你可以找到大多数各个领域的知识。当然wikipedia不能覆盖所有的知识领域,一些知识需 要通过问答的形态来组织,因此SO也做的不错。沉淀型需求对内容的质量有要求,越是高质量的内容,越能够加强社区的竞争力和黏性。所以你会看到不管是 SO,Quora还是很多知识型社区的一个基本诉求就是:内容的质量。

这里,我们要更加深入的思考一个问题: 什么叫做高质量的内容? 你如何评判一个内容的质量高低与否?

一篇学术论文,只有几个教授评审,然后永远的束之高阁,它是高质量内容否?
一个李宇春发的微博,被几万粉丝转发,它是高质量内容否?

你肯定本能的说,被束之高阁的学术论文是高质量内容,明星的脑残微博是低质量内容。错!我要告诉你的是在这两个例子中,被几万粉丝转发的明星脑残微博才是高质量内容。为什么?

互联网内容的质量高低并不是由字数多寡来判断的,而是由它的传播范围和影响范围来决定的! 传播的越广,传播的受众越精确,影响的群体越多,内容的质量就越高,这是由互联网的媒体特性来决定的。

从这一点来衡量,SO的内容组织架构显然更加有利于内容的传播,所以它的内容质量就更高,而Quora的Social组织架构对于内容的传播并不是特别有利,即便对于传播受众的精确性也未必能够做到比SO更高,因此我不认为Quora是一个比SO更好的产品形态。

总之我个人不是很看好Quora这类产品的前景,当然我个人的看法也很可能出错,Quora的产品创新还是很多的,给了我很多的BBS产品创新的启发。

 

原文地址:http://robbin.javaeye.com/blog/978077

resin-pro-4.0.16 破解版下载(resin pro 4.0.16 full crack)

resin-pro-4.0.16 破解版下载地址!

 

resin pro 4.0.16 Full Cracked download.

仅供学习使用,请在下载后24时间内删除。

 

resin-pro-4.0.15 破解版下载(resin pro 4.0.15 full crack)

resin-pro-4.0.15 破解版下载地址!

 

resin pro 4.0.15 Full Cracked download.

仅供学习使用,请在下载后24时间内删除。

 

命令行查看Memcached运行状态

很多时候需要监控服务器上的Memcached运行情况,比如缓存的查询次数,命中率之类的。但找到的那个memcached-tool是linux下用perl写的,我也没试过windows能不能用。后来发现个简单的办法可以做到,就是使用Telnet。

首先登录到服务器,然后在cmd命令行中键入

telnet 127.0.0.1 11211

其中127.0.0.1是服务器的地址(这里是本机) ,11211是memcached绑定的端口号。

之后命令行窗口全黑只有光标提示,摸黑输入stats,即可得到描述Memcached服务器运行情况的参数。如下图:

shell中查看Memcached状态

其中,uptime 是memcached运行的秒数,cmd_get是查询缓存的次数。这两个数据相除一下就能得到平均每秒请求缓存的次数——最近niupu的流量很低,所以平均也就一秒请求一次多,这么点大的压力,用文件系统缓存一样没问题,根本不会体现出使用memcached的优越。

下面的cmd_set 就是设置key=>value的次数。整个memcached是个大hash,用cmd_get没有找到的内容,就会调用一下cmd_set写进缓存里。紧跟着是get_hits,就是缓存命中的次数。缓存命中率 = get_hits/cmd_get * 100%。

下面的get_misses的数字加上get_hits应该等于cmd_get。而total_itemscurr_items表示现在在缓存中的键值对个数,在图上total_items == cmd_set == get_misses,不过当可用最大内存用光时,memcached就会删掉一些内容,上面的等式就不成立了

 

MongoDB 1.8通过Journaling日志改善可靠性​

面向文档的数据库引擎MongoDB在3月16日发布了1.8版本。关键的变更包括新增Journaling日志、提升分片性能以及Shell的Tab​补全。​

Journaling日志通过预写式的Redo日志为MongoDB增加了额外的可靠性。开启该功能时,变更会先写入Journaling日志,​ 定期集中提交(目前是每100ms提交一次)​,然后在真实数据上进行这些变更。如果服务器安全关闭,日志会被清除。在服务器启动时,如果存在 Journaling日志​,则会进行回放。这保证了那些已写入,但在服务器崩溃前还没有回放的​日志能在用户连接前​被执行。​两次提交之间那 100ms的时间窗口​在未来的版本中有望被缩小。

MongoDB是​一种 NoSQL数据库​,不同于SQL Server这样的关系型数据库,MongoDB中数据的基本单位是文档。类似于JavaScript对象,文档中包含一系列带有类型的键值对​,这些类型可以是字符串、对象、数组、正则表达式和代码。​这些文档以​BSON格式存 储​,根据文档类型被分组到集合(类似于SQL Server里的表)中​。Schema的设计取决于哪些文档应该有自己的集合​,哪些应该被嵌入到其他集合中去。嵌入的文档就像类里的成员对象。在关系 型系统中,你会用一张表来存储订单,另一张外键的表来存储订单项。在MongoDB中,​针对同样的场景,推荐的做法是用一个集合来保存订单,每个订单中 保存一个订单项的数组,嵌入其中。​

水平扩展是通过​自动分片来 ​做的​,​它允许有序的集合数据分布。每个分片都是一组配置成Replica集的机器​,这意味着分片里的每台机器​都拥有分片数据的完整拷贝。​分片 中会自动进行故障转移。MongoDB会自动将查询引导到合适的分片上,因此应用程序并不需要了解哪个分片持有什么数据元素。​新的Replica集身份 认证功能允许Replica集的成员之间进行自动身份认证,其中使用了密钥文件和 –keyfile 选项。​

Covered索引和Sparse索引也是该版本中新增加的特性。​Covered索引允许​在索引本身里存储数据,而​Sparse索引则会排除掉不包含索引字段的文档。Covered索引在查询所请求的全部字段​都包含在Covered索引中时能提升性能,因为不再需要取出完整的文档记录。Sparse索引在所检索的字段并非经常出现在集合中时能提升性能。目前,Sparse索引只能有一个字段。​

在MongoDB的工具集中也有一些变化。mongostat 增加了​discover模式(–discover)​,它会自动从集群的节点中取回统计信息。​通过mongodump –oplogmongorestore –oplogReplay提供了高级事务日志转储和恢复​功能。​

欲更多地了解该版本中的新特性,请查看MongoDB 1.8 Webinar

查看英文原文:MongoDB 1.8 Improves Reliability with Journaling

 

舊街市模型

在山頂廣場,見一唐樓展覽,有一些街市模型,做得很精緻。

20110327_Peak037

20110327_Peak039

20110327_Peak038

20110327_Peak043

20110327_Peak044

20110327_Peak040

20110327_Peak042

 

JQuery 1.5.2 RC 1 发布

JQuery 1.5.2 RC 1 发布!如果没有重大缺陷发生,3月31日就将发布jQuery 1.5.2正式版了。

该版本主要是bug的修复,没有新功能发布。

详细更新日志:http://blog.jquery.com/2011/03/24/jquery-1-5-2-rc-1-released/

下载地址:http://code.jquery.com/jquery-1.5.2rc1.js

Ruby on Rails with Nginx on CentOS 5

Ruby on Rails is a popular rapid development web framework that allows web designers and developers to implement fully featured dynamic web applications using the Ruby programming language. This guide describes the required process for deploying Ruby on Rails with Passenger and the nginx web server on CentOS 5.

 

These instructions work with the Linode platform. If you don’t have a Linode yet, sign up for a Linux VPS and get started today.

Contents
Install Required Packages
Install Passenger and Nginx
Set up an Init Script for Nginx
Install MySQL Support (optional)
More Information
License

Install Required Packages

Make sure your system is up to date by issuing the following command:

yum update

Issue the following series of commands to install packages required for Ruby on Rails.

yum groupinstall "Development Tools"
yum install zlib-devel wget openssl-devel pcre pcre-devel make gcc gcc-c++ curl-devel

The version of Ruby in the CentOS repositories is fairly old; we’ll need to download and compile it ourselves. Check the Ruby language siteExternal Link for a link to the newest stable version and substitute it for the link shown below. Execute the following sequence of commands to get Ruby installed.

cd /opt
wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p376.tar.gz
tar -zxvf ruby-1.9.1-p376.tar.gz
cd ruby-1.9.1-p376
./configure --bindir=/usr/bin --sbindir=/usr/sbin/
make -j3
make install

Now we’ll need to install gems. Issue the following series of commands to download and install a fresh version. You may wish to check the RubyForge files pageExternal Link for the most recent version.

cd /opt
wget http://production.cf.rubygems.org/rubygems/rubygems-1.5.1.tgz
tar -zxvf rubygems-1.5.1.tgz
cd /opt/rubygems-1.5.1/
ruby setup.rb

Update rubygems:

gem update --system

Install the rakerack, and fastthread gems:

gem install rake rack
gem install fastthread --no-rdoc --no-ri

Install Passenger and Nginx

Proceed to the Phusion PassengerExternal Link site and locate the link for the current source code tarball. Download it as follows (substitute the link for the current version):

cd /opt
wget http://rubyforge.org/frs/download.php/73563/passenger-3.0.1.tar.gz
tar xzvf passenger-3.0.1.tar.gz

Run the Phusion Passenger installer for Nginx:

cd /opt/passenger-3.0.1/bin
./passenger-install-nginx-module

You’ll be greeted by the Phusion Passenger Nginx installer program. Press “Enter” to continue with the installation.

Phusion Passenger Nginx installer program running on CentOS 5.When prompted for the Nginx installation method, we recommend you choose “1” to allow the installer to automatically download, compile, and install Nginx for you. Unless you have specific needs that would necessitate passing custom options to Nginx at compile time, this is the safest way to proceed.

Please do not remove the Passenger files from opt after the install. They need to stay in place or your install will not function correctly.

Set up an Init Script for Nginx

Nginx is now installed in /opt/nginx, but there are no “init” scripts to control this process. Issue the following sequence of commands to download a script, move it to the proper directory, set the proper permissions and set system startup links:

cd /opt
wget https://library.linode.com/frameworks/ruby-on-rails-nginx/reference/init-rpm.sh
mv /opt/init-deb.sh /etc/rc.d/init.d/nginx
chmod +x /etc/rc.d/init.d/nginx
chkconfig --add nginx
chkconfig nginx on

You can now start, stop, and restart Nginx just like any other server daemon. For example, to start the server, issue the following command:

/etc/init.d/nginx start

You can now start, stop, and restart Nginx just like any other server daemon. For example, to start the server, issue the following command:

/etc/rc.d/init.d/nginx start

If you haven’t already configured your firewall to allow inbound HTTP connections, run the following command to do so now:

system-config-securitylevel-tui

The configuration file for Nginx is located at /opt/nginx/conf/nginx.conf. This is the file you’ll need to edit to add support for your Rails applications. A default server is already configured in this file, and it also contains examples for alternate virtual host and SSL configurations.

Install MySQL Support (optional)

If your application uses MySQL, install the database server by following our MySQL on CentOS 5 guide. Once it’s installed and configured properly, issue the following commands:

yum install mysql-devel
gem install mysql --no-rdoc --no-ri -- --with-mysql-dir=/usr/bin --with-mysql-lib=/usr/lib/mysql --with-mysql-include=/usr/include/mysql

 

More Information

You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.