[转载]关于讯飞语音SDK开发学习 - 或、许 - 博客园

mikel阅读(1201)

[转载]关于讯飞语音SDK开发学习 – 或、许 – 博客园.

前奏,浑浑噩噩已经工作一年多,这一年多收获还是挺多的。逛园子应该有两年多了,工作后基本上是天天都会来园子逛逛,园子 里还是有很多牛人写了一些不错的博客,帮我解决很多问题。但是一直没写过博客,归根到底一个字“懒”,还有就是不知道该写 些什么…

今 天把我最近研究讯飞语音东东,分享一下,不过有些还是前辈们提供的。之前公司让我做一个小的语音识别功能,一开始我就建议使用讯飞语音,个人觉得讯飞识别 正确率还是可观的。可是老总说不能考 虑联网,还有就是钱的问题。想到微软自带语音识别引擎(基于win7)。第一次接触到语音识别,没什么头绪,只有收集相关资料 。最后成品出来了,但是识别效果不是那么满意,老总说那就将就用吧,我想他都那样说了,我也没多大意见…开年后老总老总 买了个iphone5玩了siri后,觉得我们现在那个语音太丑陋了,让换一个解决方案,识别率要达到90%。国内有好几家公司做语音识 别的比如科大讯飞、云知声、捷通华声以及紫冬锐意语音都做了一定开放。市面上我知道语音助手有百度语音助手、虫洞语音助手 、360语音助手以及科大讯飞语点;前两个我不知道采用那家公司的还是自己研发的不过都没开开放,360语音助手采用讯飞的。然 后我就继续提议使用讯飞语音SDK,于是乎同事们都下载讯飞语点来玩玩,老总说那就试试讯飞语音SDK。

先 做一个简单demo,看看识别效果,感觉识别率上能够满足要求。一般要的结果不光只是要把所说的话翻译成文字,而是需要的是 语义的理解:例如我要去北京,直接返回北京这个关键。目前讯飞还没把这个接口开放出来,公司负责人说今年会把这个开放出来 。那现在只能使用关键词识别语法,一种是直接是文本词库;另一种是ABNF语法。ABNF写法有点烦杂(语法文件里使用到的词句都是指定的,对于无法枚举 的词句暂时没有很好的解决办法。),就直接采用文本词库(因为关键词有点多)。讯飞还有专门人负责关于讯飞语音问题解答(QQ群:153789256)。

讯飞提供msc.dll这个DLL,调用DLL的封装:

/// <summary>
        /// MSCDLL入口封装
        /// </summary>
        private class MscDll
        {
            #region MscDLL
           
            /// <summary>
            /// 初始化MSC的ISR部分
            /// </summary>
            /// <param name="configs">初始化时传入的字符串,以指定合成用到的一些配置参数,各个参数以“参数名=参数值”的形式出现,大小写不敏感,不同的参数之间以“,”或“\n”隔开,不设置任何值时可以传入NULL或空串:</param>
            /// <returns>如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRInit(string configs);
           
            /// <summary>
            /// 开始一个ISR会话
            /// </summary>
            /// <param name="grammarList">uri-list格式的语法,可以是一个语法文件的URL或者一个引擎内置语法列表。可以同时指定多个语法,不同的语法之间以“,”
            /// 隔开。进行语音听写时不需要语法,此参数设定为NULL或空串即可;进行语音识别时则需要语法,语法可以在此参数中指定,也可以随后调用QISRGrammarActivate指定识别所用的语法。</param>
            /// <param name="_params">本路ISR会话使用的参数,可设置的参数及其取值范围请参考《可设置参数列表_MSP20.xls》,各个参数以“参数名=参数值” 的形式出现,不同的参数之间以“,”或者“\n”隔开。</param>
            /// <param name="errorCode">如果函数调用成功则其值为MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors。几个主要的返回值: MSP_ERROR_NOT_INIT 未初始化 MSP_ERROR_INVALID_PARA 无效的参数; MSP_ERROR_NO_LICENSE 开始一路会话失败</param>
            /// <returns>MSC为本路会话建立的ID,用来唯一的标识本路会话,供以后调用其他函数时使用。函数调用失败则会返回NULL。</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr QISRSessionBegin(string grammarList, string _params, ref int errorCode);
           
            /// <summary>
            /// 传入语法
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="grammar">语法字符串</param>
            /// <param name="type">语法类型,可以是uri-list、abnf、xml等</param>
            /// <param name="weight">本次传入语法的权重,本参数在MSP 2.0中会被忽略。</param>
            /// <returns>如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRGrammarActivate(string sessionID, string grammar, string type, int weight);

            /// <summary>
            /// 写入用来识别的语音
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="waveData">音频数据缓冲区起始地址</param>
            /// <param name="waveLen">音频数据长度,其大小不能超过设定的max_audio_size</param>
            /// <param name="audioStatus">用来指明用户本次识别的音频是否发送完毕,可能值如下:
            /// MSP_AUDIO_SAMPLE_FIRST = 1 第一块音频
            /// MSP_AUDIO_SAMPLE_CONTINUE = 2 还有后继音频
            /// MSP_AUDIO_SAMPLE_LAST = 4 最后一块音频</param>           
            /// <param name="epStatus">端点检测(End-point detected)器所处的状态,可能的值如下:
            /// MSP _EP_LOOKING_FOR_SPEECH = 0 还没有检测到音频的前端点。
            /// MSP _EP_IN_SPEECH = 1 已经检测到了音频前端点,正在进行正常的音频处理。
            /// MSP _EP_AFTER_SPEECH = 3 检测到音频的后端点,后继的音频会被MSC忽略。
            /// MSP _EP_TIMEOUT = 4 超时。
            /// MSP _EP_ERROR= 5 出现错误。
            /// MSP _EP_MAX_SPEECH = 6 音频过大。</param>
            /// <param name="recogStatus">识别器所处的状态</param>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRAudioWrite(string sessionID, byte[] waveData, uint waveLen, AudioStatus audioStatus, ref  EpStatus epStatus, ref RecogStatus recogStatus);

            /// <summary>
            /// 获取识别结果
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="rsltStatus">识别结果的状态,其取值范围和含义请参考QISRAudioWrite的参数recogStatus</param>
            /// <param name="waitTime">与服务器交互的间隔时间,可以控制和服务器的交互频度。单位为ms,建议取值为5000</param>
            /// <param name="errorCode">如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</param>
            /// <returns>函数执行成功并且获取到识别结果时返回识别结果,函数执行成功没有获取到识别结果时返回NULL</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr QISRGetResult(string sessionID, ref RecogStatus rsltStatus, int waitTime, ref int errorCode);

            /// <summary>
            /// 结束一路会话
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="hints">结束本次会话的原因描述,用于记录日志,便于用户查阅或者跟踪某些问题</param>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRSessionEnd(string sessionID, string hints);

            /// <summary>
            /// 获取与识别交互相关的参数
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="paramName">要获取的参数名称;支持同时查询多个参数,查询多个参数时,参数名称按“,” 或“\n”分隔开来</param>
            /// <param name="paramValue">获取的参数值,以字符串形式返回;查询多个参数时,参数值之间以“;”分开,不支持的参数将返回空的值</param>
            /// <param name="valueLen">参数值的长度</param>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRGetParam(string sessionID, string paramName, string paramValue, ref uint valueLen);

            /// <summary>
            /// 逆初始化MSC的ISR部分
            /// </summary>
            /// <returns></returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern int QISRFini();

            /// <summary>
            /// 上传用户自定义词库
            /// </summary>
            /// <param name="sessionID">由QISRSessionBegin返回过来的会话ID</param>
            /// <param name="dataName">词库名称</param>
            /// <param name="userData">词库数据采用是utf8格式</param>
            /// <param name="lenght">词库大小</param>
            /// <param name="paramValue">参数值</param>
            /// <param name="errorCode">如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors</param>
            /// <returns>函数执行成功并且返回exID(词库编号)</returns>
            [DllImport("msc.dll", CallingConvention = CallingConvention.StdCall)]
            public static extern IntPtr QISRUploadData(string sessionID, string dataName, byte[] userData, uint lenght, string paramValue, ref int errorCode);

            #endregion
        }

说明一下:“QISRUploadData”(上传词库)这个函数在开发文档里面没的,讯飞遗漏了。

具体实现(关键词识别,文本词库):

类:MscNet

#region 定义字段

        //返回错误代号
        private int ret = 0;
        private RecoErrors Re = null;
        /// <summary>
        /// 会话ID
        /// </summary>
        private string sess_id = null;
        /// <summary>
        /// 参数
        /// </summary>
        private string param = null;
        /// <summary>
        /// 语法
        /// </summary>
        private string grammar = null;
        //错误消息通知托管
        public delegate void delegdateOnerror(string Msg);
        private string path = null;
        /// <summary>
        /// 识别数据返回的事件
        /// </summary>
        public event EventHandler<DataArrivedEventArgs> DataArrived;
        /// <summary>
        /// 识别过程结束的事件
        /// </summary>
        public event EventHandler ISREnd;
        /// <summary>
        /// 正在识别
        /// </summary>
        public event EventHandler Spoting;

        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数,初始化引擎
        /// </summary>
        /// <param name="appid">appid</param>
        /// <param name="param">参数</param>      
        /// <param name="grammar">语法ID</param>
        /// <param name="path">路径</param>
        public MscNet(string appid, string param, string path, string grammar)
        {
            this.path = path;
            this.param = param;
            this.grammar = grammar;
            Re = new RecoErrors();
            //引擎初始化,只需初始化一次
            ret = MscDll.QISRInit("appid=" + appid);
            try
            {
                Re.GetError(ret);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message.ToString());
            }
        }
        #endregion

        #region 公共方法

        /// <summary>
        /// 开始识别语音
        /// </summary>
        /// <param name="buffer">音频数据</param>
        public void InterpretVoice(byte[] buffer)
        {
            //用来指明用户本次识别的音频是否发送完毕
            AudioStatus audioStatus = AudioStatus.ISR_AUDIO_SAMPLE_LAST;
            //端点检测(End-point detected)器所处的状态
            EpStatus ep_status = EpStatus.ISR_EP_NULL;
            //识别器所处的状态
            RecogStatus rec_status = RecogStatus.ISR_REC_NULL;
            //识别结果的状态
            RecogStatus rslt_status = RecogStatus.ISR_REC_NULL;
            Loadgrammar();
            int ret = MscDll.QISRAudioWrite(sess_id, buffer, (uint)buffer.Length, audioStatus, ref ep_status, ref rec_status);
            try
            {
                Re.GetError(ret);
                do
                {
                    if (rslt_status == RecogStatus.ISR_REC_STATUS_INCOMPLETE)
                    {
                        Spoting(this, new EventArgs());//通知正在识别
                    }
                    IntPtr p = MscDll.QISRGetResult(sess_id, ref rslt_status, 0, ref ret);
                    Re.GetError(ret);
                    if (p != IntPtr.Zero)
                    {
                        string tmp = PtrToStr(p);
                        DataArrived(this, new DataArrivedEventArgs(tmp));//激发识别数据到达事件                    
                    }
                    System.Threading.Thread.Sleep(500);
                } while (rslt_status != RecogStatus.ISR_REC_STATUS_SPEECH_COMPLETE);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message);
            }
            finally
            {
                try
                {
                    ret = MscDll.QISRSessionEnd(sess_id, string.Empty);
                    Re.GetError(ret);
                    ISREnd(this, new EventArgs());//通知识别结束 
                }
                catch (MscException ex)
                {
                    RaiseError(ex.Message);
                }
            }
        }

        /// <summary>
        /// 上传词库词库采用是utf8格式
        /// </summary>
        /// <param name="txtFile">词库名称</param>
        /// <param name="path">词库路径</param>
        /// <param name="param">参数</param>
        /// <returns>返回词库编号</returns>
        public string GetExID(string txtFile, string path, string param)
        {
            string filePath = Path.Combine(path, txtFile);
            string tmp = string.Empty;
            if (!string.IsNullOrEmpty(filePath))
            {
                try
                {
                    sess_id = PtrToStr(MscDll.QISRSessionBegin(null, param, ref ret));
                    Re.GetError(ret);
                    try
                    {
                        using (FileStream fs = File.Open(filePath, FileMode.Open))
                        {
                            long len = fs.Length;
                            byte[] buffer = new byte[len];
                            fs.Read(buffer, 0, (int)len);
                            IntPtr p = MscDll.QISRUploadData(sess_id, "sces", buffer, (uint)fs.Length, "dtt=keylist", ref ret);
                            Re.GetError(ret);
                            if (p != IntPtr.Zero)
                            {
                                tmp = PtrToStr(p);
                            }
                        }
                    }
                    catch (FileNotFoundException ex)
                    {
                        RaiseError(ex.Message);
                    }

                }
                catch (MscException ex)
                {
                    RaiseError(ex.Message);
                }
                finally
                {
                    try
                    {
                        ret = MscDll.QISRSessionEnd(sess_id, null);
                        Re.GetError(ret);
                    }
                    catch (MscException ex)
                    {
                        RaiseError(ex.Message.ToString());
                    }
                }
            }
            else
            {
                RaiseError("路径不正确!");
            }
            return tmp;
        }

        /// <summary>
        /// 对MSC的ISR部分进行逆初始化。
        /// </summary>
        public void QISRFini()
        {
            try
            {
                ret = MscDll.QISRFini();
                Re.GetError(ret);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message.ToString());
            }
        }

        #endregion

        #region 受保护方法
        /// <summary>
        /// 加载语法 
        /// </summary>
        private void Loadgrammar()
        {
            try
            {
                sess_id = PtrToStr(MscDll.QISRSessionBegin(grammar, param, ref ret));
                Re.GetError(ret);
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message);
            }
        }

        /// <summary>
        /// 指针转字符串
        /// </summary>
        /// <param name="p">指向非托管代码字符串的指针</param>
        /// <returns>返回指针指向的字符串</returns>
        private string PtrToStr(IntPtr p)
        {
            List<byte> lb = new List<byte>();
            try
            {
                while (Marshal.ReadByte(p) != 0)
                {
                    lb.Add(Marshal.ReadByte(p));
                    p = p + 1;
                }
            }
            catch (AccessViolationException ex)
            {
                RaiseError(ex.Message);
            }
            return Encoding.Default.GetString(lb.ToArray());
        }       
        #endregion

        #region 事件
        /// <summary>
        /// 错误通知事件
        /// </summary>
        public event delegdateOnerror OnError;
        private void RaiseError(string Msg)
        {
            if (OnError != null)
            {
                OnError(Msg);
            }
        }
        /// <summary>
        /// 有识别数据返回的事件参数,包含了识别的文本结果
        /// </summary>
        public class DataArrivedEventArgs : EventArgs
        {
            public string result;
            public DataArrivedEventArgs(string rs)
            {
                result = rs;
            }
        }
        #endregion

如果采用ABNF语法,只是与文本词库加载语法方式有点不一样:

/// <summary>
        /// 加载语法 
        /// </summary>
        private void Loadgrammar()
        {
            try
            {
               
               //sess_id = PtrToStr(MscDll.QISRSessionBegin(grammar, param, ref ret));              
                /*ABNF语法*/
                sess_id = PtrToStr(MscDll.QISRSessionBegin(null, "rst=plain,sub=asr,ssm=1,aue=speex,auf=audio/L16;rate=16000,cfd=350", ref ret));
                em.GetError(ret);
                string grammar1 = "#ABNF 1.0 GB2312;\n mode voice;\n language zh-cn;\n\n\n root $main;\n public $main = 我[想要]看$place1;\n $place1=足球;\n";
                ret = MscDll.QISRGrammarActivate(sess_id, grammar1, "abnf", 0);//将语法ID传入QISRSessionBegin
                /*end */
                em.GetError(ret);             
            }
            catch (MscException ex)
            {
                RaiseError(ex.Message.ToString());
            }
        }

常量的枚举:

#region 错误代号
    enum ErrorCode
    {
        MSP_SUCCESS= 0,
        MSP_ERROR_FAIL = -1,
        MSP_ERROR_EXCEPTION = -2,

        /* General errors 10100(0x2774) */
        MSP_ERROR_GENERAL = 10100,     /* 0x2774 */
        MSP_ERROR_OUT_OF_MEMORY = 10101,     /* 0x2775 */
        MSP_ERROR_FILE_NOT_FOUND = 10102,     /* 0x2776 */
        MSP_ERROR_NOT_SUPPORT = 10103,     /* 0x2777 */
        MSP_ERROR_NOT_IMPLEMENT = 10104,     /* 0x2778 */
        MSP_ERROR_ACCESS = 10105,     /* 0x2779 */
        MSP_ERROR_INVALID_PARA = 10106,     /* 0x277A */
        MSP_ERROR_INVALID_PARA_VALUE = 10107,     /* 0x277B */
        MSP_ERROR_INVALID_HANDLE = 10108,     /* 0x277C */
        MSP_ERROR_INVALID_DATA = 10109,     /* 0x277D */
        MSP_ERROR_NO_LICENSE = 10110,     /* 0x277E */
        MSP_ERROR_NOT_INIT = 10111,     /* 0x277F */
        MSP_ERROR_NULL_HANDLE = 10112,     /* 0x2780 */
        MSP_ERROR_OVERFLOW = 10113,     /* 0x2781 */
        MSP_ERROR_TIME_OUT = 10114,     /* 0x2782 */
        MSP_ERROR_OPEN_FILE = 10115,     /* 0x2783 */
        MSP_ERROR_NOT_FOUND = 10116,     /* 0x2784 */
        MSP_ERROR_NO_ENOUGH_BUFFER = 10117,     /* 0x2785 */
        MSP_ERROR_NO_DATA = 10118,     /* 0x2786 */
        MSP_ERROR_NO_MORE_DATA = 10119,     /* 0x2787 */
        MSP_ERROR_SKIPPED = 10120,     /* 0x2788 */
        MSP_ERROR_ALREADY_EXIST = 10121,     /* 0x2789 */
        MSP_ERROR_LOAD_MODULE = 10122,     /* 0x278A */
        MSP_ERROR_BUSY = 10123,     /* 0x278B */
        MSP_ERROR_INVALID_CONFIG = 10124,     /* 0x278C */
        MSP_ERROR_VERSION_CHECK = 10125,     /* 0x278D */
        MSP_ERROR_CANCELED = 10126,     /* 0x278E */
        MSP_ERROR_INVALID_MEDIA_TYPE = 10127,     /* 0x278F */
        MSP_ERROR_CONFIG_INITIALIZE = 10128,     /* 0x2790 */
        MSP_ERROR_CREATE_HANDLE = 10129,     /* 0x2791 */
        MSP_ERROR_CODING_LIB_NOT_LOAD = 10130,     /* 0x2792 */

        /* Error codes of network 10200(0x27D8)*/
        MSP_ERROR_NET_GENERAL = 10200,     /* 0x27D8 */
        MSP_ERROR_NET_OPENSOCK = 10201,     /* 0x27D9 */   /* Open socket */
        MSP_ERROR_NET_CONNECTSOCK = 10202,     /* 0x27DA */   /* Connect socket */
        MSP_ERROR_NET_ACCEPTSOCK = 10203,     /* 0x27DB */   /* Accept socket */
        MSP_ERROR_NET_SENDSOCK = 10204,     /* 0x27DC */   /* Send socket data */
        MSP_ERROR_NET_RECVSOCK = 10205,     /* 0x27DD */   /* Recv socket data */
        MSP_ERROR_NET_INVALIDSOCK = 10206,     /* 0x27DE */   /* Invalid socket handle */
        MSP_ERROR_NET_BADADDRESS = 10207,     /* 0x27EF */   /* Bad network address */
        MSP_ERROR_NET_BINDSEQUENCE = 10208,     /* 0x27E0 */   /* Bind after listen/connect */
        MSP_ERROR_NET_NOTOPENSOCK = 10209,     /* 0x27E1 */   /* Socket is not opened */
        MSP_ERROR_NET_NOTBIND = 10210,     /* 0x27E2 */   /* Socket is not bind to an address */
        MSP_ERROR_NET_NOTLISTEN = 10211,     /* 0x27E3 */   /* Socket is not listenning */
        MSP_ERROR_NET_CONNECTCLOSE = 10212,     /* 0x27E4 */   /* The other side of connection is closed */
        MSP_ERROR_NET_NOTDGRAMSOCK = 10213,     /* 0x27E5 */   /* The socket is not datagram type */
        MSP_ERROR_NET_DNS=10214,
        /* Error codes of mssp message 10300(0x283C) */
        MSP_ERROR_MSG_GENERAL = 10300,     /* 0x283C */
        MSP_ERROR_MSG_PARSE_ERROR = 10301,     /* 0x283D */
        MSP_ERROR_MSG_BUILD_ERROR = 10302,     /* 0x283E */
        MSP_ERROR_MSG_PARAM_ERROR = 10303,     /* 0x283F */
        MSP_ERROR_MSG_CONTENT_EMPTY = 10304,     /* 0x2840 */
        MSP_ERROR_MSG_INVALID_CONTENT_TYPE = 10305,     /* 0x2841 */
        MSP_ERROR_MSG_INVALID_CONTENT_LENGTH = 10306,     /* 0x2842 */
        MSP_ERROR_MSG_INVALID_CONTENT_ENCODE = 10307,     /* 0x2843 */
        MSP_ERROR_MSG_INVALID_KEY = 10308,     /* 0x2844 */
        MSP_ERROR_MSG_KEY_EMPTY = 10309,     /* 0x2845 */
        MSP_ERROR_MSG_SESSION_ID_EMPTY = 10310,     /* 0x2846 */
        MSP_ERROR_MSG_LOGIN_ID_EMPTY = 10311,     /* 0x2847 */
        MSP_ERROR_MSG_SYNC_ID_EMPTY = 10312,     /* 0x2848 */
        MSP_ERROR_MSG_APP_ID_EMPTY = 10313,     /* 0x2849 */
        MSP_ERROR_MSG_EXTERN_ID_EMPTY = 10314,     /* 0x284A */
        MSP_ERROR_MSG_INVALID_CMD = 10315,     /* 0x284B */
        MSP_ERROR_MSG_INVALID_SUBJECT = 10316,     /* 0x284C */
        MSP_ERROR_MSG_INVALID_VERSION = 10317,     /* 0x284D */
        MSP_ERROR_MSG_NO_CMD = 10318,     /* 0x284E */
        MSP_ERROR_MSG_NO_SUBJECT = 10319,     /* 0x284F */
        MSP_ERROR_MSG_NO_VERSION = 10320,     /* 0x2850 */
        MSP_ERROR_MSG_MSSP_EMPTY = 10321,     /* 0x2851 */
        MSP_ERROR_MSG_NEW_RESPONSE = 10322,     /* 0x2852 */
        MSP_ERROR_MSG_NEW_CONTENT = 10323,     /* 0x2853 */
        MSP_ERROR_MSG_INVALID_SESSION_ID = 10324,     /* 0x2854 */

        /* Error codes of DataBase 10400(0x28A0)*/
        MSP_ERROR_DB_GENERAL = 10400,     /* 0x28A0 */
        MSP_ERROR_DB_EXCEPTION = 10401,     /* 0x28A1 */
        MSP_ERROR_DB_NO_RESULT = 10402,     /* 0x28A2 */
        MSP_ERROR_DB_INVALID_USER = 10403,     /* 0x28A3 */
        MSP_ERROR_DB_INVALID_PWD = 10404,     /* 0x28A4 */
        MSP_ERROR_DB_CONNECT = 10405,     /* 0x28A5 */
        MSP_ERROR_DB_INVALID_SQL = 10406,     /* 0x28A6 */
        MSP_ERROR_DB_INVALID_APPID = 10407,    /* 0x28A7 */

        /* Error codes of Resource 10500(0x2904)*/
        MSP_ERROR_RES_GENERAL = 10500,     /* 0x2904 */
        MSP_ERROR_RES_LOAD = 10501,     /* 0x2905 */   /* Load resource */
        MSP_ERROR_RES_FREE = 10502,     /* 0x2906 */   /* Free resource */
        MSP_ERROR_RES_MISSING = 10503,     /* 0x2907 */   /* Resource File Missing */
        MSP_ERROR_RES_INVALID_NAME = 10504,     /* 0x2908 */   /* Invalid resource file name */
        MSP_ERROR_RES_INVALID_ID = 10505,     /* 0x2909 */   /* Invalid resource ID */
        MSP_ERROR_RES_INVALID_IMG = 10506,     /* 0x290A */   /* Invalid resource image pointer */
        MSP_ERROR_RES_WRITE = 10507,     /* 0x290B */   /* Write read-only resource */
        MSP_ERROR_RES_LEAK = 10508,     /* 0x290C */   /* Resource leak out */
        MSP_ERROR_RES_HEAD = 10509,     /* 0x290D */   /* Resource head currupt */
        MSP_ERROR_RES_DATA = 10510,     /* 0x290E */   /* Resource data currupt */
        MSP_ERROR_RES_SKIP = 10511,     /* 0x290F */   /* Resource file skipped */

        /* Error codes of TTS 10600(0x2968)*/
        MSP_ERROR_TTS_GENERAL = 10600,     /* 0x2968 */
        MSP_ERROR_TTS_TEXTEND = 10601,     /* 0x2969 */  /* Meet text end */
        MSP_ERROR_TTS_TEXT_EMPTY = 10602,     /* 0x296A */  /* no synth text */

        /* Error codes of Recognizer 10700(0x29CC) */
        MSP_ERROR_REC_GENERAL = 10700,     /* 0x29CC */
        MSP_ERROR_REC_INACTIVE = 10701,     /* 0x29CD */
        MSP_ERROR_REC_GRAMMAR_ERROR = 10702,     /* 0x29CE */
        MSP_ERROR_REC_NO_ACTIVE_GRAMMARS = 10703,     /* 0x29CF */
        MSP_ERROR_REC_DUPLICATE_GRAMMAR = 10704,     /* 0x29D0 */
        MSP_ERROR_REC_INVALID_MEDIA_TYPE = 10705,     /* 0x29D1 */
        MSP_ERROR_REC_INVALID_LANGUAGE = 10706,     /* 0x29D2 */
        MSP_ERROR_REC_URI_NOT_FOUND = 10707,     /* 0x29D3 */
        MSP_ERROR_REC_URI_TIMEOUT = 10708,     /* 0x29D4 */
        MSP_ERROR_REC_URI_FETCH_ERROR = 10709,     /* 0x29D5 */

        /* Error codes of Speech Detector 10800(0x2A30) */
        MSP_ERROR_EP_GENERAL = 10800,     /* 0x2A30 */
        MSP_ERROR_EP_NO_SESSION_NAME = 10801,     /* 0x2A31 */
        MSP_ERROR_EP_INACTIVE = 10802,     /* 0x2A32 */
        MSP_ERROR_EP_INITIALIZED = 10803,     /* 0x2A33 */

        /* Error codes of TUV */
        MSP_ERROR_TUV_GENERAL = 10900,     /* 0x2A94 */
        MSP_ERROR_TUV_GETHIDPARAM = 10901,     /* 0x2A95 */   /* Get Busin Param huanid*/
        MSP_ERROR_TUV_TOKEN = 10902,     /* 0x2A96 */   /* Get Token */
        MSP_ERROR_TUV_CFGFILE = 10903,     /* 0x2A97 */   /* Open cfg file */
        MSP_ERROR_TUV_RECV_CONTENT = 10904,     /* 0x2A98 */   /* received content is error */
        MSP_ERROR_TUV_VERFAIL = 10905,     /* 0x2A99 */   /* Verify failure */

        /* Error codes of IMTV */
        MSP_ERROR_IMTV_SUCCESS = 11000,     /* 0x2AF8 */   /* 成功 */
        MSP_ERROR_IMTV_NO_LICENSE = 11001,     /* 0x2AF9 */   /* 试用次数结束,用户需要付费 */
        MSP_ERROR_IMTV_SESSIONID_INVALID = 11002,     /* 0x2AFA */   /* SessionId失效,需要重新登录通行证 */
        MSP_ERROR_IMTV_SESSIONID_ERROR = 11003,     /* 0x2AFB */   /* SessionId为空,或者非法 */
        MSP_ERROR_IMTV_UNLOGIN = 11004,     /* 0x2AFC */   /* 未登录通行证 */
        MSP_ERROR_IMTV_SYSTEM_ERROR = 11005,     /* 0x2AFD */   /* 系统错误 */

        /* Error codes of HCR */
        MSP_ERROR_HCR_GENERAL = 11100,
        MSP_ERROR_HCR_RESOURCE_NOT_EXIST = 11101,

        /* Error codes of http 12000(0x2EE0) */
        MSP_ERROR_HTTP_BASE = 12000,    /* 0x2EE0 */

        /*Error codes of ISV */
        MSP_ERROR_ISV_NO_USER = 13000,    /* 32C8 */    /* the user doesn't exist */
    }
    #endregion

    #region ISR枚举常量
    public enum AudioStatus
    {
        ISR_AUDIO_SAMPLE_INIT = 0x00,
        ISR_AUDIO_SAMPLE_FIRST = 0x01,
        ISR_AUDIO_SAMPLE_CONTINUE = 0x02,
        ISR_AUDIO_SAMPLE_LAST = 0x04,
        ISR_AUDIO_SAMPLE_SUPPRESSED = 0x08,
        ISR_AUDIO_SAMPLE_LOST = 0x10,
        ISR_AUDIO_SAMPLE_NEW_CHUNK = 0x20,
        ISR_AUDIO_SAMPLE_END_CHUNK = 0x40,

        ISR_AUDIO_SAMPLE_VALIDBITS = 0x7f /* to validate the value of sample->status */
    }

    public enum EpStatus
    {
        ISR_EP_NULL = -1,
        ISR_EP_LOOKING_FOR_SPEECH = 0,          ///还没有检测到音频的前端点
        ISR_EP_IN_SPEECH = 1,                   ///已经检测到了音频前端点,正在进行正常的音频处理。
        ISR_EP_AFTER_SPEECH = 3,                ///检测到音频的后端点,后继的音频会被MSC忽略。
        ISR_EP_TIMEOUT = 4,                     ///超时
        ISR_EP_ERROR = 5,                       ///出现错误
        ISR_EP_MAX_SPEECH = 6                   ///音频过大
    }

    public enum RecogStatus
    {
        ISR_REC_NULL = -1,
        ISR_REC_STATUS_SUCCESS = 0,             ///识别成功,此时用户可以调用QISRGetResult来获取(部分)结果。
        ISR_REC_STATUS_NO_MATCH = 1,            ///识别结束,没有识别结果
        ISR_REC_STATUS_INCOMPLETE = 2,          ///正在识别中
        ISR_REC_STATUS_NON_SPEECH_DETECTED = 3, ///保留
        ISR_REC_STATUS_SPEECH_DETECTED = 4,     ///发现有效音频
        ISR_REC_STATUS_SPEECH_COMPLETE = 5,     ///识别结束
        ISR_REC_STATUS_MAX_CPU_TIME = 6,        ///保留
        ISR_REC_STATUS_MAX_SPEECH = 7,          ///保留
        ISR_REC_STATUS_STOPPED = 8,             ///保留
        ISR_REC_STATUS_REJECTED = 9,            ///保留
        ISR_REC_STATUS_NO_SPEECH_FOUND = 10     ///没有发现音频
    }
    #endregion
}

自定义异常:

[Serializable] //声明为可序列化的 因为要写入文件中  
    public class MscException : ApplicationException//由用户程序引发,用于派生自定义的异常类型  
    {
        /// <summary>  
        /// 默认构造函数  
        /// </summary>  
        public MscException() { }
        public MscException(string message)
            : base(message) { }
        public MscException(string message, Exception inner)
            : base(message, inner) { }
    } 
    /// <summary>
    /// 是否出错
    /// </summary>
    internal class RecoErrors
    {
        public RecoErrors() { }
        /// <summary>  
        /// 是否发生错误.  
        /// </summary>  
        /// <param name="id">错误ID</param>  
        public virtual void GetError(int id)
        {
            if (id != 0)
            {               
                var ex = new MscException(((ErrorCode)id).ToString("G"));
               // var ex = new MscException(Enum.GetName(typeof(ErrorCode),id));
                throw ex;
            }
        }
    }

讯飞语音支持边录边上传,不过我这里采用是一次性上传。起初我采用的是边录边上传,不过感觉有数字混合后识别正常率不好(还没跟讯飞那边沟通。),最后才使用一次性上传,毕竟语音文件也不是大就200KB一下。讯飞语音识别不支持多线程识别。

我做的这个语音识别产品,做成服务端与客户端。服务端:放在一个能连接外网机子上提供语音识别(做了一个简单队列),客户端:将音频数据采集后发送到局域网内的语音识别服务端进行识别。

以上有些代码是借助别人的,第一次写大家尽量不要吐槽,不过可以给点意见。大家相互学习…

[转载]Android ZXing 二维码、条形码扫描介绍-Android开发源码下载-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(877)

[转载]Android ZXing 二维码、条形码扫描介绍-Android开发源码下载-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

最近公司的Android项目需要用到摄像头做条码或二维码的扫描,Google一下,发现一个开源的 ZXing项目。它提供二维码和条形码的扫描。扫描条形码就是直接读取条形码的内容,扫描二维码是按照自己指定的二维码格式进行编码和解码。

1.什么是二维码和条形码?

                        

二 维条形码最早发明于日本,它是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的,在代码编制上巧妙地利用构成 计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实 现信息自动处理。它具有条码技术的一些共性:每种码制有其特定的字符集;每个字符占有一定的宽度;具有一定的校验功能等。同时还具有对不同行的信息自动识 别功能、及处理图形旋转变化等特点。

条 形码(barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符。常见的条形码是由反射率相差很大的黑条 (简称条)和白条(简称空)排成的平行线图案。条形码可以标出物品的生产国、制造厂家、商品名称、生产日期、图书分类号、邮件起止地点、类别、日期等许多 信息,因而在商品流通、图书管理、邮政管理、银行系统等许多领域都得到广泛的应用。

2.ZXing基本介绍

ZXing是一个开源Java类库用于解析多种格式的条形码和二维码.官网:http://code.google.com/p/zxing/

截止目前为止最新版本提供以下编码格式的支持:

  • UPC-A and UPC-E
  • EAN-8 and EAN-13
  • Code 39
  • Code 93
  • Code 128
  • QR Code
  • ITF
  • Codabar
  • RSS-14 (all variants)
  • Data Matrix
  • PDF 417 (‘alpha’ quality)
  • Aztec (‘alpha’ quality)

同时官网提供了 Android、cpp、C#、iPhone、j2me、j2se、jruby、objc、rim、symbian等多种应用的类库,具体详情可以参考下载的源码包中。

3.Android端编码演示

这里使用的ZXing是经过简化版的,去除了一些一般使用不必要的文件,项目工程和效果截图如下:

   

其 中encoding包是在原基础上加上去的,功能是根据传入的字符串来生成二维码图片,返回一个Bitmap,其余的包是ZXing项目自带的。另外对扫 描界面的布局也进行了修改,官方的扫描界面是横向的,我改成了纵向的,并加入了顶部的Tab和取消按钮(camera.xml),另外还需要的一些文件是 colors.xml、ids.xml,这些都是原本ZXing项目中自带的,最后就是libs下面的jar包。

接下来看如何使用,首先是把ZXing项目中的一些文件拷贝到我们自己的项目中,然后在Mainifest文件中进行配置权限:


还有就是扫描界面Activity的配置:


接下来是我自己项目的布局文件:

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

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

下面是主Activity的代码,主要功能是打开扫描框、显示扫描结果、根据输入的字符串生成二维码图片:

public class BarCodeTestActivity extends Activity {
/** Called when the activity is first created. */
private TextView resultTextView;
private EditText qrStrEditText;
private ImageView qrImgImageView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

resultTextView = (TextView) this.findViewById(R.id.tv_scan_result);
qrStrEditText = (EditText) this.findViewById(R.id.et_qr_string);
qrImgImageView = (ImageView) this.findViewById(R.id.iv_qr_image);

Button scanBarCodeButton = (Button) this.findViewById(R.id.btn_scan_barcode);
scanBarCodeButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
//打开扫描界面扫描条形码或二维码
Intent openCameraIntent = new Intent(BarCodeTestActivity.this,CaptureActivity.class);
startActivityForResult(openCameraIntent, 0);
}
});

Button generateQRCodeButton = (Button) this.findViewById(R.id.btn_add_qrcode);
generateQRCodeButton.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
try {
String contentString = qrStrEditText.getText().toString();
if (!contentString.equals("")) {
//根据字符串生成二维码图片并显示在界面上,第二个参数为图片的大小(350*350)
Bitmap qrCodeBitmap = EncodingHandler.createQRCode(contentString, 350);
qrImgImageView.setImageBitmap(qrCodeBitmap);
}else {
Toast.makeText(BarCodeTestActivity.this, "Text can not be empty", Toast.LENGTH_SHORT).show();
}

} catch (WriterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//处理扫描结果(在界面上显示)
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
String scanResult = bundle.getString("result");
resultTextView.setText(scanResult);
}
}
}

其中生成二维码图片的代码在EncodingHandler.java中:

public final class EncodingHandler {
private static final int BLACK = 0xff000000;

public static Bitmap createQRCode(String str,int widthAndHeight) throws WriterException {
Hashtable&lt;EncodeHintType, String&gt; hints = new Hashtable&lt;EncodeHintType, String&gt;();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
BitMatrix matrix = new MultiFormatWriter().encode(str,
BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight);
int width = matrix.getWidth();
int height = matrix.getHeight();
int[] pixels = new int[width * height];

for (int y = 0; y &lt; height; y++) {
for (int x = 0; x &lt; width; x++) {
if (matrix.get(x, y)) {
pixels[y * width + x] = BLACK;
}
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
}

最后是在哪里对扫描结果进行解码,进入CaptureActivity.java找到下面这个方法便可以对自己对结果进行操作:

/**
* Handler scan result
* @param result
* @param barcode
*/
public void handleDecode(Result result, Bitmap barcode) {
inactivityTimer.onActivity();
playBeepSoundAndVibrate();
String resultString = result.getText();
//FIXME
if (resultString.equals("")) {
Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
}else {
// System.out.println("Result:"+resultString);
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putString("result", resultString);
resultIntent.putExtras(bundle);
this.setResult(RESULT_OK, resultIntent);
}
CaptureActivity.this.finish();
}

4.Java端编码演示

在Java端上实现条形码(EAN-13)和二维码(QRCode) 的编码和解码的示例,以供大家参考,用到了源码中core和javase下面的相关源代码,附件提供自己编译之后的lib包:
zxing.jar
zxing-j2se.jar
有关各种手机系统的应用,有兴趣的朋友可以下载官方源码包,包下有具体详细的应用介绍。
1)二维码(QRCode)的编码和解码演示:
编码示例:

package michael.zxing;

import java.io.File;
import java.util.Hashtable;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
* [url=home.php?mod=space&amp;uid=618199]@blog[/url] http://sjsky.iteye.com
* @author Michael
*/
public class ZxingEncoderHandler {

/**
* 编码
* @param contents
* @param width
* @param height
* @param imgPath
*/
public void encode(String contents, int width, int height, String imgPath) {
Hashtable&lt;Object, Object&gt; hints = new Hashtable&lt;Object, Object&gt;();
// 指定纠错等级
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
// 指定编码格式
hints.put(EncodeHintType.CHARACTER_SET, "GBK");
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
BarcodeFormat.QR_CODE, width, height, hints);

MatrixToImageWriter
.writeToFile(bitMatrix, "png", new File(imgPath));

} catch (Exception e) {
e.printStackTrace();
}
}

/**
* @param args
*/
public static void main(String[] args) {
String imgPath = "d:/1.png";
String contents = "Hello Word!";
int width = 300, height = 300;
ZxingEncoderHandler handler = new ZxingEncoderHandler();
handler.encode(contents, width, height, imgPath);
}
}
运行后生成的二维码图片如下:
用手机的二维码扫描软件(本人用的:android 快拍二维码 )来测试下,识别成功的截图如下:
解码示例:

package michael.zxing;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

/**
* @blog http://sjsky.iteye.com
* @author Michael
*/
public class ZxingDecoderHandler {

/**
* @param imgPath
* [url=home.php?mod=space&amp;uid=7300]@return[/url] String
*/
public String decode(String imgPath) {
BufferedImage image = null;
Result result = null;
try {
image = ImageIO.read(new File(imgPath));
if (image == null) {
System.out.println("the decode image may be not exit.");
}
LuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

Hashtable&lt;Object, Object&gt; hints = new Hashtable&lt;Object, Object&gt;();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");

result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**
* @param args
*/
public static void main(String[] args) {
String imgPath = "d:/1.png";
ZxingDecoderHandler handler = new ZxingDecoderHandler();
String decodeContent = handler.decode(imgPath);
System.out.println("解码内容如下:");
System.out.println(decodeContent);
}
}

Hello Word!
2)条形码(EAN-13)的编码和解码演示:
编码示例:

package michael.zxing;

import java.io.File;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;

/**
* @blog http://sjsky.iteye.com
* @author Michael
*/
public class ZxingEAN13EncoderHandler {

/**
* 编码
* @param contents
* @param width
* @param height
* @param imgPath
*/
public void encode(String contents, int width, int height, String imgPath) {
int codeWidth = 3 + // start guard
(7 * 6) + // left bars
5 + // middle guard
(7 * 6) + // right bars
3; // end guard
codeWidth = Math.max(codeWidth, width);
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
BarcodeFormat.EAN_13, codeWidth, height, null);

MatrixToImageWriter
.writeToFile(bitMatrix, "png", new File(imgPath));

} catch (Exception e) {
e.printStackTrace();
}
}

/**
* @param args
*/
public static void main(String[] args) {
String imgPath = "d:/2.png";
// 益达无糖口香糖的条形码
String contents = "6923450657713";

int width = 105, height = 50;
ZxingEAN13EncoderHandler handler = new ZxingEAN13EncoderHandler();
handler.encode(contents, width, height, imgPath);
}
}
运行后生成条形码图片如下:

用手机的条形码扫描软件(本人用的:android 快拍二维码 )来测试下,识别成功的截图如下:
解码示例:
package michael.zxing;

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

/**
 * @blog http://sjsky.iteye.com
 * @author Michael
 */
public class ZxingEAN13DecoderHandler {

    /**
     * @param imgPath
     * @return String
     */
    public String decode(String imgPath) {
        BufferedImage image = null;
        Result result = null;
        try {
            image = ImageIO.read(new File(imgPath));
            if (image == null) {
                System.out.println("the decode image may be not exit.");
            }
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

            result = new MultiFormatReader().decode(bitmap, null);
            return result.getText();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        String imgPath = "d:/2.png";
        ZxingEAN13DecoderHandler handler = new ZxingEAN13DecoderHandler();
        String decodeContent = handler.decode(imgPath);
        System.out.println("解码内容如下:");
        System.out.println(decodeContent);
    }
}

解码内容如下:
6923450657713

5.源码说明和下载
官方例子:
BarcodeScanner (Barcode Scanner 4.31 for Android Featured 必须先将此apk安装才可以运行ZXingTest项目)
ZXingTest (android端调用BarcodeScanner测试例子)
简化例子:
BarCodeTest (android端扫描和解码精简例子)
QRcode (java端扫描和解码例子)

[转载]微享,微信分享实例-Android开发源码下载-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(922)

[转载]微享,微信分享实例-Android开发源码下载-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

最近在搞微信分享,因此做了个小应用,坑爹的微信官方文档,真让人火大,这是后话了,先看我这个应用的效果图:


主要有三个功能,拍照立即分享、取本地照片分享、微信好友及好友圈,我一一讲解,先看项目结构图:

(一)拍照
//打开相机
private final int CAMERA_CODE = 1; // 这里的CAMERA_CODE 是自己任意定义的

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent,CAMERA_CODE);

//onActivityResult方法返回处理拍照照片

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) { // 此处的 RESULT_OK 是系统自定义得一个常量
Toast.makeText(WXEntryActivity.this, "操作取消", Toast.LENGTH_SHORT)
.show();
return;
}
switch (requestCode) {
case CAMERA_CODE:
if (data != null) {
// HTC
if (data.getData() != null) {
// 根据返回的URI获取对应的SQLite信息
Cursor cursor = getContentResolver().query(data.getData(),
null, null, null, null);
if (cursor.moveToFirst()) {
filePath = cursor.getString(cursor
.getColumnIndex("_data"));// 获取绝对路径
}
cursor.close();
} else {
// 三星 小米(小米手机不会自动存储DCIM
mBitmap = (Bitmap) (data.getExtras() == null ? null : data
.getExtras().get("data"));
}

// 直接强转报错 这个主要是为了去高宽比例
Bitmap bitmap = mBitmap == null ? null : (Bitmap) mBitmap;

if (bitmap == null) {
/**
* 该Bitmap是为了获取压缩后的文件比例 如果没有缩略图的比例
* 就获取真实文件的比例(真实图片比例会耗时很长,所以如果有缩略图最好)
*/
bitmap = BitmapFactory.decodeFile(filePath);
}
path = AppUtil.saveBitmap(bitmap);
shareImg.setImageBitmap(AppUtil.getLoacalBitmap(path)); // 设置Bitmap
isPicture = true;
}
break;
default:
break;
}

}

其中saveBitmap()方法:

/**
* 是否存在SDCard
*
*/
public static boolean hasSdCard() {
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
return true;
}
return false;
}

/**
* 将Bitmap保存在本地
*
* @param mBitmap
* @return
*/
@SuppressLint("SimpleDateFormat")
public static String saveBitmap(Bitmap mBitmap) {

try {
String sdCardPath = "";
if (hasSdCard()) {
sdCardPath = Environment.getExternalStorageDirectory()
.getPath();
} else {

}

String filePath = sdCardPath + "/" + "MicroShare/";

Date date = new Date(System.currentTimeMillis());

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");// 时间格式-显示方式

String imgPath = filePath + sdf.format(date) + ".png";

File file = new File(filePath);

if (!file.exists()) {
file.mkdirs();
}
File imgFile = new File(imgPath);

if (!imgFile.exists()) {
imgFile.createNewFile();
}

FileOutputStream fOut = new FileOutputStream(imgFile);

mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);

fOut.flush();

if (fOut != null) {

fOut.close();
}
return imgPath;

} catch (IOException e) {
e.printStackTrace();
}
return null;
}

这样拍照的过程完了,分享等下再说。

(二)本地照片
// 使用intent调用系统提供的相册功能,使用startActivityForResult是为了获取用户选择的图片
private final int IMAGE_CODE = 0; // 这里的IMAGE_CODE是自己任意定义的

Intent getAlbum = new Intent( Intent.ACTION_GET_CONTENT);
getAlbum.setType(IMAGE_TYPE);
startActivityForResult(getAlbum,IMAGE_CODE);

//onActivityResult方法返回处理照片

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) { // 此处的 RESULT_OK 是系统自定义得一个常量
Toast.makeText(WXEntryActivity.this, "操作取消", Toast.LENGTH_SHORT)
.show();
return;
}

switch (requestCode) {
case IMAGE_CODE:
Bitmap bm = null;
// 外界的程序访问ContentProvider所提供数据 可以通过ContentResolver接口
ContentResolver resolver = getContentResolver();
try {
Uri originalUri = data.getData(); // 获得图片的uri
bm = MediaStore.Images.Media.getBitmap(resolver, originalUri); // 显得到bitmap图片

// 这里开始的第二部分,获取图片的路径:
String[] proj = { MediaStore.Images.Media.DATA };

// 好像是android多媒体数据库的封装接口,具体的看Android文档
Cursor cursor = managedQuery(originalUri, proj, null, null,
null);

// 按我个人理解 这个是获得用户选择的图片的索引值
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);

// 将光标移至开头 ,这个很重要,不小心很容易引起越界
cursor.moveToFirst();

// 最后根据索引值获取图片路径
path = cursor.getString(column_index);
Bitmap bitmap = AppUtil.getLoacalBitmap(path); // 从本地取图片(在cdcard中获取)
shareImg.setImageBitmap(bitmap); // 设置Bitmap
isPicture = true;
} catch (IOException e) {
Toast.makeText(WXEntryActivity.this, e.toString(),
Toast.LENGTH_SHORT).show();

}
break;
default:
break;
}

}

提示:调用系统提供的相册功能时,请选择系统的相册功能进入,比如:

这里请选择系统的,如果你选择第三方进入它的的相册肯定是报错,关于这个错误我没有做处理。

(三)微信分享
这部分是重点也是难点,我慢慢讲解我两天做的微 信分享的心得,首先我给的项目源码你们肯定跑不起来,因为我的这项目已经微信审核通过了,审核的时候应用签名(打包时MD5值)和包名绑定了,因此运行源 码是不能调微信客户端的。附件里已经附带了我打包好了apk,大家可以跑这个看效果。

1、申请你的appid
请到 微信开发者应用登记页面 进行登记,登记并选择移动应用进行设置后,将该应用提交审核,只有审核通过的应用才能进行开发。

2、导jar包
在工程中新建一个libs目录,将开发工具包中libs目录下的libammsdk.jar复制到该目录中(如下图所示,建立了一个名为SDK_Sample 的工程,并把jar包复制到libs目录下)。

3、代码编写
(1)初始化、注册

// 通过WXAPIFactory工厂,获取IWXAPI的实例
api = WXAPIFactory.createWXAPI(this, APP_ID, false);
// 将该app注册到微信
api.registerApp(APP_ID);
api.handleIntent(getIntent(), this);//此行后面再说

(2)分享部分
此项目制涉及分享本地的图片,代码如下:

// 微信好友
case 0:
weixinShare(true);
break;
// 微信朋友圈
case 1:
weixinShare(false);
break;

weixinShare方法:

private void weixinShare(boolean isFriend) {

File file = new File(path);
if (!file.exists()) {
String tip = WXEntryActivity.this
.getString(R.string.send_img_file_not_exist);
Toast.makeText(WXEntryActivity.this, tip + " path = " + path,
Toast.LENGTH_LONG).show();
return;
}
WXImageObject imgObj = new WXImageObject();
imgObj.setImagePath(path);

WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;

Bitmap bmp = BitmapFactory.decodeFile(path);
Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE,
THUMB_SIZE, true);
bmp.recycle();
msg.thumbData = Util.bmpToByteArray(thumbBmp, true);

int imageSize = msg.thumbData.length / 1024;
if (imageSize &gt; 32) {
Toast.makeText(WXEntryActivity.this, "您分享的图片过大", Toast.LENGTH_SHORT)
.show();
return;
}

SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("img");
req.message = msg;
req.scene = isFriend ? SendMessageToWX.Req.WXSceneSession
: SendMessageToWX.Req.WXSceneTimeline;
api.sendReq(req);
finish();
}

注意点:如果分享的图片大于35k,微信客户端是没有响应的,因此做了判断,这是官方demo没有的,官方文档有讲解。
(3)接收微信的请求及返回值如果你的程序需要接收微信发送的请求,或者接收发送到微信请求的响应结果,需要下面3步操作:
a. 在你的包名相应目录下新建一个wxapi目录,并在该wxapi目录下新增一个WXEntryActivity类(注意点:必须是wxapi目录,WXEntryActivity类),该类继承自Activity并在manifest文件里面加上exported属性,设置为true,例如:

b. 实现IWXAPIEventHandler接口,微信发送的请求将回调到onReq方法,发送到微信请求的响应结果将回调到onResp方法
c. 在WXEntryActivity中将接收到的intent及实现了IWXAPIEventHandler接口的对象传递给IWXAPI接口的handleIntent方法,示例如下:

api.handleIntent(getIntent(), this);

当微信发送请求到你的应用,将通过IWXAPIEventHandler接口的onReq方法进行回调,类似的,应用请求微信的响应结果将通过onResp回调。

protected void onNewIntent(Intent intent) {
                super.onNewIntent(intent);
 
                setIntent(intent);
                api.handleIntent(intent, this);
        }
 
        // 微信发送请求到第三方应用时,会回调到该方法
        @Override
        public void onReq(BaseReq req) {
        }
 
        // 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法
        @Override
        public void onResp(BaseResp resp) {
 
                String result = "";
                switch (resp.errCode) {
                case BaseResp.ErrCode.ERR_OK:
                        result = "发送成功";
                        break;
                case BaseResp.ErrCode.ERR_USER_CANCEL:
                        result = "分享取消";
                        break;
                case BaseResp.ErrCode.ERR_AUTH_DENIED:
                        result = "发送失败";
                        break;
                default:
                        result = "出现异常";
                        break;
                }
                Toast.makeText(this, result, Toast.LENGTH_LONG).show();
        }

(四)其他功能
(1)再按一次退出程序

private static Boolean isExit = false;
 
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_BACK) {
                        if (isExit == false) {
                                isExit = true;
                                Toast.makeText(this, "再按一次退出程序", Toast.LENGTH_SHORT).show();
                                new Timer().schedule(new TimerTask() {
                                        @Override
                                        public void run() {
                                                isExit = false;
                                        }
                                }, 2000);
                        } else {
                                finish();
                                System.exit(0);
                        }
                }
                return false;
        }

(2)检测网络

public boolean checkNetworkInfo() {
                ConnectivityManager conMan = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                // mobile 3G Data Network
                State mobile = conMan.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
                                .getState();
                // wifi
                State wifi = conMan.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
                                .getState();
                // 如果3G网络和wifi网络都未连接,且不是处于正在连接状态 则进入Network Setting界面 由用户配置网络连接
 
                if (mobile == State.CONNECTED || mobile == State.CONNECTING)
                        return true;
                if (wifi == State.CONNECTED || wifi == State.CONNECTING)
                        return true;
 
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage("网络不给力")
                                .setTitle("提示")
                                .setCancelable(false)
                                .setPositiveButton("配置", new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int id) {
 
                                                // 进入无线网络配置界面
                                                startActivity(new Intent(
                                                                Settings.ACTION_WIRELESS_SETTINGS));
                                                WXEntryActivity.this.finish();
                                        }
                                })
                                .setNegativeButton("退出", new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int id) {
                                                WXEntryActivity.this.finish();
                                        }
                                });
                builder.show();
                return false;
 
        }

[转载]FlexPaper+SWFTool+操作类=在线预览PDF - wolfy - 博客园

mikel阅读(1037)

[转载]FlexPaper+SWFTool+操作类=在线预览PDF – wolfy – 博客园.

引言

由于客户有在线预览PDF格式的需求,在网上找了一下解决方案,觉得FlexPaper用 起来还是挺方便的,flexpaper是将pdf转换为swf格式的文件预览的,所以flexpaper一般和swftool配合使用,在程序运行时将 pdf文件转换为swf格式的文件。

如果flexpaper不满足你的要求,也可以对其进行二次开发,这里推荐两篇文章,希望对您有所帮助:

http://www.cnblogs.com/xcong/archive/2013/06/20/3142155.html

http://www.cnblogs.com/zamlove/archive/2013/05/07/3065079.html

如何使用flexpaper

测试demo项目结构如图

使用的页面代码:


<!-- saved from url=(0014)about:internet -->

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<style type="text/css" media="screen"><!--
html, body { height: 100%; } body { margin: 0; padding: 0; overflow: auto; } #flashContent { display: none; }
--></style><!--首先引入相关的js文件-->
<script type="text/javascript" src="js/swfobject/swfobject.js"></script><script type="text/javascript" src="js/flexpaper_flash.js"></script>
<!--配置-->
<script type="text/javascript">// <![CDATA[
For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. -->
        var swfVersionStr = "10.0.0";
        <!-- To use express install, set to playerProductInstall.swf, otherwise the empty string. -->
        var xiSwfUrlStr = "playerProductInstall.swf";

        var flashvars = {
            SwfFile: escape("Paper.swf"),
            Scale: 0.6,
            ZoomTransition: "easeOut",
            ZoomTime: 0.5,
            ZoomInterval: 0.1,
            FitPageOnLoad: false,
            FitWidthOnLoad: true,
            PrintEnabled: true,
            FullScreenAsMaxWindow: false,
            ProgressiveLoading: true,
            PrintToolsVisible: true,
            ViewModeToolsVisible: true,
            ZoomToolsVisible: true,
            FullScreenVisible: true,
            NavToolsVisible: true,
            CursorToolsVisible: true,
            SearchToolsVisible: true,
            localeChain: "en_US"
        };
        var params = {
        }
        params.quality = "high";
        params.bgcolor = "#ffffff";
        params.allowscriptaccess = "sameDomain";
        params.allowfullscreen = "true";
        var attributes = {};
        attributes.id = "FlexPaperViewer";
        attributes.name = "FlexPaperViewer";
        swfobject.embedSWF(
            "FlexPaperViewer.swf", "flashContent",
            "650", "500",
            swfVersionStr, xiSwfUrlStr,
            flashvars, params, attributes);
        swfobject.createCSS("#flashContent", "display:block;text-align:left;");
// ]]></script>

&nbsp;
<div style="position: absolute; left: 10px; top: 10px;">
<div id="flashContent">

To view this page ensure that Adobe Flash Player version
10.0.0 or greater is installed.

<script type="text/javascript">// <![CDATA[
var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://");
                document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='"                                 + pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>");
// ]]></script>

</div>
<div id="errNoDocument" style="padding-top: 10px;">Can't see the document? Running FlexPaper from your local directory? Make sure you have added FlexPaper as trusted. You can do that at <a href="http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04a.html#119065">Adobe's website</a>.</div>
</div>

效果图

上面的工具栏:打印,全屏等功能可配置。

swftool工具

 操作类(本类来自常用类库,从网上下载的,一搜一大把)

using System.Web;
using System.Text;

public static class PSD2swfHelper
{
///
/// 转换所有的页,图片质量80%
///

///PDF文件地址 ///生成后的SWF文件地址 public static bool PDF2SWF(string pdfPath, string swfPath)
{
return PDF2SWF(pdfPath, swfPath, 1, GetPageCount(HttpContext.Current.Server.MapPath(pdfPath)), 80);
}

///
/// 转换前N页,图片质量80%
///

///PDF文件地址 ///生成后的SWF文件地址 ///页数 public static bool PDF2SWF(string pdfPath, string swfPath, int page)
{
return PDF2SWF(pdfPath, swfPath, 1, page, 80);
}

///
/// PDF格式转为SWF
///

///PDF文件地址 ///生成后的SWF文件地址 ///转换开始页 ///转换结束页 private static bool PDF2SWF(string pdfPath, string swfPath, int beginpage, int endpage, int photoQuality)
{
//swftool,首先先安装,然后将安装目录下的东西拷贝到tools目录下
string exe = HttpContext.Current.Server.MapPath("~/Bin/tools/pdf2swf.exe");
pdfPath = HttpContext.Current.Server.MapPath(pdfPath);
swfPath = HttpContext.Current.Server.MapPath(swfPath);
if (!System.IO.File.Exists(exe) || !System.IO.File.Exists(pdfPath) || System.IO.File.Exists(swfPath))
{
return false;
}
StringBuilder sb = new StringBuilder();
sb.Append(" \"" + pdfPath + "\"");
sb.Append(" -o \"" + swfPath + "\"");
sb.Append(" -s flashversion=9");
if (endpage &gt; GetPageCount(pdfPath)) endpage = GetPageCount(pdfPath);
sb.Append(" -p " + "\"" + beginpage + "" + "-" + endpage + "\"");
sb.Append(" -j " + photoQuality);
string Command = sb.ToString();
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = exe;
p.StartInfo.Arguments = Command;
p.StartInfo.WorkingDirectory = HttpContext.Current.Server.MapPath("~/Bin/");
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = false;
p.Start();
p.BeginErrorReadLine();
p.WaitForExit();
p.Close();
p.Dispose();
return true;
}

///
/// 返回页数
///

///PDF文件地址 private static int GetPageCount(string pdfPath)
{
byte[] buffer = System.IO.File.ReadAllBytes(pdfPath);
int length = buffer.Length;
if (buffer == null)
return -1;
if (buffer.Length &lt;= 0)
return -1;
string pdfText = Encoding.Default.GetString(buffer);
System.Text.RegularExpressions.Regex rx1 = new System.Text.RegularExpressions.Regex(@"/Type\s*/Page[^s]");
System.Text.RegularExpressions.MatchCollection matches = rx1.Matches(pdfText);
return matches.Count;
}
}

然后安装swftool工具,将安装后的目录中的文件拷贝到tools目录下,如图

 

test.asp.cs代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Wolfy.FlexPaperDemo
{
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//这里需要虚拟路径
PSD2swfHelper.PDF2SWF("PDFFile/王牌2_C#_控件查询手册.pdf", "SWFFile/王牌2_C#_控件查询手册.swf");
}
}
}

如何禁用右键中的打印,复制功能

如果pdf保密性强,不让别人复制,打印等该如何?在上面推荐的两篇文章中,他们对其进行了二次开发,禁用了这个功能。非常感谢,那么之后只需将FlexPaperViewer.swf替换就可以了。

原图

替换后的

 

说保密只是相对的,在互联网上,只要能看,别人想盗取还是很容易的事,大不了,一张一张的截图。

总结

互联网,没有绝对安全的,想安全就别放在互联网上显摆,只要想要,总会有办法的。有时候客户的需求真他妈的让人蛋疼。

demo下载:链接:http://pan.baidu.com/s/1sjnSsyx 密码:jjbx

swftools-2013-04-09-1007下载:http://pan.baidu.com/s/1jGI8H4U

[原创]Android秒杀倒计时自定义TextView

mikel阅读(1130)

自定义TextView控件TimeTextView代码:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.text.Html;
import android.util.AttributeSet;
import android.widget.TextView;

import com.new0315.R;
/**
 * 自定义倒计时文本控件
 * @author Administrator
 *
 */
public class TimeTextView extends TextView implements Runnable{

	Paint mPaint; //画笔,包含了画几何图形、文本等的样式和颜色信息

	private long[] times;

	private long mday, mhour, mmin, msecond;//天,小时,分钟,秒

	private boolean run=false; //是否启动了

	public TimeTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mPaint=new Paint();
		TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TimeTextView);

		array.recycle(); //一定要调用,否则这次的设定会对下次的使用造成影响
	}

	public TimeTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mPaint=new Paint();
		TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TimeTextView);

		array.recycle(); //一定要调用,否则这次的设定会对下次的使用造成影响
	}

	public TimeTextView(Context context) {
		super(context);
	}

	public long[] getTimes() {
		return times;
	}

	public void setTimes(long[] times) {
		this.times = times;
		mday = times[0];
		mhour = times[1];
		mmin = times[2];
		msecond = times[3];

	}

	/**
	 * 倒计时计算
	 */
	private void ComputeTime() {
		msecond--;
		if (msecond < 0) {
			mmin--;
			msecond = 59;
			if (mmin < 0) {
				mmin = 59;
				mhour--;
				if (mhour < 0) {
					// 倒计时结束
					mhour = 59;
					mday--;

				}
			}

		}

	}

	public boolean isRun() {
		return run;
	}

	public void setRun(boolean run) {
		this.run = run;
	}

	@Override
	public void run() {
		//标示已经启动
		run=true;

		ComputeTime();

		String strTime="还剩</pre>
<span style="color: red;">"+mday+"</span>
<pre>"+"天</pre>
<span style="color: red;">"+mhour+"</span>
<pre>小时</pre>
<span style="color: red;">"+
 mmin+"</span>
<pre>分钟</pre>
<span style="color: red;">"+msecond+"</span>
<pre>秒";
		this.setText(Html.fromHtml(strTime));

		postDelayed(this, 1000);

	}

}

属性atts.xml

    <declare-styleable name="TimeTextView">

    </declare-styleable>

Adapter调用代码:

import java.text.DecimalFormat;
import java.util.List;

import android.content.Context;
import android.graphics.Paint;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.new0315.R;
import com.new0315.entity.SpecialGoods;
import com.new0315.utils.CorrectSpecialDataFormHttp;
import com.new0315.utils.DateTools;
import com.new0315.widgets.TimeTextView;
import com.nostra13.universalimageloader.core.ImageLoader;

public class SpecialGoodsAdapter extends BaseAdapter {

	private Context context;
	private List list;
	private long sumTime;

	public SpecialGoodsAdapter(Context context) {

		this.context = context;
	}

	public void setList(List list) {
		this.list = list;
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return list.size();
	}

	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int arg0) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public View getView(int arg0, View convertView, ViewGroup arg2) {
        //开始计时,性能测试用nanoTime会更精确,因为它是纳秒级的
        long startTime = System.nanoTime();
        Log.d("position","getView " + arg0 + " " + convertView);
		ViewHolder viewHolder;
		if(convertView == null)
        {
    		convertView = LayoutInflater.from(context).inflate(
    				R.layout.item_temai_list, null);
    		viewHolder = new ViewHolder();
    		viewHolder.goodName = (TextView) convertView
    				.findViewById(R.id.temai_Name);
    		viewHolder.price = (TextView) convertView
    				.findViewById(R.id.temai_yuanjia_text);

    		viewHolder.specialPrice = (TextView) convertView
    				.findViewById(R.id.temai_xiajia_text);
    		//特卖倒计时控件
    		viewHolder.mTimeText = (TimeTextView) convertView
    				.findViewById(R.id.temai_timeTextView);

    		viewHolder.showDate = (TextView) convertView
    				.findViewById(R.id.index_temai_day);
    		viewHolder.showDate_l = (LinearLayout) convertView
    				.findViewById(R.id.temai_weikaishi);
    		viewHolder.showTime = (LinearLayout) convertView
    				.findViewById(R.id.temai_yikaishi);
    		viewHolder.koukou = (TextView) convertView
    				.findViewById(R.id.temai_zhekou_text);
    		viewHolder.image = (ImageView) convertView
    				.findViewById(R.id.index_temai_image);
    		Log.d("GoogleIO","new position:"+viewHolder.goodName.getText());

    		convertView.setTag(viewHolder);

        }else {
			viewHolder = (ViewHolder) convertView.getTag();
			resetViewHolder(viewHolder);
		}
		//setData
		String off = getOff(list.get(arg0).getGoods_Price(), list.get(arg0)
				.getGoods_SpecialPrice());
		viewHolder.goodName.setText(list.get(arg0).getGoods_Name());
		viewHolder.price.setText(list.get(arg0).getGoods_Price());
		viewHolder.price.getPaint().setFlags(
				Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
		viewHolder.specialPrice.setText(list.get(arg0).getGoods_SpecialPrice());
		viewHolder.koukou.setText(off + "折");

		if (DateTools.isStart(list.get(arg0).getSpecialFrom())) {
			//特卖倒计时开始
			viewHolder.mTimeText.setTimes(DateTools.getDate(CorrectSpecialDataFormHttp
					.correctData((list.get(arg0).getSpecialEnd()))));
			//已经在倒计时的时候不再开启计时
			if(!viewHolder.mTimeText.isRun())
			{
				viewHolder.mTimeText.run();
			}
			viewHolder.showDate_l.setVisibility(View.GONE);
			viewHolder.showTime.setVisibility(View.VISIBLE);
		} else {
			viewHolder.showTime.setVisibility(View.GONE);
			viewHolder.showDate_l.setVisibility(View.VISIBLE);
			viewHolder.showDate.setText(DateTools.getDay(list.get(arg0).getSpecialFrom())
					+ "");
		}

		ImageLoader.getInstance().displayImage(list.get(arg0).getGoods_Pic(),viewHolder.image);

        //停止计时
        long endTime = System.nanoTime();
        //耗时
        long spendTime = (endTime - startTime);

        sumTime += spendTime;
//        Log.d("GoogleIO", "position at:"+arg0+"--sumTime:"+String.valueOf(sumTime));
		return convertView;
	}

	public String getOff(String price, String specialPrice) {

		double off = Double.parseDouble(specialPrice)
				/ Double.parseDouble(price) * 10;

		DecimalFormat df = new DecimalFormat("0.0");
		String off_String = df.format(off);

		if (off_String.equals("NaN") || off_String.equals("1")) {
			off_String = "10";
		}
		return off_String;
	}

	static class ViewHolder {
		ImageView image;
		TextView goodName;
		TextView price;
		TextView specialPrice;
		TextView koukou;
		TimeTextView mTimeText;
		TextView showDate;
		LinearLayout showDate_l;
		LinearLayout showTime;

	}

	protected void resetViewHolder(ViewHolder viewHolder) {
		viewHolder.image.setImageBitmap(null);
		viewHolder.goodName.setText("");
		viewHolder.price.setText("");
		viewHolder.specialPrice.setText("");
		viewHolder.koukou.setText("");
		viewHolder.mTimeText.setText("");
		viewHolder.showDate.setText("");

	}
}

layout使用代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/home_panicbuying_background"
android:orientation="vertical" >

<!-- 免单 -->

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp" >

<FrameLayout
android:id="@+id/index_temai_image_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_margin="5dp" >

<ImageView
android:id="@+id/index_temai_image"
android:layout_width="80dp"
android:layout_height="80dp" />

<ImageView
android:id="@+id/index_temai_discount_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|left"
android:background="@drawable/app_limit_buy_sale"
android:src="@drawable/app_limit_buy_begin" />
</FrameLayout>

<LinearLayout
android:id="@+id/temai_date_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/index_temai_image_layout"
android:orientation="vertical" >

<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<LinearLayout
android:id="@+id/temai_weikaishi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:orientation="horizontal" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="距离开始还有"
android:textColor="@color/black"
android:textSize="@dimen/small_text_size"
android:textStyle="bold" />

<TextView
android:id="@+id/index_temai_day"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="99"
android:textColor="@color/red"
android:textSize="@dimen/small_text_size"
android:textStyle="bold" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="天"
android:textColor="@color/black"
android:textSize="@dimen/small_text_size"
android:textStyle="bold" />
</LinearLayout>

<LinearLayout
android:id="@+id/temai_yikaishi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:orientation="horizontal" >

<com.new0315.widgets.TimeTextView
android:id="@+id/temai_timeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="@dimen/small_text_size"
/>

</LinearLayout>
</RelativeLayout>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp"
android:orientation="horizontal" >

<TextView
android:id="@+id/temai_Name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="2"
android:text="大众甲壳虫,豪华款,曾全套汽车配件,十年加油卡,车库补贴,十年车险,五年以旧换新服务,比提供五年免费待架服务"
android:textColor="@color/black"
android:textSize="12sp" />
</LinearLayout>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/index_raw_price"
android:textColor="@color/darkgray"
android:textSize="@dimen/small_text_size" />

<TextView
android:id="@+id/temai_yuanjia_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:textColor="@color/darkgray"
android:textSize="@dimen/small_text_size" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5sp"
android:background="@drawable/app_limit_buy_sale_bg"
android:gravity="center_vertical" >

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="3dp"
android:orientation="horizontal" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="特卖价:"
android:textColor="#919263"
android:textSize="13sp" />

<TextView
android:id="@+id/temai_xiajia_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5sp"
android:text="¥400"
android:textColor="@color/red"
android:textSize="13sp" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="折扣:"
android:textColor="#919263"
android:textSize="13sp" />

<TextView
android:id="@+id/temai_zhekou_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5sp"
android:text="5.0折"
android:textColor="@color/green"
android:textSize="13sp" />
</LinearLayout>
</LinearLayout>

</LinearLayout>

最终效果:
Screenshot_2014-01-26-09-18-25

[转载]关于 ASP.NET MVC 中的视图生成 - 冠军 - 博客园

mikel阅读(1028)

[转载]关于 ASP.NET MVC 中的视图生成 – 冠军 – 博客园.

ASP.NET MVC 中,我们将前端的呈现划分为三个独立的部分来实现,Controller 用来控制用户的操作,View 用来控制呈现的内容,Model 用来表示处理的数据。

从控制器到视图

通常,在 Controller 中,我们定义多个 Action ,每个 Action 的返回类型一般是 ActionResult,在 Action 处理的最后,我们返回对于视图的调用。

public ActionResult Index()
{
    return this.View();
}

默认情况下,将会调用与 Action 同名的视图,比如,在上面的 Action 中,将会使用名为 Index 的视图。

如果我们传递了一个字符串参数,那么,这个字符串就回被视为视图的名称,例如,我们希望使用名为 IndexView 的视图进行呈现,那么,可以如下完成。

public ActionResult Index()
{
    return this.View("IndexView");
}

布局与视图

MVC 会直接去找我们的视图吗?不会!

从 Action 返回之后,首先,MVC 会在 Views 文件夹下查看是否存在一个名为 _ViewStart.cshtml 的特殊文件,如果存在的话,就回执行这个文件。

默认情况下,这个文件的内容如下所示:

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

也就是说,它设置了我们的默认布局使用那一个文件文件。

布局等价于我们在 WebForm 中所使用的母版页。

如果没有这个文件,默认没有使用布局。

如果有了这个文件,而我们在页面中不想使用这个布局怎么办呢?很简单,在页面中设置 Layout = null 来覆盖掉它。

@{
    Layout = null;
}

布局中的分区

在布局页面中,默认就回存在一个特殊的指令 @RenderBody(),这是说,你在内容页面中呈现的内容,将会在这里进行输出。这就是在使用布局之后,你会发现你的视图中已经没有了 <html> 标记的原因。

<body>
    @RenderBody()
</body>

假如说,我们希望在布局中的多个位置进行输出,比如,样式表通常在 <head> 标记中,而现代的脚本则会出现在页面的最后,页面的内容当然出现在页面的主体中了。这样的话,我们在内容页面的实际内容,将会需要在布局的不同部分进行呈 现,而不是在同一个位置进行呈现了。

解决的办法就是分区,实际上,类似于 WebForm 中的 ContentPlaceHolder ,定义一个命名的区域。

比如,下面我们定义了一个名为 scripts 的命名区域,第二个参数表示这个区域是可选的区域,在内容页面中可以不用提供内容。

<body>
    @RenderBody()

    @RenderSection("scripts", required: false)
</body>

而在我们的内容视图中,默认所有的内容都是填充到布局页面中的 RenderBody 部分。

如果不是的话,就可以在内容页面中,通过 @section 区域名称{ } 的方式来定义准备输出到对应区域中的内容了。

@section scripts{
    <script type="text/javascript">
        var i = 0;
    </script>
}

分部视图

如果我们的页面比较复杂,在同一个视图中定义输出的内容会导致页面非常复杂,通过将页面划分为多个比较独立的组成部分,可以将一个复杂的页面拆分为 多个子部分来呈现。比如页面的标题部分,页面的菜单,页面的脚注部分等等。在 WebForm 中,解决这个问题的技术称为用户控件,在 MVC 中由两个技术来解决:分部视图和子 Action。

先看分部视图,分部视图不依赖于 Action ,只能嵌入到其他独立视图中使用,你可以直接在视图文件夹中创建分部视图。

在使用分部视图的页面中,使用 RenderPartial 方法调用分部视图。

Html.RenderPartial("ProductSummary");

分部视图与主视图共享所有的数据,比如模型,ViewData,ViewBag 等等,这些数据可以直接在分部视图中使用。

如果希望分部视图使用不同的模型对象,简化分部视图中的数据复杂度,也可以直接传递一个模型对象过去。

Html.RenderPartial("ProductSummary", p);

这里的第二个参数,将会在分部视图中当在模型对象来使用。

需要注意的是 RenderPartial 方法的返回类型是 void,它会将输出的内容直接输出到回应的输出流中。所以在使用上面语句的时候,不能直接嵌入到页面中,需要放在一个 @ { } 语句中,如下所示。

@{
  Html.RenderPartial("ProductSummary", p);
}

如果你不喜欢这样的语法,而希望直接嵌入到页面中,也可以使用 Html.Partial 方法来呈现,区别是这个方法返回呈现的 Html 片段,而不是直接输出到输出流中。

@Html.Partial("ProductSummary", p)

 

子 Action 问题

由于分布视图没有处理能力,只能继承主页面的数据进行呈现,如果需要有处理能力,怎么办呢?在 WebForm 中,我们可以使用 Server.Execute  来嵌入其它处理程序的输出内容,在 MVC 中,我们使用子 Action 来处理。

子 Action 就是用户不能直接访问,只能在其他的 Action 中访问的 Action 方法,它与普通的 Action 一样,有 Action 方法,还有这个 Action 对应的视图。

我们使用特性 ChildActionOnly 来说明这是一个子 Action。

[ChildActionOnly]
public string Menu()
{
    return "Hello, from NavController";
}

如果用户直接请求这个子 Action ,那么,系统会返回一个错误信息。

操作“menu”只能由子请求访问。

在其它视图中,可以使用 RenderAction 来访问子 Action,类似于 RenderPartial 方法,这个方法直接将内容输出到输出流中,由于它们的返回类型都是 void ,所以需要使用 @{} 来使用。

@{ Html.RenderAction("Menu", "Nav"); }

同样,使用 Action 则可以直接返回一个 Html 片段,就不用使用一个 @{ } 了。

<!--  Action -->
@Html.Action("Menu", "Nav")

[转载]我也来自己做刷机包 - linux86 - 博客园

mikel阅读(944)

[转载]我也来自己做刷机包 – linux86 – 博客园.

  作为一名程序员,尤其是开发Android应用程序的程序员,不会自己折腾ROM简 直就是一件不好意思的事情,于是乎我就费劲巴力的上网看资料,找工具,准备自己开始制作有“中国特色”的ROM,以下是解决的一些问题,希望对在座的各位 机油有帮助,废话少说喽,开始简单介绍一下。

首先,我要说明的第一点是,我讲的内容是针对三星手机部分ROM。第二点,现在只说一下怎样解开内容和大体上美化步骤。第三,如果出现手机变成板砖,小生概不负责。

三星手机的ROM包一半是好几个包,而且后缀名都是.md5或者.tar。这或许另许多机油困惑,就像下面这张截图。

结果上网一搜或者有些变成经验的人就知道,md5是一种签名,可以去掉,真正的后缀名是tar,tar其实是一种linux的压缩文件,就相当 于windows的rar,zip等格式,也就是说,把MD5去掉,直接可以用windows的winrar解压缩,当然解压哪一个自己选择,目前我所涉 及到的是code部分(有的ROM包只有一个tar文件,你可以解压一下)。推荐使用linux环境,系统可以自己选择,我推荐使用ubuntu的 linux系统。没有linux环境的机油也不要紧张,今天讲的是windows环境下的。

我就默认你已经明白上面说的内容了,现在是已经解开tar文件了,看一下里面的东西(只是我ROM包自己的内容,仅做参考)。截图如下。

聪明的你可能已经才出来了,我们给system.img开刀,但是怎样开刀呢,这就需要有一个工具能够打开它,这个工具叫做 sgs2toext4,从名字中可能会理解它是做什么的,我的理解是一种文件格式转换工具,自己百度上google一下,然后下载,是一个jar文件,截 图如下。

小巧玲珑的一个软件,然后双击运行,回事如下界面。

看到没有,专门为三星准备的,然后就可以名正言顺的把你的system.img文件拖拽到这个框框里面,随后会有一些数字在跳动,然后就是文件格式转换成功,转换成功后的文件是.ext4格式,下面是截图。

这个格式目前还是打不开的,那就需要另外一个神器,叫做ext2explorer,自己搜索下载吧。下面是截图

多么熟悉的企鹅,不是腾讯家养的,但是比他家的厉害,OK目前就可以用它打开刚才的ext4文件了。打开后会是这个样子。

然后说一下其他需要用到的工具是大名鼎鼎的apktool反编译回编译使用,还有就是sign的签名工具,这个一般都是集成的环境。下面说一下 需要动手术的东西,一个是app下面的SystemUI.apk,还有一个就是framework下面的framework-res.apk,这两个文件 不多介绍,可自行搜索,看看怎样美化。选中文件,点击save然后就可以拿出文件了,再用apktool反编译,剩下的就是自己喜欢怎么折腾的事情了。

最后推荐一个美化教程网站,当然是小米喽。不过力卓社区也不错,慢慢来,会学会。

刷机有风险,美化需谨慎。

[转载]APP广告联盟介绍陆续更新 | 网赚赚

mikel阅读(1144)

[转载]APP广告联盟介绍陆续更新 | 网赚赚.

  1. 嬴告无线 winads.cn
  2. 抓猫  http://zhuamob.com/
  3. 百度移动联盟 http://munion.baidu.com/
  4. 易积分 http://yijifen.com/
  5. 点乐 http://www.dianjoy.com/
  6. 有米 http://www.youmi.net/
  7.  爱沃 http://www.adwo.com/
  8.  友盟  http://www.umeng.com/
  9. 第七移动传媒 http://mobile7.cn/
  10. 高端手机预装联盟 http://cui9.com/
  11. 米迪  http://www.miidi.net/
  12. 91admob http://91admob.com/
  13. ————点华丽的分割线——————
  14. 大头鸟 http://datouniao.com/
  15. 米积分 http://www.mijifen.com/
  16. 天马广告 http://pgswap.com/
  17. 指盟 http://mobsmar.com/
  18. Ader  http://www.ader.mobi/
  19. 万普世纪 http://wapx.cn/
  20. ————跳华丽的分割线——————
  21. 91点金 http://mjoy.91.com/
  22. 力美广告 http://www.limei.com/
  23. 多盟 http://www.domob.cn

[转载]Fiddler 教程 - 小坦克 - 博客园

mikel阅读(2188)

[转载]Fiddler 教程 – 小坦克 – 博客园.

Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说,都有很大的帮助。

阅读目录

  1. Fiddler的基本介绍
  2. Fiddler的工作原理
  3. 同类的其它工具
  4. Fiddler如何捕获Firefox的会话
  5. Firefox 中使用Fiddler插件
  6. Fiddler如何捕获HTTPS会话
  7. Fiddler的基本界面
  8. Fiddler的统计视图
  9. QuickExec命令行的使用
  10. Fiddler中设置断点修改Request
  11. Fiddler中设置断点修改Response
  12. Fiddler中创建AutoResponder规则
  13. Fiddler中如何过滤会话
  14. Fiddler中会话比较功能
  15. Fiddler中提供的编码小工具
  16. Fiddler中查询会话
  17. Fiddler中保存会话
  18. Fiddler的script系统
  19. 如何在VS调试网站的时候使用Fiddler
  20. Response 是乱码的

Fiddler的基本介绍

Fiddler的官方网站www.fiddler2.com

Fiddler官方网站提供了大量的帮助文档和视频教程, 这是学习Fiddler的最好资料。

Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据,Fiddler包含了一个强大的基于事件脚本的子系统,并且能使用.net语言进行扩展

你对HTTP 协议越了解, 你就能越掌握Fiddler的使用方法. 你越使用Fiddler,就越能帮助你了解HTTP协议.

Fiddler无论对开发人员或者测试人员来说,都是非常有用的工具

Fiddler的工作原理

Fiddler 是以代理web服务器的形式工作的,它使用代理地址:127.0.0.1, 端口:8888. 当Fiddler会自动设置代理, 退出的时候它会自动注销代理,这样就不会影响别的程序。不过如果Fiddler非正常退出,这时候因为Fiddler没有自动注销,会造成网页无法访问。 解决的办法是重新启动下Fiddler.

 

同类的其它工具

同类的工具有: httpwatch, firebug, wireshark

 

Fiddler 如何捕获Firefox的会话

能支持HTTP代理的任意程序的数据包都能被Fiddler嗅探到,Fiddler的运行机制其实就是本机上监听8888端口的HTTP代理。 Fiddler2启动的时候默认IE的代理设为了127.0.0.1:8888,而其他浏览器是需要手动设置的,所以将Firefox的代理改为 127.0.0.1:8888就可以监听数据了。

Firefox 上通过如下步骤设置代理

点击: Tools -> Options,  在Options 对话框上点击Advanced tab – > network tab -> setting.

 

Firefox 中安装Fiddler插件

修改Firefox 中的代理比较麻烦, 不用fiddler的时候还要去掉代理。 麻烦

推荐你在firefox中使用fiddler hook 插件, 这样你非常方便的使用Fiddler获取firefox中的request 和response

当你安装fiddler后, 就已经装好了Fiddler hook插件, 你需要到firefox中去启用这个插件
打开firefox   tools->Add ons -> Extensions 启动 FiddlerHook

 

 

Fiddler如何捕获HTTPS会话

默认下,Fiddler不会捕获HTTPS会话,需要你设置下, 打开Fiddler  Tool->Fiddler Options->HTTPS tab

选中checkbox, 弹出如下的对话框,点击”YES”

点击”Yes” 后,就设置好了

Fiddler的基本界面

看看Fiddler的基本界面

 

Inspectors tab下有很多查看Request或者Response的消息。 其中Raw Tab可以查看完整的消息,Headers tab 只查看消息中的header. 如下图

 

Fiddler的HTTP统计视图

通过陈列出所有的HTTP通信量,Fiddler可以很容易的向您展示哪些文件生成了您当前请求的页面。使用Statistics页签,用户可以通过选择多个会话来得来这几个会话的总的信息统计,比如多个请求和传输的字节数。

选择第一个请求和最后一个请求,可获得整个页面加载所消耗的总体时间。从条形图表中还可以分别出哪些请求耗时最多,从而对页面的访问进行访问速度优化

QuickExec命令行的使用

Fiddler的左下角有一个命令行工具叫做QuickExec,允许你直接输入命令。

常见得命令有

help  打开官方的使用页面介绍,所有的命令都会列出来

cls    清屏  (Ctrl+x 也可以清屏)

select  选择会话的命令

?.png  用来选择png后缀的图片

bpu  截获request

 

Fiddler中设置断点修改Request

[作者:小坦克]  Fiddler最强大的功能莫过于设置断点了,设置好断点后,你可以修改httpRequest 的任何信息包括host, cookie或者表单中的数据。设置断点有两种方法

第一种:打开Fiddler 点击Rules-> Automatic Breakpoint  ->Before Requests(这种方法会中断所有的会话)

如何消除命令呢?  点击Rules-> Automatic Breakpoint  ->Disabled

第二种:  在命令行中输入命令:  bpu www.baidu.com   (这种方法只会中断www.baidu.com)

如何消除命令呢?  在命令行中输入命令 bpu

 

看个实例,模拟博客园的登录, 在IE中打开博客园的登录页面,输入错误的用户名和密码,用Fiddler中断会话,修改成正确的用户名密码。这样就能成功登录

1. 用IE 打开博客园的登录界面  http://passport.cnblogs.com/login.aspx
2. 打开Fiddler,  在命令行中输入bpu http://passport.cnblogs.com/login.aspx
3. 输入错误的用户名和密码 点击登录
4. Fiddler 能中断这次会话,选择被中断的会话,点击Inspectors tab下的WebForms tab 修改用户名密码,然后点击Run to Completion 如下图所示。
5. 结果是正确地登录了博客园

 

 

Fiddler中设置断点修改Response

当然Fiddler中也能修改Response

第一种:打开Fiddler 点击Rules-> Automatic Breakpoint  ->After Response  (这种方法会中断所有的会话)

如何消除命令呢?  点击Rules-> Automatic Breakpoint  ->Disabled

第二种:  在命令行中输入命令:  bpafter www.baidu.com   (这种方法只会中断www.baidu.com)

如何消除命令呢?  在命令行中输入命令 bpafter,

具体用法和上节差不多,就不多说了。

Fiddler中创建AutoResponder规则

Fiddler 的AutoResponder tab允许你从本地返回文件,而不用将http request 发送到服务器上。

看个实例. 1. 打开博客园首页,把博客园的logo图片保存到本地,并且对图片做些修改。

2. 打开Fiddler 找到logo图片的会话, http://static.cnblogs.com/images/logo_2012_lantern_festival.gif,  把这个会话拖到AutoResponer Tab下

3. 选择Enable automatic reaponses 和Unmatched requests passthrough

4. 在下面的Rule Editor 下面选择 Find a file… 选择本地保存的图片.  最后点击Save 保存下。

5.  再用IE博客园首页, 你会看到首页的图片用的是本地的。

 

Fiddler中如何过滤会话

每次使用Fiddler, 打开一个网站,都能在Fiddler中看到几十个会话,看得眼花缭乱。最好的办法是过滤掉一些会话,比如过滤掉图片的会话. Fiddler中有过滤的功能, 在右边的Filters tab中,里面有很多选项, 稍微研究下,就知道怎么用。

 

Fiddler中会话比较功能

选中2个会话,右键然后点击Compare,就可以用WinDiff来比较两个会话的不同了 (当然需要你安装WinDiff)

 

Fiddler中提供的编码小工具

点击Fiddler 工具栏上的TextWizard,  这个工具可以Encode和Decode string.

Fiddler中查询会话

用快捷键Ctrl+F 打开 Find Sessions的对话框,输入关键字查询你要的会话。 查询到的会话会用黄色显示

Fiddler中保存会话

有些时候我们需要把会话保存下来,以便发给别人或者以后去分析。  保存会话的步骤如下:

选择你想保存的会话,然后点击File->Save->Selected Sessions

Fiddler的script系统

Fiddler最复杂的莫过于script系统了 官方的帮助文档: http://www.fiddler2.com/Fiddler/dev/ScriptSamples.asp

首先先安装SyntaxView插件,Inspectors tab->Get SyntaxView tab->Download and Install SyntaxView Now… 如下图

 

安装成功后Fiddler 就会多了一个Fiddler Script tab, 如下图

在里面我们就可以编写脚本了, 看个实例 让所有cnblogs的会话都显示红色。

把这段脚本放在OnBeforeRequest(oSession: Session) 方法下,并且点击”Save script”

     if (oSession.HostnameIs("www.cnblogs.com")) {
            oSession["ui-color"] = "red";
        }

这样所有的cnblogs的会话都会显示红色

 

如何在VS调试网站的时候使用Fiddler

我们在用visual stuido 开发ASP.NET网站的时候也需要用Fiddler来分析HTTP, 默认的时候Fiddler是不能嗅探到localhost的网站。不过只要在localhost后面加个点号,Fiddler就能嗅探到。

例如:原本ASP.NET的地址是 http://localhost:2391/Default.aspx,  加个点号后,变成 http://localhost.:2391/Default.aspx 就可以了

 

第二个办法就是在hosts文件中加入  127.0.0.1  localsite

如何你访问http://localsite:端口号   。  这样Fiddler也能截取到了。

 

Response 是乱码的

有时候我们看到Response中的HTML是乱码的, 这是因为HTML被压缩了, 我们可以通过两种方法去解压缩。

1. 点击Response Raw上方的”Response is encoded any may need to be decoded before inspection. click here to transform”

2. 选中工具栏中的”Decode”。  这样会自动解压缩。

 

[原创]Android提交表单并上传图片到web服务器

mikel阅读(1326)

Android提交表单并上传图片到web服务器,直接上代码

用到了Apache的HttpClient.jar

 

	/**
	 * 提交表单并上传文件到网站
	 * @param url 提交的接口
	 * @param param 参数 <键,值>
	 * @param bitmap 图片内容
	 */
	public static String postForm(String url,Map<String, String> param, Bitmap bitmap)
	{
		try {
			url="http://localhost:4657" +
                    "/api/SaveNeed";
			HttpPost post = new HttpPost(url);

			HttpClient client = new DefaultHttpClient();
			String BOUNDARY = "*****"; // 边界标识
			MultipartEntity entity = new MultipartEntity(
					HttpMultipartMode.BROWSER_COMPATIBLE, BOUNDARY, null);
			if (param != null && !param.isEmpty()) {

				entity.addPart("needList", new StringBody(
						param.get("needList"), Charset.forName("UTF-8")));

			}

			saveImageFile(bitmap);
			String path = Environment.getExternalStorageDirectory()
					+ "/temple/temp.jpg";
			File file = new File(path);
			// 添加文件参数
			if (file != null && file.exists()) {

				entity.addPart("file", new FileBody(file));
			}

			post.setEntity(entity);

			HttpResponse response;

			response = client.execute(post);

			int stateCode = response.getStatusLine().getStatusCode();
			StringBuffer sb = new StringBuffer();
			if (stateCode == HttpStatus.SC_OK) {
				HttpEntity result = response.getEntity();
				if (result != null) {
					InputStream is = result.getContent();
					BufferedReader br = new BufferedReader(
							new InputStreamReader(is));
					String tempLine;
					while ((tempLine = br.readLine()) != null) {
						sb.append(tempLine);
					}
				}
			}
			post.abort();

			return sb.toString();
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}