当前位置:  编程技术>移动开发
本页文章导读:
    ▪一个棋牌游戏的服务端开发一        一个棋牌游戏的服务端开发1 一个多人在线的棋牌类网络游戏的项目临近尾声,我参与了该项目的整个设计流程,并且完成了90%的核心代码。关于这个项目,有很多地方值得聊一聊。本系列不.........
    ▪ AsyncTask的用法-UI刷新发给        AsyncTask的用法-UI刷新发放   在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则: 1. 不.........
    ▪ 能说话的代码——书写自表达代码之道       会说话的代码——书写自表达代码之道 《会说话的代码——书写自表达代码之道》 基本信息 作者: 王洪亮 出版社:电子工业出版社 ISBN:9787121208768 上架时间:2013-7-12 出版日期:2013 年7月.........

[1]一个棋牌游戏的服务端开发一
    来源: 互联网  发布时间: 2014-02-18
一个棋牌游戏的服务端开发1

一个多人在线的棋牌类网络游戏的项目临近尾声,我参与了该项目的整个设计流程,并且完成了90%的核心代码。关于这个项目,有很多地方值得聊一聊。本系列不打算把这个项目将得多么详细规范,那是设计文档应该描述的,我打算只说说一些值得注意的地方。

  这个项目的一个特别之处是,客户端是手机,用户通过移动网络与服务器通信。和PC相比,手机的处理能力极弱,而且网络流量费用昂贵。因为除了要考虑普通网络游戏的一些问题之外,这两点也需要在设计中充分考虑。

  首先是开发语言的选择,由于服务器是Linux的环境,MS的技术直接排除,至于MONO嘛,我实在不放心。可供选择的是C++和Java,Java胜在网络能力强大,开发周期短,有众多框架和开源库的支持,要写出烂得不可接受的代码也不容易;C++则胜在速度快。综合各方面因素,C++更容易把这个项目变成一堆代码噩梦,我们选择了Java。


一、网络

  网络游戏,首先面临的问题当然是如何进行网络通信。首先考虑的是HTTP协议,因为所有的J2ME手机都支持这个,我们当然想尽可能的兼容用户。而且HTTP协议封装程度已经非常高了,不用去考虑线程、同步、状态管理、连接池,不过HTTP协议有两个不爽的地方:

  ◇ 协议无状态,这个问题已经困扰过很多人很多次了。我曾考虑过的解决办法是改造HTTP协议,在数据传输完成之后不关闭socket,但是这样做工作量非常大,在项目周期中,基本上就是Mission impossible,不予考虑。那么客户也就只能通过轮询的方式向服务器请求数据。

  ◇ 网络流量过大。就这个项目来说,网络间传递的只是指令,但是每次传递都要加上一堆毫无用处的HTTP Head,再加上客户端需要做轮询,这个流量对于手机来说简直恐怖,经简单测试,按照0.03元/K的GPRS网络费用计算,一局牌居然要消耗1元多的费用(每秒轮询),实在不可接受。也许我们可以采用流量费包月的资费方式,不过这个话题与技术无关。

  以上问题导致我们选择了Socket,这意味着我们将没有一个web环境,很多东西都要靠自己去实现:线程管理、客户状态监控、对象池、控制台……….

  网络部分打算采用Java NIO来实现,这是一种新的网络监听方式,基于事件的异步通信,可以提高性能。每个客户端连接之后,会有一个独立的SocketChannel与它通信,这个SocketChannel会在用户的整个生存周期中存在。用户如果断开连接,服务器会得到-1,并且会抛出Connection reset异常,通过捕获这两个特征,可以在用户意外断开连接后清理相关的资源。由于NIO是异步通信的,所以没有复杂的线程管理。


二、通信协议

  这个项目并没有复杂的通信指令,命令数量很有限,但是还是有个关键问题需要关注:流量。为了尽量减小流量,我们使用字节代替字符串来保存系统指令,这样可以使流量减少一半,比如使用一个字节来保存一张扑克牌,字节高位表示花色,字节低位表示数字,如果0代表黑桃,那么黑桃三就应该是0x03,这个需要靠位操作来实现:

    int m=0;
    int n=3;
    byte card=(byte)(m)<<4)|((byte)n; //m左移四位,然后与n左或操作

  游戏中需要传递用户的积分,这是一个大整数,使用四个字节来保存比较保险,将整数转换为四个字节的操作如下:

public static byte[] translateLong(long mark)
{
    byte[] b = new byte[4];
    for (int i = 0; i < 4; i++)
    {
        b = (byte) (mark >>> (24 - i * 8));
    }
    return b;
}

  将四个字节转回来的操作如下:

public static long translateByte(byte[] b)
{
    int mask = 0xff;
    int temp = 0;
    int res = 0;
    for (int i = 0; i < 4; i++)
    {
        res <<= 8;
        temp = b & mask;
        res |= temp;
    }
    return res;
}


三、数据库连接池

  由于没有一个web环境,所以我们需要自己实现一个数据库连接池,apache有一个项目叫做commons DBCP,这是一个基于apache自己的对象池(apache commons pool)实现的数据库连接池,我们可以直接拿来使用,apache的软件未必是最好的,但是极大可能比我们自己写的要好。

Commons DBCP需要三个.jar:

    commons-collections-3.1.jar、commons-dbcp-1.2.1.jar、commons-pool-1.2.jar

这三个文件都可以在apache – Jakarta – commons项目下下载,加入到工程中即可。

构造一个数据库连接池的代码如下:

    import java.sql.*;
    import com.gwnet.games.antiLord.util.*;
    import org.apache.commons.dbcp.ConnectionFactory;
    import org.apache.commons.dbcp.BasicDataSource;
    import org.apache.commons.dbcp.DataSourceConnectionFactory;

    private static BasicDataSource bds=new BasicDataSource();
    private static ConnectionFactory fac=null;

    //初始化连接池
    bds.setDriverClassName(“org.postgresql.Driver”); //数据库驱动程序
    bds.setUrl(/blog_article/“jdbc_postgresql_/localhost_5432/myDB”/index.html); //数据库url
    bds.setUsername(“postgres”); //dba帐号
    bds.setPassword(“XXXXXXXX”); //密码
    bds.setInitialSize(100); //初始化连接数量
    bds.setMaxIdle(10); //最大idle数
    bds.setMaxWait(1000*60); //超时回收时间

    fac=new DataSourceConnectionFactory(bds); //得到连接工厂
    Connection conn=fac.createConnection(); //从池中获得连接
    conn.close(); //释放连接,回到池中

    //销毁连接池
    bds.close();
    bds=null;
    fac=null;

请自行处理操作中的各种异常。


    
[2] AsyncTask的用法-UI刷新发给
    来源: 互联网  发布时间: 2014-02-18
AsyncTask的用法-UI刷新发放

  在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则: 
1. 不要阻塞UI线程 
2. 确保只在UI线程中访问Android UI工具包 
      当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。 
      比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后,是不能直接在网络操作线程中调用TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员 。

android提供了几种在其他线程中访问UI线程的方法。 
Activity.runOnUiThread( Runnable ) 
View.post( Runnable ) 
View.postDelayed( Runnable, long ) 
Hanlder 
这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。 

     为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。 
AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。 
  Params 启动任务执行的输入参数,比如HTTP请求的URL。 
  Progress 后台任务执行的百分比。 
  Result 后台执行任务最终返回的结果,比如String。 

     AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。 
  1) 子类化AsyncTask 
  2) 实现AsyncTask中定义的下面一个或几个方法 
     onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。 
    doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。 
    onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。 
    onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread. 

为了正确的使用AsyncTask类,以下是几条必须遵守的准则: 
  1) Task的实例必须在UI thread中创建 
  2) execute方法必须在UI thread中调用 
  3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法 
  4) 该task只能被执行一次,否则多次调用时将会出现异常 
      doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。


从网上获取一个网页,在一个TextView中将其源代码显示出来

package test.list;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class NetworkActivity extends Activity{
    private TextView message;
    private Button open;
    private EditText url;

    @Override
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.network);
       message= (TextView) findViewById(R.id.message);
       url= (EditText) findViewById(R.id.url);
       open= (Button) findViewById(R.id.open);
       open.setOnClickListener(new View.OnClickListener() {
           public void onClick(View arg0) {
              connect();
           }
       });

    }

    private void connect() {
        PageTask task = new PageTask(this);
        task.execute(url.getText().toString());
    }


    class PageTask extends AsyncTask<String, Integer, String> {
        // 可变长的输入参数,与AsyncTask.exucute()对应
        ProgressDialog pdialog;
        public PageTask(Context context){
            pdialog = new ProgressDialog(context, 0);   
            pdialog.setButton("cancel", new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog, int i) {
              dialog.cancel();
             }
            });
            pdialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
             public void onCancel(DialogInterface dialog) {
              finish();
             }
            });
            pdialog.setCancelable(true);
            pdialog.setMax(100);
            pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            pdialog.show();


        }
        @Override
        protected String doInBackground(String... params) {

            try{

               HttpClient client = new DefaultHttpClient();
               // params[0]代表连接的url
               HttpGet get = new HttpGet(params[0]);
               HttpResponse response = client.execute(get);
               HttpEntity entity = response.getEntity();
               long length = entity.getContentLength();
               InputStream is = entity.getContent();
               String s = null;
               if(is != null) {
                   ByteArrayOutputStream baos = new ByteArrayOutputStream();

                   byte[] buf = new byte[128];

                   int ch = -1;

                   int count = 0;

                   while((ch = is.read(buf)) != -1) {

                      baos.write(buf, 0, ch);

                      count += ch;

                      if(length > 0) {
                          // 如果知道响应的长度,调用publishProgress()更新进度
                          publishProgress((int) ((count / (float) length) * 100));
                      }

                      // 让线程休眠100ms
                      Thread.sleep(100);
                   }
                   s = new String(baos.toByteArray());              }
               // 返回结果
               return s;
            } catch(Exception e) {
               e.printStackTrace();

            }

            return null;

        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
        }

        @Override
        protected void onPostExecute(String result) {
            // 返回HTML页面的内容
            message.setText(result);
            pdialog.dismiss(); 
        }

        @Override
        protected void onPreExecute() {
            // 任务启动,可以在这里显示一个对话框,这里简单处理
            message.setText(R.string.task_started);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            // 更新进度
              System.out.println(""+values[0]);
              message.setText(""+values[0]);
              pdialog.setProgress(values[0]);
        }

     }

}


 


    
[3] 能说话的代码——书写自表达代码之道
    来源: 互联网  发布时间: 2014-02-18
会说话的代码——书写自表达代码之道
《会说话的代码——书写自表达代码之道》
基本信息
作者: 王洪亮
出版社:电子工业出版社
ISBN:9787121208768
上架时间:2013-7-12
出版日期:2013 年7月
开本:16开
页码:204
版次:1-1
所属分类:计算机 > 软件与程序设计
更多关于 》》》《会说话的代码——书写自表达代码之道》
内容简介
计算机书籍
  《会说话的代码——书写自表达代码之道》内容简介:写得不好的代码有各种各样的问题,会给读者带来不好的阅读体验,并且如果代码写得不够好,文档和代码不一致,注释和代码不一致,那么对维护人员来说,理解代码和进入项目组都是有困难的。如果代码写得不够好,就需要扩展功能,修改bug时所需要花费的时间也较长。
   自表达代码是一种采用接近于自然语言的方式书写代码的主张。
   代码可读性、可扩展性、可测试性是关联代码质量的重要参考指标。本书从各个角度来分析产生劣质代码的原因,并从代码的命名、注释、风格、结构、架构等方面着手,对提高设计能力、熟悉开发环境、了解编程语言、提高英语能力等诸多方面提出了具体的改善建议。
目录
《会说话的代码——书写自表达代码之道》
第1章 劣质代码带来的劣质体验1
1.1 代码的可读性问题1
1.1.1 命名类问题2
1.1.2 注释类问题6
1.1.3 风格类问题8
1.1.4 结构类问题11
1.1.5 架构类问题18
1.2 代码的可测试性问题22
1.3 代码的可维护性问题22
1.3.1 需求变更难以应对23
1.3.2 纠缠不清的bug23
第2章 劣质代码是怎么产生的25
2.1 理论知识匮乏25
2.2 对编程语言不熟悉29
2.3 对开发环境不熟悉31
2.4 对设计方法不了解32
2.5 编程习惯不佳32
2.6 英语能力不足35
2.7 管理人员误导36
.第3章 自表达代码39
第4章 理论知识的补充41
4.1 面向对象的基础知识41
4.1.1 封装41
4.1.2 继承42
4.1.3 多态44
4.2 设计的基本原则45
4.2.1 单一职责原则45
4.2.2 开放封闭原则46
4.2.3 里氏代换原则48
4.2.4 接口分离原则48
4.2.5 依赖倒置原则49
4.2.6 迪米特法则50
4.2.7 不要重复你自己51
4.3 圈复杂度52
第5章 编程环境的熟悉53
5.1 保存动作与自动格式化53
5.2 快速修复58
5.2.1 缺少类59
5.2.2 缺少方法60
5.2.3 缺少变量61
5.2.4 类型不匹配62
5.3 重构63
5.3.1 改名64
5.3.2 改变方法签名68
5.3.3 提取方法69
5.3.4 移动73
5.3.5 引入参数对象76
5.3.6 引入接口77
5.3.7 向上提取78
5.3.8 提取常量81
5.3.9 局部变量变为域变量82
5.3.10 引入工厂82
5.4 自动完成83
5.5 大纲84
5.6 eclipse快捷键86
第6章 编程语言的学习88
6.1 注解88
6.2 异常94
6.3 反射97
6.4 泛型100
第7章 设计方法的学习101
7.1 设计模式101
7.2 依赖注入102
7.3 map的妙用103
7.4 采用位掩码减少类的个数107
7.5 list处理z-order110
第8章 英文能力的提升113
8.1 词性113
8.2 时态115
8.3 语法116
8.4 否定词117
8.5 成对词119
8.6 近义词120
8.7 前缀、后缀120
8.8 缩写122
8.9 正确用词122
第9章 编程习惯的改进124
9.1 命名方面的改进124
9.1.1 命名的基本原则124
9.1.2 包的命名125
9.1.3 接口的命名125
9.1.4 类的命名125
9.1.5 注解的命名126
9.1.6 枚举的命名126
9.1.7 方法的命名127
9.1.8 变量129
9.1.9 常量的命名130
9.1.10 相似的命名130
9.2 注释方面的改进131
9.2.1 javadoc131
9.2.2 todo、fixme和xxx132
9.2.3 其他注释133
9.2.4 方法的注释133
9.2.5 类的注释133
9.2.6 版权声明134
9.3 风格方面的改进135
9.3.1 缩进与对齐135
9.3.2 空格与空行138
9.3.3 行长与换行140
9.4 结构方面的改进140
9.4.1 缩短长判定140
9.4.2 缩短长分支144
9.4.3 减少参数个数148
9.4.4 减少嵌套的层数150
9.4.5 去掉重复代码152
9.4.6 分离暧昧关系155
9.4.7 多维度变化156
9.4.8 缩短长方法158
9.4.9 正则表达式158
9.4.10 自相似对象160
9.4.11 同质化处理161
9.5 架构方面的改进162
9.5.1 mvc162
9.5.2 包含关系164
9.5.3 继承关系164
9.5.4 包的划分165
9.5.5 内部类、内部接口及内部枚举166
9.5.6 匿名类167
9.5.7 有限取值范围168
第10章 测试代码的自表达改进174
10.1 测试代码的可读性175
10.2 测试代码的可维护性179
10.3 测试代码的可扩展性179
10.4 测试语法180
第11章 lambda表达式182
11.1 filter183
11.2 foreach183
11.3 findany与findfirst184
11.4 sorted184
11.5 uniqueelements185
附录186
本图书信息来源:互动出版网

 


    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
操作系统 iis7站长之家
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3