[转载]Android服务之Service(其一)

mikel阅读(982)

[转载]Android服务之Service(其一) – 东子哥 – 博客园.

Android中服务是运行在后台的东西,级别与activity差不多。既然说service是运行在后台的服务,那么它就是不可见的,没有界面 的东西。你可以启动一个服务Service来播放音乐,或者记录你地理信息位置的改变,或者启动一个服务来运行并一直监听某种动作。

Service和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的请求或者动作。你可以在服务中开一一个线程,在线程中做耗时动作。

那么究竟Service怎么使用呢?

老规矩,先来点基础知识。

一.基础知识

服务一般分为两种:

1:本地服务 Local Service 用于应用程序内部。在Service可以调用Context.startService()启动,调用Context.stopService()结束。 在内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次 stopService()来停止。

2:远程服务, Remote Service 用于Android系统内部的应用程序之间。可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服 务。调用Context.bindService()方法建立连接,并启动,以调用 Context.unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加 载它。
提供给可被其他应用复用,比如定义一个天气预报服务,提供与其他应用调用即可。

那么先来看Service的生命周期吧:如图:


context.startService() ->onCreate()- >onStart()->Service running–调用context.stopService() ->onDestroy()

context.bindService()->onCreate()->onBind()->Service running–调用>onUnbind() -> onDestroy() 从上诉可以知道分别对应本地的,,以及远程的,也对应不同的方式启动这个服务。

二.实战

我们可以定义一个本地服务继承Service,然后在这个服务里播放媒体播放器或者记录地理位置变化。通常有时候我们的Service 要与Activity交互,那么可以可以定义一个内部类,返回这个Service,当然我们要考虑到如果是以绑定方式启动服务,那么内部类可以定义为继承 Binder,然后返回本地服务,具体代码如下。

View Code

package com.dongzi;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class LocalService extends Service {

    private static final String TAG = "LocalService"; 
    private IBinder binder=new LocalService.LocalBinder();
    
    @Override
    public IBinder onBind(Intent intent) {
         
        return binder;
    }
    MediaPlayer mediaPlayer=null;
    @Override 
    public void onCreate() { 
            Log.i(TAG, "onCreate"); 
            //这里可以启动媒体播放器
           // if(mediaPlayer==null)
           //     mediaPlayer=MediaPlayer.create(this, uri);
            super.onCreate(); 
    } 

    @Override 
    public void onStart(Intent intent, int startId) { 
            Log.i(TAG, "onStart"); 
            super.onStart(intent, startId); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
          Log.i(TAG, "onStartCommand"); 
        return START_STICKY;
    }

    
    
    @Override 
    public void onDestroy() { 
            Log.i(TAG, "onDestroy"); 
            super.onDestroy(); 
    } 

    
    //定义内容类继承Binder
    public class LocalBinder extends Binder{
        //返回本地服务
        LocalService getService(){
            return LocalService.this;
        }
    }
    
    
}

我们可以从上面知道

//定义内容类继承Binder
public class LocalBinder extends Binder{
//返回本地服务
LocalService getService(){
return LocalService.this;
}
}

可以返回这个服务,然后activity可以通过服务调用服务的方法了。

那么如何启动服务呢?从上面基础知识中,我们知道有2种方法,如下:

View Code

  //启动服务
    private void startCustomService(){
         Intent intent=new Intent(this,LocalService.class);
         startService(intent);
    }

第2种绑定方式:

View Code

LocalService localService=null;
    //用bindService方法启动服务
    private void BinderService(){
         Intent intent=new Intent(this,LocalService.class);
         bindService(intent, new ServiceConnection(){
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder binder) {
                //调用bindService方法启动服务时候,如果服务需要与activity交互,
                //则通过onBind方法返回IBinder并返回当前本地服务
                localService=((LocalService.LocalBinder)binder).getService();
                //这里可以提示用户,或者调用服务的某些方法
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                localService=null;
                //这里可以提示用户
            }     
         }, Context.BIND_AUTO_CREATE);
    }

在绑定服务的时候,需要一个服务连接对象,ServiceConnection,服务一旦连接,就会调用 onServiceConnected方法,我们可以在这个方法里面返回我们的本地服务对象,具体看代码;而在服务断开时候会调用 onServiceDisconnected方法,我们可以清理一些服务资源。

[转载]Java的动态绑定机制

mikel阅读(927)

[转载]Java的动态绑定机制 – eric.dream – 博客园.

Java的动态绑定又称为运行时绑定。意思就是说,程序会在运行的时候自动选择调用哪儿个方法。

一、动态绑定的过程:

例子:

1 public class Son extends Father
2 Son son = new Son();
3 son.method();

1. 首先,编译器根据对象的声明类型和方法名,搜索相应类(Son)及其父类(Father)的“方法表”,找出所有访问属性为public的method方法。

可能存在多个方法名为method的方法,只是参数类型或数量不同。

2. 然后,根据方法的“签名”找出完全匹配的方法。

方法的名称和参数列表称为方法的签名。

在Java SE 5.0 以前的版本中,覆盖父类的方法时,要求返回类型必须是一样的。现在子类覆盖父类的方法时,允许其返回类型定义为原始类型的子类型。

1 public Father getFather(){...}  //父类中的方法
2 public Son getFather(){...}     //子类覆盖父类中的getFather()方法

3. 如果是private、static、final 方法或者是构造器,则编译器明确地知道要调用哪儿个方法,这种调用方式成为“静态调用”。

4. 调用方法。

如果子类Son中定义了 method() 的方法,则直接调用子类中的相应方法;如果子类Son中没有定义相应的方法,则到其父类中寻找method()方法。

二、Demo

1. 子类重写父类中的方法,调用子类中的方法

 1 public class Father{
 2     public void method(){
 3         System.out.println("父类方法:"+this.getClass());
 4     }
 5 }
 6 public class Son extends Father{
 7     public void method(){
 8        System.out.println("子类方法"+this.getClass());
 9     }
10     public static void main(String[] args){
11         Father instance = new Son();
12         instance.method();
13     }
14 }
15 //结果:子类方法:class Son

2. 子类没有重写父类中的方法,所以到父类中寻找相应的方法

public class Father{
    public void method(){
        System.out.println("父类方法:"+this.getClass());
    }
}
public class Son extends Father{
    public static void main(String[] args){
        Father instance = new Son();
        instance.method();
    }
}
//结果:父类方法:class Son

三、动态绑定只是针对对象的方法,对于属性无效。因为属性不能被重写。

 1 public class Father{
 2     public String name = "父亲属性";
 3 }
 4 public class Son extends Father{
 5     public String name = "孩子属性";
 6 
 7     public static void main(String[] args){
 8         Father instance = new Son();
 9         System.out.println(instance.name);
10     }
11 }
12 //结果:父亲属性

[转载]git/github初级运用自如

mikel阅读(1007)

[转载]git/github初级运用自如 – 虫师 – 博客园.

之前初学过一点git版本控制工具,利用github做仓库,照着github上的文档练习的了一下。不过那只篇只是照虎画猫(我的水平只能照着老虎画个猫模样,嘻嘻!)。

最近在学hibernate,公司与家之间都要调用我练习的小项目,交给git/github来管理,我只想说真的爽歪歪了。

本文在我之前的那篇《git/github学习笔记》的基础上,属于那个的升级加强版,欢迎对照阅读:http://www.cnblogs.com/fnng/archive/2011/08/25/2153807.html

如果本文有不太明白的地方请参考上面的文章。

Github: git项目托管网站,请先免费申请一个github帐号:www.github.com

Git:分布式版本控制工具,http://d.download.csdn.net/down/3169511/z_y_liu89

Github的申请与git的安装我这里就不说了。这个不难。

----//git/github环境配置

一 .  github上创建立一个项目

用户登录后系统,在github首页,点击页面右下角“New Repository”

填写项目信息:

project name: hibernate-demo

description : my first project

点击Create Repository; 现在完成了一个项目在github上的创建。

说明:我们创建的是一个github仓库,一个仓库里只能存放(或叫对应)一个项目。

当你创建完成一个仓库的之后,github已经给你一个提示:当你看完了我的文章再来看这个提示就非常清楚了。

Global setup:
 Set up git
  git config --global user.name "Your Name"
  git config --global user.email defnngj@gmail.com
      
Next steps:
  mkdir hibernaet-demo2
  cd hibernaet-demo2
  git init
  touch README
  git add README
  git commit -m 'first commit'
  git remote add origin git@github.com:defnngj/hibernaet-demo2.git
  git push -u origin master
Existing Git Repo?
  cd existing_git_repo
  git remote add origin git@github.com:defnngj/hibernaet-demo2.git
  git push -u origin master
Importing a Subversion Repo?
  Click here 
When you're done:
  Continue

二  .  创建密钥

我们如何让本地git项目与远程的github建立联系呢?之里就用的密钥。通俗点叫口令吧!(天王盖地老,宝塔镇河妖。。)

$ cd ~/. ssh 检查本机的ssh密钥

如果提示:No such file or directory 说明你是第一次使用git

如果不是第一次使用,请执行下面的操作,清理原有ssh密钥

 $ mkdir key_backup
 $ cp id_rsa* key_backup
 $ rm id_rsa*

生成新的密钥:

Ssh-keygen –t rsa –C “defnngj@gmai.com”

注意: 此处的邮箱地址,你可以输入自己的邮箱地址。在回车中会提示你输入一个密码,这个密码会在你提交项目时使用,如果为空的话提交项目时则不用输入。这个设置是防止别人往你的项目里提交内容。

打开本地C:\Documents and Settings\Administrator\.ssh\id_rsa.pub文件。此文件里面内容为刚才生成人密钥。

登陆github系统。点击右上角的 Account Settings—>SSH Public keys —> add another public keys

把你本地生成的密钥复制到里面(key文本框中), 点击 add key ok

git中运行下面命令:

$ git –T git@github.com

如果提示:Hi defnngj You’ve successfully authenticated, but GitHub does not provide shell access. 说明你连接成功了

三 . 设置用户信息

这一步不是很重要,貌似不设置也行,但github官方步骤中有,所以这里也提一下。

git中设置用户名,邮箱

$ git config --global user.name "defnngj"//给自己起个用户名
$ git config --global user.email  "defnngj@gmail.com"//填写自己的邮箱


github中找到 Account Settings—>Account Admin ,找到一下信息:

Your API token is e97279836f0d415a3954c1193dba522f —keep it secret! Changing your password will

generate a new token

$ git config --global github.user defnngj      //github 上的用户名
$ git config --global github.token e97279836f0d415a3954c1193dba522f

----//小玩一下git

上面都是准备工作,一次完成,以后就不用设置了。下面内容才是亮点。

先来说说git下常用的几个基本操作,和linux系统的操作是一样一样的:

$ ls   查看当前目录的内容

$ cd  /d   切换到d盘

$ cd  java/   打开当前目录下的java目录

$ cd  j(table键)  如果当你想打开java目录且当前目录下只有一个j开头的目录,输入J 然后按键盘上的table键,会自动帮你补齐。

$ cd ..  返回上一级目录

假如你现在新创建了一个项目,想把它提交到github上面?

假设你创建好了一个项目,并切换到项目的根目录下面:

$ git status //查看当前项目下所有文的状态,如果第一次,你会发现都红颜色的,因为它还没有交给git/github管理。

$ git add . //.)点表示当前目录下的所有内容,交给git管理,也就是提交到了git的本地仓库。

Ps:git的强大之处就是有一个本地仓库的概念,在没有网络的情况下可以先将更新的内容提交到本地仓库。

$ git commit –m”new natter ” //对你更新或修改了哪些内容做一个描述。

$ git remote add origin git@github.com:defnngj/hibernate-demo.git

//如果你是第一次提交项目,这一句非常重要,这是你本地的当前的项目与远程的哪个仓库建立连接。

Psorigin可以改为别人的名字,但是在你下一次push(提交)时,也要用你修改之后的名字。

$ git remote -v //查看你当前项目远程连接的是哪个仓库地址。

$ git push -u origin master //将本地的项目提交到远程仓库中。

————————————————————

假如,你回到了家,想把公司提交的项目克隆到本地?

如果你是第一次想把github上面的项目克隆到本地或者要克隆别人的项目到地。

$ git clone git@github.com:defnngj/hibernate-demo.git //在git下面切换到想存放此项目的文件目录下,运行这条命令就可以将项目克隆下来。

假如本地已经存在了这个项目,而仓库中又有一新的更新,如何把更的合并到本地的项目中?

$ git fetch origin //取得远程更新,这里可以看做是准备要取了

$ git merge origin/master //把更新的内容合并到本地分支/master

——————————————-

项目中删除了一些文件,如何提交?

假如远程仓库中已经存了aaa这个文件,我fetch了下来,并删除了aaa这个文件,想再push上到远程仓库中,并使远程仓库中的项目被新的修改覆盖(也是是远程仓库中的aaa也被删除)

$ git status //可以看到我们删除的哪些文件

$ git add . //删除之后的文件提交git管理。

$ git rm   src/com/hzh/hibernate/dao/aaa.java //移除我们删除的那个文件,不然git不允许我们往远程仓库提交。

Ps: 如果你想删除的是某个目录(java包),这里想移除整个目录的内容。

$ git rm  src/com/hzh/hibernate/bbb/ -r // -r 会把bbb/目录下的所有内容一次性移动。

————————————————————————

远程创建了一个新仓库,本地创建了一个新项目,如何使新的项目与仓库对应起来?

其实,这个也很简单,只是我当时对那些命令不太理解,所以比较模糊,不知如何对应。

$ git remote add origin git@github.com:defnngj/hibernate-demo.git

//还是这个命令,在你push项目之前加上这一句就OK了。

git@github.com:defnngj/hibernate-demo.git 就是你常见的新仓库的地址啊。git切换到新项目下,在push之前,加上这一句,我们创建的新仓库就与新项目建立了连接。

[转载]CURD - 使用 Transact-SQL 的 select 语句查询数据 (二):在查询中使用普通函数和聚集函数

mikel阅读(1062)

[转载]CURD – 使用 Transact-SQL 的 select 语句查询数据 (二):在查询中使用普通函数和聚集函数 – MicroStone – 博客园.

– 常用字符串函数:
— CharIndex:用来寻找一个指定字符串在另一个字符串中的起始位置
select CHARINDEX(‘朱磊’,’我的名字叫朱磊’,1)

— Len:返回传递给它的字符串长度
select LEN(‘我的名字叫朱磊’)

— Upper:把传递给它的字符串转换为大写
select UPPER(‘my name is zhulei’)

— Ltrim:清楚字符串左边的空格
select LTRIM(‘   hello’)

— Rtrim:清楚字符串右边的空格
select RTRIM(‘   hello   ‘)

— Right:从字符串右边返回指定数目的字符
select RIGHT(‘MicroStone’,5)

— Replace:替换一个字符串中的字符
select REPLACE(‘中华人民万岁’,’万’,’亿’)

— Stuff:在一个字符串中,删除指定长度的字符,并在该位置插入一个新的字符
select STUFF(‘ABCDEFG’,3,2,’朱磊’)

— 常用日起函数:
— GetDate:取得当前的系统日期
select GETDATE()

— DateAdd:将指定的数值添加到指定的日期部分后的日期
select DATEADD(dd,5,’03/12/2011′)

— DateDiff:两个日期之间的指定日期部分的区别
select DATEDIFF(mm,’05/23/2011′,’11/23/2011′)

— DateName:日期中指定日期部分的字符串形式
select DATENAME(dw,’01/06/1992′)

— DatePart:日期中指定日期部分的整数形式
select DATEPART(day,’01/06/1992′)

— 常用数学函数:
— Abs:取数值表达式的绝对值
select ABS(-5)

— Ceiling:取大于或等于指定数值、表达式的最小整数 (只要小数位有值就进一位)
select CEILING(33.2)

— Floor:取小于或等于指定表达式的最大整数 (只要有小数就去掉小数位)
select FLOOR(43.5)

— Power:取数值表达式的幂值
select POWER(2,16)

— Round:将数值表达式四舍五入为指定精度
select ROUND(3.1415926,4)

— Sign:判断正负数,正数返回+1,负数返回-1,0就返回0
select SIGN(23)

— Sqrt:去浮点表达式的平方根
select SQRT(9)

— 常用系统函数:
— Convert:用来转变数据类型
select CONVERT(varchar(5),12345)

— Current_User:返回当前用户的名字
select CURRENT_USER

— DataLength:返回用于指定表达式的字节数
select DATALENGTH(‘中国中央村软件园’)

— Host_Name:返回当前用户所登录的计算机的名字
select HOST_NAME()

— System_User:返回当前所登录的用户的名称
select SYSTEM_USER

— User_Name:从给定的用户ID返回用户名
select USER_NAME(1)

— 常用聚合函数:
— Sum:返回表达式中所有数值的总和
select SUM(StuAge) From Students

— Avg:返回表达式中所有数值的平均值
select AVG(StuAge) From Students

— Max:返回表达式中的最大值
select MAX(StuAge) From Students

— Min:返回表达式中的最小值
select MIN(StuAge) From Students

— Count:返回提供的表达式中非空值的计数
select COUNT(*) From ChineseScores where Score > 80

[转载]iis6 伪静态 iis配置方法 图解

mikel阅读(858)

[转载]iis6 伪静态 iis配置方法 图解 – 彦桢 – 博客园.

1.右键点击 要设置网站网站

2.属性 ——》主目录 ——》配置——》

3.如右侧窗口,找到 .aspx 扩展名——》编辑——》复制 可执行文件的路径——》关闭

4.点击 添加——》粘贴 刚复制的 可执行文件路径

5.扩展名填写 .html (如果是 .htm 或者 任意你想要的扩展都可以 前提是以后的应用程序扩展列表里边没有该扩展)

6.不选中 确认文件是否存在

7.确定

如不了解 iis6 web.config 伪静态配置方法 请参考这篇文章

iis6 web.config 伪静态配置方法

http://www.cnblogs.com/yanzhen/archive/2012/01/07/2315534.html大功告成。自认为写的很详细。如有疑问欢迎留言交流


[转载]youku网架构学习笔记

mikel阅读(1020)

[转载]网架构学习笔记 – #知了 – 博客园.

最近在网上溜达时,看到优酷网架构学习笔记,感觉很不错,转过来与大家分享。

记得以前给大家介绍过视频网站龙头老大YouTube的技术架构,相信大家看了都会有不少的感触,互联网就是这么一 个神奇的东西。今天我突然想到,优酷网在国内也算是视频网站的老大了,不知道他的架构相对于YouTube是怎么样的,于是带着这个好奇心去网上找了优酷 网架构的各方面资料,虽然谈得没有YouTube那么详细,但多少还是挖掘了一点,现在总结一下,希望对喜欢架构的朋友有所帮助。

一、网站基本数据概览

据2010年统计,优酷网日均独立访问人数(uv)达到了8900万,日均访问量(pv)更是达到了17亿,优酷凭借这一数据成为google榜单中国内视频网站排名最高的厂商。

硬件方面,优酷网引进的戴尔服务器主要以 PowerEdge 1950与PowerEdge 860为主,存储阵列以戴尔MD1000为主,2007的数据表明,优酷网已有1000多台服务器遍布在全国各大省市,现在应该更多了吧。

二、网站前端框架

从一开始,优酷网就自建了一套CMS来解决前端的页面显示,各个模块之间分离得比较恰当,前端可扩展性很好,UI的分离,让开发与维护变得十分简单和灵活,下图是优酷前端的模块调用关系:

这样,就根据module、method及params来确定调用相对独立的模块,显得非常简洁。下面附一张优酷的前端局部架构图:

三、数据库架构

应该说优酷的数据库架构也是经历了许多波折,从一开始的单台MySQL服务器(Just Running)到简单的MySQL主从复制、SSD优化、垂直分库、水平sharding分库,这一系列过程只有经历过才会有更深的体会吧,就像 MySpace的架构经历一样,架构也是一步步慢慢成长和成熟的。

1、简单的MySQL主从复制:

MySQL的主从复制解决了数据库的读写分离,并很好的提升了读的性能,其原来图如下:

其主从复制的过程如下图所示:

但是,主从复制也带来其他一系列性能瓶颈问题:

  • 写入无法扩展
  • 写入无法缓存
  • 复制延时
  • 锁表率上升
  • 表变大,缓存率下降

那问题产生总得解决的,这就产生下面的优化方案,一起来看看。

2、MySQL垂直分区

如果把业务切割得足够独立,那把不同业务的数据放到不同的数据库服务器将是一个不错的方案,而且万一其中一个业务崩溃了也不会影响其他业务的正常进行,并且也起到了负载分流的作用,大大提升了数据库的吞吐能力。经过垂直分区后的数据库架构图如下:

然而,尽管业务之间已经足够独立了,但是有些业务之间或多或少总会有点联系,如用户,基本上都会和每个业务相关联,况且这种分区方式,也不能解决单张表数据量暴涨的问题,因此为何不试试水平sharding呢?

3、MySQL水平分片(Sharding)

这是一个非常好的思路,将用户按一定规则(按id哈希)分组,并把该组用户的数据存储到一个数据库分片中,即一个sharding,这样随着用户数量的增加,只要简单地配置一台服务器即可,原理图如下:

如何来确定某个用户所在的shard呢,可以建一张用户和shard对应的数据表,每次请求先从这张表找用户的shard id,再从对应shard中查询相关数据,如下图所示:

但是,优酷是如何解决跨shard的查询呢,这个是个难点,据介绍优酷是尽量不跨shard查询,实在不行通过多维分片索引、分布式搜索引擎,下策是分布式数据库查询(这个非常麻烦而且耗性能)

四、缓存策略

貌似大的系统都对“缓存”情有独钟,从http缓存到memcached内存数据缓存,但优酷表示没有用内存缓存,理由如下:

  • 避免内存拷贝,避免内存锁
  • 如接到老大哥通知要把某个视频撤下来,如果在缓存里是比较麻烦的

而且Squid 的 write() 用户进程空间有消耗,Lighttpd 1.5 的 AIO(异步I/O) 读取文件到用户内存导致效率也比较低下。

但为何我们访问优酷会如此流畅,与土豆相比优酷的视频加载速度略胜一筹?这个要归功于优酷建立的比较完善的内容分发 网络(CDN),它通过多种方式保证分布在全国各地的用户进行就近访问——用户点击视频请求后,优酷网将根据用户所处地区位置,将离用户最近、服务状况最 好的视频服务器地址传送给用户,从而保证用户可以得到快速的视频体验。这就是CDN带来的优势,就近访问,有关CDN的更多内容,请大家Google一 下。

[转载]Asp.net MVC 利用PartialView 构造自定义菜单

mikel阅读(1044)

[转载]Asp.net MVC 利用PartialView 构造自定义菜单 – 胡以谦 – 博客园.

在VS2010中利用ASP.NET MVC自带的模板生成的菜单是固定的,没办法更改,下面利用PartialView实现简单的一级菜单。

1) 修改_Layout.cshtml,在<nav>部分改成@{ Html.RenderAction(“Menu”, “Home”);}

<div class="float-right">
<section id="login">
@Html.Partial("_LogOnPartial")
</section>
<nav>
@{ Html.RenderAction("Menu", "Home");}
</nav>
</div>

MVC将会调用HomeController的Menu方法来显示菜单

2)在HomeController里面添加Menu方法,返回PartialView

public PartialViewResult Menu()
 {
            List<MenuItem> menus = new List<MenuItem>();
            menus.Add(new MenuItem{ Text="Home", Controller="Home", Action="Index"});
            menus.Add(new MenuItem { Text = "Job", Controller = "Job", Action = "Index" });
            menus.Add(new MenuItem { Text = "About", Controller = "Home", Action = "About" });
            menus.Add(new MenuItem { Text = "Contact", Controller = "Home", Action = "Contact" });
            return PartialView(new MenuModel { Menus = menus });
  }

3) 定义一个新的PartialView ,名称为Menu.cshtml,基于原来自动生成的代码修改为:

@model MVCDemo.Models.MenuModel
<ul id="menu">
@foreach (var item in Model.Menus)
{
<li>@Html.RouteLink(item.Text, new { controller = item.Controller, action = item.Action })</li>
}
</ul>

利用PartialView可以实现自定义多级菜单,并且权限控制也很容易。

完整代码如下:

http://files.cnblogs.com/huyq2002/MVCDemo.zip

网盘下载

运行该示例可能需要安装ASP.NET MVC4

[转载]Android UI 使用更快更高效

mikel阅读(918)

[转载]Android UI 使用更快更高效 – 华德飞 – 博客园.

之前有谈过如何使用adapter更高效的,现在在谈谈其他的。

一、选择恰当的图像尺寸

视图背景图总是会填充整个视图区域,图像尺寸的不适合会导致图像的自动缩放,为了避免这种情况,我们可以先将图片进行缩放到视图的大小。

originalImage = Bitmap.createScaledBitmap(
originalImage, //被缩放图
view.getWidth(), //视图宽度
view.getHright(), //视图高度
true //双限行过滤器
);

二、去掉不需要的默认窗口背景

在默认情况下,窗口有一个不透明的背景,有时候我们并不需要他,就可以去掉他。因为更新看不见的窗口是浪费时间的。

去掉的方法:

1.代码实现:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //删除窗口背景
        getWindow().setBackgroundDrawable(null);
    }

2.xml里实现:

首先去顶你的res/xml/styles.xml里有

<resources>
  <style name="NoBackGroundTheme" parent="android:Theme">
       <item name="android:windowBackground">@null</item>
</style>
</resources>

然后在你的manifest.xml里声明

<activity android:name="MyActivity" android:theme="@style/NoBackGroundTheme">
 ......
</activity>

三、尽可能的使用简单的布局和视图

如果一个窗口包含很多的视图,那么启动时间长、测量时间长、绘制时间长、布局时间长;

如果视图树深度太深,会导致StackOverflowException异常,和用户界面反映会很慢很慢。
解决的方法:

1.使用TextView的复合drawables,减少层次

如有这样的布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/hello" />
    <Image android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:id="@+id/image" android:background="@drawable/icon" />
</LinearLayout>

我们可以这样来取代他,从而来将少层次:

<TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/hello" android:drawableRight="@drawable/icon"/>

2.使用ViewStub延迟展开视图

默认情况下,使用ViewStub包含的视图是不可见的。

<ViewStub android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/vs" android:layout="@layout/main"/>

这个里面包含的main视图是不会展现出来的,如果需要展现出来需要代码的处理

findViewById(R.id.vs).setVisibility(View.VISIBLE);

或者

findViewById(R.id.vs).inflate();

3.使用<merge>合并视图
默认情况下,布局文件的根作为一个借点加入到父视图中,如果使用<merge>可以避免根节点。

如果最外层的布局是FrameLayout,那么可以使用merge替换掉,引用官方说明:

Obviously, using <merge /> works in this case because the parent of an activity’s content view is always a FrameLayout. You could not apply this trick if your layout was using a LinearLayout as its root tag for instance.

<merge
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
    .....
</merge>

4.使用RelativeLayout减少层次

5.自定义布局

[转载]网友提供Firefox+扩展 15秒网上快速预定火车票教程

mikel阅读(971)

[转载]网友提供Firefox+扩展 15秒网上快速预定火车票教程_Mozilla FireFox_cnBeta.COM.

近日网络上有名为“特种兵—AK47”的技术网友提供了15秒通过订票网站成功预定火车票的教程引发网友热议,该网友在教程中通过FireFox(火狐浏览器 点击下载)及FireBug(火狐浏览器的一种附加插件 点击下载)修改网页相关参数从而实现快速购票。

记者提醒部分欲网上订购火车票的用户,如果你没有使用过FireFox和FireBug请谨慎操作。(完)

附网上购买火车票注意事项:

1、确保网速够快

2、确保迅速完成修改参数步骤(最好提前演练几次)

3、提前在IE-32Bit上登陆系统,以确保及时完成支付

附网上15秒快速购买火车票教程:

1、提前十五分钟(8点放票,我是7点半登的系统),用Firefox(8.01)打开页面:https://dynamic.12306.cn/otsweb/order/querySingleAction.do?method=init

2、提前十分钟,查询能够进入预订页面(预订按钮为激活状态)的同类车次,进入该页面。比如,我想订的是14号T9的硬卧(这个时候还没放出来),但我知道12号的硬座还有票,那么我直接查询12号T9。

(点击查看大图)

3、提前五分钟,用Firebug改好相应的参数,这步非常重要。

3A、修改席别

右键单击 席别 下面的下拉列表,选择 审查元素。

(点击查看大图)

修改 硬座 对应项的值,即将 Value 改为3(3对应的是硬卧)。

(点击查看大图)

3B、修改日期

在之前动态修改的 HTML 代码之上,找到 id 为 start_date 的 INPUT 标记(默认为隐藏),将日期修改为想要预定的时间。

(点击查看大图)

4、提前一分钟,单击(刷新)验证码并填好(注意是只刷新验证码)。

5、提前几秒钟,单击提交订单按钮

[转载]技术宅网上买火车票攻略

mikel阅读(1079)

[转载]技术宅网上买火车票攻略 – Phinecos(洞庭散人) – 博客园.

写在前面

写这篇文章的起因是今天在12306上买火车票时,被这牛逼的网站给震撼到了,靠,牛叉得让人无语的用户体验啊。就讲讲我是如何利用一个小工具做辅助,幸运地抢到了回家的卧铺票的。希望能给有需要的兄弟们做个参考。如果博客园的管理员觉得这和技术无关,请移出首页好了。

回顾下我今天网上购票的全过程,总结起来有四个难关,第一是登陆,第二是预定,第三是提交订单,第四是支付。本文的目的主要是为了在第一和第二关提供一些帮助。

准备工作:

1firefox浏览器

2,油猴脚本扩展GreaseMonkey

(有园友反映这里看不懂啥意思,好吧,特别补充一段。GreaseMonkey是一个firefox扩展,当然,别再问我啥是扩展了,请自行google,简单说,就是装了这个扩展,就可以再它基础上跑一些js脚本,对页面做一些修改什么的。。。,)

先去这个页面下载扩展,https://addons.mozilla.org/zh-cn/firefox/addon/greasemonkey/

下载到本地的是一个xpi文件,将其拖拽进firefox里面,就可以完成扩展的安装,重启firefox以后就生效,启用了GreaseMonkey

3,去这个页面安装12306 train ticket buyer脚本,http://userscripts.org/scripts/show/122334

(完成第二步以后,就可以直接在firefox里打开上述链接,页面上会有一个”Install”按钮,单击后就完成了脚本在油猴里的安装了)

下面我们就开始体验购票的整个流程吧。在firefox浏览器里安装好上面的油猴脚本后,首先打开登陆页面,http://www.12306.cn/mormhweb/kyfw/,这时你就会发现页面上出现了下面这个设置区域

如果你没看到,请记得去确认下GreaseMonkey扩展是否已经启用,就在地址栏最右边那个小猴子,记得点亮它,嘿嘿。

Ok,再来介绍下这个脚本的功能,它对我们闯第一,二关有一定的辅助功效,功能1:登录助手(自动填充用户名密码,验证码输入框自动获得焦点,无需碰鼠标即可输入验证码回车重复登录);功能2:自动查询车票(根据用户事先配置的始发到站信息,自动查询)

先说说第一关登陆,每天整点放票的时候,想登陆进去真是难如登天,每次都会弹出下面这个让人泪流满面的窗口,尼玛连个登陆进去的机会都不给啊。。。

更可恶的是,如果你用IE浏览器的话,密码会清空,鼠标焦点也没有选中在任何一个输入框,你不得不鼠标移到密码框,重输密码,再验证码,再鼠标单击“登录“,如果你用的是firefox呢,情况稍微好点,起码密码可以帮你保存,可还是上面的鼠标动作免不了。

大家懂的,这时候,速度就是一切,差之毫厘,失之千里,省下那么一点点鼠标操作的时间,你就比别人多了几次登录的机会啊。

这就是上面那个油猴脚本能帮到你的地方了,安装 了以后,你会发现,登录时,你只需要使用键盘进行操作,就两个动作,输入验证码,回车,如果失败,再次回车干掉弹出框,此时鼠标焦点依旧在验证码那,继续 输入验证码,回车,。。。。只要你键盘操作够快,此时的你绝对是正常登录操作的好几倍啊,有么有?哈哈

Ok,千辛万苦终于爬进系统里头来了,下一关就是预定,这个脚本在这里还是继续可以帮到你一点点的。

如果不用上面这个脚本的话,正常的操作流程是自己填写出发站点和到达站点,出发日期,点击“重新查询“按钮,完了你发现没票,囧了,又重新填一遍信息,再点,还是没票,又来一遍?

这时候上面的油猴脚本就可以帮我们做这种无聊的重填信息动作了,上面我们不是设置了出发站点和到达站点,出发日期嘛,这些信息就是脚本用来在车票查询的时候自动重填的,

你现在只管不断地点“重新查询“按钮,期待着宝贵的车票出现,然后你懂的,剩下的预定是否成功,订单是否提交成功,支付是否能完成,那就只有老天爷知道了。。,

当然,登陆不进,进去了又被踢下线,502 Bad gate way,这些问题就无语了,没办法,只有不断的重试,重试,再重试,关键时刻还得拼人品,拼运气的。

此外,网上有文章介绍如何用firebug修改html页面上的参数值,然后在提交页面来快速下订单的教程,见《网友提供Firefox+扩展 15秒网上快速预定火车票教程》,但我也试了,基本用处不大,能否提交订单成功,真的是只有上帝才知道,我基本都卡在这里,眼看着有票,可订单死活提交不上去。。。

但起码这个脚本可以让我们节省出不少的时间,在这全民抢票的时代,时间就是机会,时间就是金钱啊,心动了么?赶紧照着我这个教程试试吧。

最后,再推荐一个Chromium下的脚本,我使用的是Chromium 16

1,首先在Chromium中打开下述链接,安装12306 auto query脚本。

https://gist.github.com/raw/1554666/dec45c925002ec23ccef9f5be14770572d27625c/12306.user.js

2,登陆到12306,选择“车票预订”,填写好信息后进行一次查询后,就会看到下面的画面。

程序是会自动查询,当有票时会会高亮有票的车次。在查询期间你可以做其他事情,但要保持标签页开启(是否是当前标签页无所谓)。注意:1) 只在 Chromium 上调试过。2) 不支持自动订票,有票后请手工操作。

哈哈,反正我今天是坚持不懈的斗争,终于抢到了一张回家的卧铺票,一点小经验,不敢独享,拿出来给大家分享,咱技术宅买个票就得像打仗一样,仔细研究对手,做好一切能做的准备,打持久战,不是么?