从获取QQ验证码谈如何改进用户体验,提高程序的响应效果

很久没写博客了,最近没有什么惊天地、泣鬼神的大作,就从小处着眼,总结一些开发过程中的一些心得和见解吧。

众所周知,互联网改变生活,现在是验证码大行其道的年代,基本上主要涉及用户信息注册、登录、提交数据等,都来一个验证码来限制下,QQ在这方面可真是运用到了极致,因此做QQ的开发,必须了解如何处理验证码的问题。一般验证码是通过一个带参数的URL获取到一个数字字符图片,由于网络原因,一般返回比较缓慢,所以如果要提高用户体验和程序的响应速度,就必须采用改良一点的方法来进行处理。

我们先从一个正常的操作讲起,逐步改进,看看效果及使用情况,如一般的处理就是把它封装在一个独立的函数中,在触发事件的地方调用该函数,如下所示。

        public void GetNewImage()
        {
            HttpHelper httpHelper 
= new HttpHelper();
            
using (Stream s = httpHelper.GetStream("http://ptlogin2.qq.com/getimage?aid=3000801&0.43878429697395826", Portal.gc.cookieQun))
            {
                
if (s == null)
                {
                    MessageUtil.ShowWarning(
"获取登陆码错误,请检查您的网络!");
                    
return;
                }
                pictureBox1.Image 
= Image.FromStream(s);
            }
        }

 

这种方式方式是一般的处理方式,有时候界面会因为获取网络数据而有停顿,除非你的网络非常好,所以可以把它放到一个独立的线程中进行处理,通过hreadPool.QueueUserWorkItem来进行线程处理,如下代码所示:

        public void GetNewImage()
        {
            ThreadPool.QueueUserWorkItem(GetNewImageThread, 
null);
        }

        
private void GetNewImageThread(object obj)
        {
            
using (Stream s = httpHelper.GetStream("https://mail.qq.com/cgi-bin/getverifyimage?aid=23000101&f=html&ck=1&31997", EmailCookie))
            {
                
if (s == null)
                {
                    SetTips(
"获取登陆码错误,请检查您的网络!");
                    
return;
                }

                
this.pictureBox1.Invoke(new MethodInvoker(delegate()
                {
                    
this.pictureBox1.Image = Image.FromStream(s);
                }));
            }
        }

 

 

 这样已经比较好的处理界面停顿等不友好的问题了,不过有时候,因为使用了Invoke函数,可能会出现一些线程间的异常,如你关闭了窗口,而进行还在运行,就会出现一些问题,但是还是相对比较好的解决途径。

 偶尔一天,看到一个比较好的后台线程封装类QueuedBackgroundWorker,使用效果还比较不错,虽然代码多了一些,不过处理起来效果还真的不错,还支持取消线程操作等功能,整个后台线程以及获取验证码的操作代码如下所示,整个代码运行效果不错,而且不会出现线程间的绑定错误。

         private QueuedBackgroundWorker worker;


        
public Form1()
        {
            InitializeComponent();

            worker 
= new QueuedBackgroundWorker();
            worker.IsBackground 
= true;
            worker.Threads 
= 1;
            worker.ProcessingMode 
= ProcessingMode.FIFO;
            worker.DoWork 
+= new QueuedWorkerDoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted 
+= new RunQueuedWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        }

        
        
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            worker.DoWork 
-= worker_DoWork;
            worker.RunWorkerCompleted 
-= worker_RunWorkerCompleted;
            worker.Dispose();
        }

        
private void GetVerifyImage()
        {
            worker.RunWorkerAsync(
"GetImage");
        }

        
void worker_DoWork(object sender, QueuedWorkerDoWorkEventArgs e)
        {
            
string newverifyUrl = "http://captcha.qq.com/getimage?aid=1007901&0.5723910723542236";
            
string referer = "http://reg.qq.com";

            cookieReg 
= new CookieContainer();
            HttpHelper httpHelper 
= new HttpHelper();
            
using (Stream s = httpHelper.GetStream(newverifyUrl, cookieReg, referer))
            {
                
if (s == null)
                {
                    MessageUtil.ShowWarning(
"获取登陆码错误,请检查您的网络!");
                    
return;
                }
                e.Result 
= Image.FromStream(s);
            }
        }

        
void worker_RunWorkerCompleted(object sender, QueuedWorkerCompletedEventArgs e)
        {
            Image image 
= e.Result as Image;
            
if (image != null)
            {
                
this.pictureBox1.Image = image;
            }
        }

 线程封装类的源码地址提供给大家下载:https://files.cnblogs.com/wuhuacong/QueuedBackgroundWorker.rar

 其实用C#内置的后台线程也是可以处理这个问题的,只是这个封装的后台线程,提供较好的一些封装及处理,可以应付更为复杂的情况,而对于要等线程返回值、用户可取消的操作,更是方便。系统这些对你有帮助!

 

 

posted on 2010-11-06 10:12  伍华聪  阅读(5105)  评论(5编辑  收藏  举报

导航