终于买好本本了

纠结了大半个月,寻找中意的本本. 看来是我要求太高的关系,既要配置高、又要质量好、还要便宜的真的难找。

本周终于入手一台Y460C ,参数:http://detail.zol.com.cn/notebook/index261787.shtml

入手价格:4680 加了2G内存170.

悲剧的是 预按照的windows7是32BIT。 4G内存只能使用2.3(集成显卡吞掉一部分)

个人感觉散热没有说的这么夸张,估计是我很少玩游戏的关系。 不过现在是开春,到夏天估计还是需要配个散热底座。

 

小Y倩图:

android自定义日期组件(拨动效果)

android自带的日期组件是通过TimeDialog,让用户上下调整来输入.但这样势必让用户需要点击某个按钮,弹出对话框后在选择.感觉不是非常的友好.

自己写了一个日期组件,可以通过手势在时间上拨动,达到调整数字的目的.

代码如下:

package com.zjhcsoft.mobi.android.widget;

import java.util.Calendar;

import java.util.GregorianCalendar;

import com.zjhcsoft.mobi.android.ui.R;

import android.app.DatePickerDialog;

import android.app.Dialog;

import android.content.Context;

import android.content.res.TypedArray;

import android.util.AttributeSet;

import android.util.Log;

import android.view.GestureDetector;

import android.view.MotionEvent;

import android.view.View;

import android.widget.DatePicker;

import android.widget.TextView;

/**

* 日期滚动组件

* @author Fred

*

*/

public class RotateTimeInput extends TextView {

    private static final String TAG = "RotateTimeInput";

    public static final String UP = "up";

    public static final String DOWN = "down";

    private int year;

    private int month;

    private int days;

    private Calendar currentDate;//当前时间

    private float fontSize = 13L;

    private GestureDetector ges;//手势接口实现

    private RotateTimeListener rotateTimeListener;

    private Dialog dataDialog;//日期选择器

    private boolean isMove = false;

    private boolean isFling = false;

    private boolean isScroll = false;

    //细粒度属性设置

    private float longClickFix = 0;//防止滑动和长按有冲突

    private float longClickNorm = 50;//区分滑动和长按标准差值,差值大于改值时,放弃长按事件

    private int scrollNorm;//设置scroll因子 ,scroll数大于默认值时,时间触发

    public RotateTimeInput(Context context, AttributeSet attrs) {

        super(context, attrs);

        initRotateWidget(context,attrs);

    }

    /**

    * 初始化控件时间

    * @param year 年

    * @param month 月-1

    * @param days 日

    */

    public void initByGivenDate(int year,int month,int days){

        this.year = year;

        this.month = month-1;

        this.days = days;

        currentDate = null;

        this.setText(formatTime());//设置默认值显示值

    }

    /**

    * 初始化RotateTime组件

    * @param context 应用上下文

    * @param attrs 配置属性

    */

    private void initRotateWidget(Context context,AttributeSet attrs){

        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RotateTimeInput);

        scrollNorm = a.getInt(R.styleable.RotateTimeInput_scrollNorm,8);

        a.recycle();

        //设置字体大小

        setTextSize(fontSize);

        //初始化当前时间

        this.setText(formatTime());//设置默认值显示值

        //增加轨迹事件

        ges = new GestureDetector(context,new TouchGesture(context));

        //鼠标手势触发

        this.setOnTouchListener(new OnTouchListener() {

            public boolean onTouch(View v, MotionEvent event) {

                if(event.getAction()==MotionEvent.ACTION_UP){

                    if(isMove&&isScroll&&!isFling){

                        longClickFix = 0;

                        rotateTimeListener();

                        isScroll = false;

                        isMove = false;

                    }

                }

                return ges.onTouchEvent(event);

            }

        });

    }

    /**

    * 时间格式化

    * @return

    */

    private String formatTime(){

        calculate();

        return new StringBuffer().append(year).append("年").append(month+1).append("月").append(days).append("日").toString();

    }

    /**

    * 日期递增

    */

    private void upDays(){

        currentDate.add(Calendar.DATE, 1);

        setText(formatTime());

    }

    /**

    * 日期减少

    */

    private void downDays(){

        currentDate.add(Calendar.DATE, -1);

        setText(formatTime());

    }

    /**

    * 调整时间

    * @param way 调整时间方向(RotateTimeInput.UP向前一天,RotateTimeInput.DOWN回退一天)

    */

    public void adjustDay(String way){

        if(way==UP){

            upDays();

            }else{

            downDays();

        }

        rotateTimeListener();

    }

    /**

    * 重新计算当前年月日天数

    */

    private void calculate(){

        if(currentDate==null){

            if(year!=0&&month!=0&&days!=0){

                this.currentDate = new GregorianCalendar(year, month, days);

                }else{

                this.currentDate = GregorianCalendar.getInstance();

            }

        }

        if (currentDate!=null){

            this.year = currentDate.get(Calendar.YEAR);

            this.month = currentDate.get(Calendar.MONTH);//Java中,月份从0开始

            this.days = currentDate.get(Calendar.DATE);

        }

    }

    /**

    * 创建Dialog对象,此处只有一个DataPick对象

    * @param context 应用上下文

    * @return

    */

    private Dialog initDialog(Context context){

        dataDialog = new DatePickerDialog(context,new DatePickerDialog.OnDateSetListener() {

            public void onDateSet(DatePicker view, int years, int monthOfYear,

            int dayOfMonth) {

                //DataPick用户锁定后

                currentDate.set(years, monthOfYear, dayOfMonth);

                setText(formatTime());

                rotateTimeListener();

            }

        },currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE));

        dataDialog.show();

        longClickFix = 0;//释放差值

        return dataDialog;

    }

    /**

    * Touch接口实现,监听用户鼠标轨迹

    * @author Fred

    *

    */

    class TouchGesture extends GestureDetector.SimpleOnGestureListener{

        private double scrollDistence=0;

        Context dialogContext;

        public TouchGesture(Context dialogContext){

            this.dialogContext = dialogContext;

        }

        @Override

        public void onLongPress(MotionEvent e) {

            if(longClickFix scrollNorm) {

                scrollDistence=0;

                if (distanceX<0){

                    upDays();

                    }else{

                    downDays();

                }

            }

            longClickFix = Math.abs(e2.getRawX() - e1.getRawX());

            return false;

        }

    }

    /**

    * 拨动事件

    * @param listener

    */

    public void setOnRotateTimeListener(RotateTimeListener listener){

        this.rotateTimeListener = listener;

    }

    private void rotateTimeListener(){

        calculate();

        if (rotateTimeListener!=null){

            rotateTimeListener.onRotateTime(this.year, this.month+1, this.days);

        }

    }

    class RotateFlyingThread extends Thread {

        private int ri;

        private int rp;

        private float af;

        private boolean stop = false;

        private int ic;

        public RotateFlyingThread(int rotateInterval, int rotatePeriod,

        float attenuateFactor, int increment) {

            ri = rotateInterval;

            rp = rotatePeriod;

            af = attenuateFactor;

            ic = increment;

        }

        public void stopRotate() {

            stop = true;

        }

        public void run() {

            int p = 0;

            Log.i("Rotating", String.format( "rotateInterval: %s, rotatePeriod: %s, attenuateFactor: %s, increment: %s,", ri, rp, af, ic));

            while ((p < rp) && !stop) {

                Log.i("Rotating", " ..." + RotateTimeInput.this.getText());

                RotateTimeInput.this.post(new Runnable() {

                    public void run() {

                        if (ic>0){

                            upDays();

                            }else{

                            downDays();

                        }

                    }

                });

                try {

                    Thread.sleep(ri);

                    } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                ri += (int) (ri * (af / 10));

                p += ri;

            }

            rotateTimeListener();

            isFling = false;

            isMove = false;

            Log.i("Rotating", "stopped");

        }

    }

}

事件接口:

package com.fengsage.mobi.android.widget;

/**

* 拨动时间空间

* @author Fred

*

*/

public interface RotateTimeListener {

/**

* 当时间停下来的时候,开始触发事件

* @param year

* @param month 1--12

* @param days

*/

public void onRotateTime(int year,int month,int days);

}

最终效果如下:

在数字上面,用手左右来回拖动,时间也会跟着变动. 如果长按,则会弹出android标准的日期控件.

在android如何使用AsyncTask异步任务

最近项目中用到异步任务功能,网上搜罗了下资料,奈何国内的质量实在太低,依靠伟大的谷歌搜到很多国外的文章,写的非常的好,更好的在于没有copy paste的成分.

本文内容转自:http://www.brighthub.com/mobile/google-android/articles/82805.aspx

英语好的朋友请直接阅读原文.小弟不才,做个苦力当翻译

介绍

我们的Android应用越来越复杂,连接服务端,和web交互数据,存储大文件在android数据库中的同时显示进度条或者在通知栏显示通知. 我们如何能在抛开UI线程的情况下,边接受处理数据边用进度条展示呢?开始之前,必须知道什么是"UI线程"?

如果你熟悉"Thread"的概念. 那么你应该很容易明白异步任务. Android应用在处理的时候只有一个main主线程在运行.这个看上去像在任何地方只有一个任务. 如果你只有一个UI线程在工作,你就不能做一些复杂的事情,比如同时存储10000条记录,这个时候应用会停住,直到1000条记录存储完毕. 这不是一个好的方式. 在android你可以在一个应用里,同一时间运行多个线程. 举例:一个后台任务可以从服务端接受数据并且存储到本地数据库中.

如何对"Thread"概念有足够的了解,那么我们继续

现在我们可以开始了吗? 开始在后台执行任务? 这里我们还有几步工作要做.

一个古老的路线方法是使用Thread线程类,使用HandlersRunnables. 但是我们有更好的方式。使用AsyncTask

AsyncTask 类

让我来看看AsyncTask类的结构


				private class myBrightHubTask extends AsyncTask

				protected void onPreExecute(){

				}

				这个方式是在执行新线程前运行. 这里没有输入和输出的参数,所以这个可以初始化一些你认为必要的参数.

				protected Z doInBackground(X...x){

				}

				这是个非常重要的方法. 你可以在这里定义你需要的在后台执行的方法.这里开始是一个独立的线程在运行,而不是main线程. 这个方法接收一组对象集合,对象可以是在前继承AsyncTask的时候定义的X类型(你看到这个类的一开始我们继承的AsyncTask类了吗?这里的X就是这里的类型),默认是Object集合.

				protected void onProgressUpdate(Y y){

				}

				这个方法是在使用publishProgress()方法时触发,这个方法常用于显示一些在主线程中执行的进度条或者一些信息展示.比如当在执行一个后台任务的时候,前台做一个滚动条在滚动 ,

				protected void onPostExecute(Z z){

				}

这个方法在后台任务完成后执行,传入一个参数Z,也是前面定义的那个,你可以使用这个参数做一些结束任务时的处理,比如跳转intent或者其他的事情.

X,Y,Z的是什么类型?

我想你也可以从上面的结构中得出结论:

X – 运行后台任务的时候,需要传入的参数类型. 可以是一个对象的集合.

Y – 当你需要使用onProgressUpdate方法时,传入的参数类型

Z – 当后台任务完成时,需要传入数据处理的数据类型

如何使用这个异步任务呢?执行要执行下面2行代码.


				myBrightHubTask brightHubTask = new myBrightHubTask();

				brightHubTask.execute(x);

这里的输入参数是前面讲的X类型

一旦我们运行异步任务.你可以使用getStatus()方法获取它的状态


				brightHubTask.getStatus();

我们可以接受下面几个状态:

RUNNING – 任务处理中

PENDING – 任务还没有完成.

FINISHED – 任务结束.

提醒

需要注意的是:

  • 不用主动去调用onPreExecute, doInBackground and onPostExecute这个三个方法.这些方法会自动执行.

  • 你不能在另外一个AsyncTask或者线程中使用异步任务. 调用异步任务必须在UI主线程中使用.

  • onPostExecute 这个方法时在UI主线程中执行.这里你可以调用另外一个异步任务.

  • 输入参数可以设置一个Object集合,这样你就可以传入任意类型的对象

更多内容: http://www.brighthub.com/mobile/google-android/articles/82805.aspx#ixzz1GkXV8IT4

 

android单元测试(AndroidTestCase)

Android 单元测试基于JUnit开发.但是用起来并不容易

AndroidManifest.xml

确保你的应用加载了JUnint库,并配置AndroidMainifest.xml按照下面的方式.


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

				<manifest

				xmlns:android="http://schemas.android.com/apk/res/android"

				package="com.example.app.tests" android:versionCode="1"

				android:versionName="1.0">

				<application>

				<uses-library android:name="android.test.runner" />

				</application>

				<uses-sdk android:minSdkVersion="3" />

				<instrumentation android:name="android.test.InstrumentationTestRunner"

				android:targetPackage="com.example.app" android:label="Tests for My App" />

				</manifest>

AllTests.java

编写测试代码入口.你可以把下面代码拷贝到任意工程去即可.


				package com.example.app;

				import junit.framework.Test;

				import junit.framework.TestSuite;

				import android.test.suitebuilder.TestSuiteBuilder;

				/**

				 * A test suite containing all tests for my application.

				 */

				public class AllTests extends TestSuite {

				    public static Test suite() {

				        return new TestSuiteBuilder(AllTests.class).includeAllPackagesUnderHere().build();

				    }

				}

				

SomeTests.java

编写单元测试,该测试集成AndroidTestCase父类. 记住所有的测试方法开头必须使用"test". 使用不同的assert方法来判断不同测试结果


				package com.example.app;

				import junit.framework.Assert;

				import android.test.AndroidTestCase;

				public class SomeTest extends AndroidTestCase {

				    public void testSomething() throws Throwable {

				       Assert.assertTrue(1 + 1 == 2);

				    }

				    public void testSomethingElse() throws Throwable {

				       Assert.assertTrue(1 + 1 == 3);

				    }

				}

				

运行单元测试

使用Eclipse的Run Junit Tests方法.选中测试工程,按右键,选择Run As…Android Junit Test.

或者输入下面命令:

adb shell am instrument -w com.example.app.tests/android.test.InstrumentationTestRunner

结果

你可以从Eclipse的console或命令行工具中看到结果. 完毕!

 

原文连接:http://marakana.com/tutorials/android/junit-test-example.html

分享一个在线视频学习网站

网址http://mytut.jaoee.com

 

好吧·~ 这个是广告~ 公司开发的一个实验性产品,目前V0.2 欢迎大家提意见

一段linux启动脚本(python版)

公司项目用到需要开机自动执行相关程序,奈何shell不是很精通,老大给了段python版的,我也分享下,供大家参考

#!/usr/bin/env python

# init.d script for the Mytut CS Repo Server; John Wang 14 Feb 2011

import sys,subprocess,time

cmmd    = '/home/fred/test.py'#启动/关闭执行命令

port    = '12600'

decp    = 'start process program....'

cmmdln  = ['nohup',cmmd,'-p',port]

def start():

print 'Starting %s...' % decp

subprocess.Popen(cmmdln)

print 'Started'

def stop():

print 'Stopping %s...' % decp

subprocess.Popen(cmmdln)

print 'Stopped'

return 0

def restart():

if stop()==1:

print 'Stopping error. Maybe already stopped ?. starting anyway ...'

else:

time.sleep(1)

start()

def run(argv):

fns={

    'start':start,

    'stop':stop,

    'restart':restart,

    'reload':restart,

}

fn=fns.get(argv[1],None) if len(argv)>1 else None

if not fn:

print >> sys.stderr,"Usage: %s {%s}" % (argv[0],'|'.join(fns.keys()))

sys.exit()

fn()

if __name__ == '__main__':

run(sys.argv)

比较简单~

前文介绍过,放在/etc/rc3.d 目录下即可,linux启动后会自动执行这个目录里面的脚本,默认使用start参数启动

一段不错的PRE样式

从网上找的,忘了作者链接,若作者看到此文,请留言链接,我将补上


				PRE {

				overflow: auto;

				overflow-y: hidden;

				background-color: grey;

				font-size: 12px;

				width: 95%;

				line-height: 16px;

				font-family: "Courier New", FixedSys;

				color: #555;

				background: #fafafa;

				border-top: 1px solid #ccc;

				border-bottom: 1px solid #ccc;

				border-left: 15px solid #ccc;

				border-right: 1px solid #ccc;

				padding: 0 5px;

				margin: 0 0 20px;

				}

				

效果看此处即可

美丽的故乡-嘉兴

 

想念嘉兴的朋友和同学~~

nginx反向代理(ghs.google.com)

设置ghs.google.com代理

 


				upstream ghs {

				ip_hash;

				server ghs.google.com;

				server 72.14.203.121;

				server 72.14.207.121;

				server 74.125.43.121;

				server 74.125.47.121;

				server 74.125.53.121;

				server 74.125.77.121;

				server 74.125.93.121;

				server 74.125.95.121;

				server 74.125.113.121;

				server 216.239.32.21;

				server 216.239.34.21;

				server 216.239.36.21;

				}

				server {

				listen 80;

				server_name www.fengsage.com;

				location / {

				proxy_set_header Host $host;

				proxy_pass http://ghs;

				proxy_set_header X-Real-IP  $remote_addr;

				proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

				}

				}

				}

				upstream 设置轮询服务IP,其实设置一个ghs.google.com就可以了,因为本身就是googleCDNS网络

 

Linux自动运行脚本

windows下开机启动某个程序比较简单,只需要把程序添加到”程序-启动”栏即可.

对于linux下开机自动运行程序笔记麻烦. 以Apache Tomcat为例. 做开机自动启动


				SERVICE_HOME="/home/tomcat"

				SERVICE_DESC="Apache Tomcat"

				SERVICE_USER="tomcat"

				CONSOLE_LOG="$SERVICE_HOME/console.log"

				START_SCRIPT="startup.sh"

				SHUTDOWN_SCRIPT="shutdown.sh"

				start(){

				echo "Starting $SERVICE_DESC Server ..."

				cd $SERVICE_HOME/bin

				sudo -u $SERVICE_USER ./$START_SCRIPT > $CONSOLE_LOG 2> $CONSOLE_LOG &

				}

				stop(){

				echo "Stopping $SERVICE_DESC Server ... "

				cd $SERVICE_HOME/bin

				sudo -u $SERVICE_USER ./$SHUTDOWN_SCRIPT > $CONSOLE_LOG 2> $CONSOLE_LOG &

				}

				restart(){

				stop

				# give stuff some time to stop before we restart

				sleep 5s

				start

				}

				case "$1" in

				start)

				start

				;;

				stop)

				stop

				;;

				restart)

				restart

				;;

				*)

				echo "Usage: tomcat {start|stop|restart}"

				exit 1

				esac

				exit 0

 

 

设置:

1、保存脚本到/ect/init.d/目录下,保存名tomcat.sh

2、进入/etc/rc3.d/目录,新建一个软链接 sudo ln -s  ../init.d/tomcat.sh tomcat

 

注:ect目录下有很多rc1.d、rc2.d….这类的目录,这里是linux用来设置不同程序启动顺序用,数字越小启动优先级越高,一般而言我们自己的程序放在rc3.d目录下即可