博客

  • android游戏开发框架libgdx的使用(三)–中文显示与汉字绘制

    android游戏开发框架libgdx的使用(三)–中文显示与汉字绘制

    本文使用的libgdx是0.92版本,和现在的最新版可能有一些不一样的地方。全文内容仅供参考。

    本来这篇想写场景的,但是昨天和群里一个朋友讨论了一下libgdx显示汉字的问题。以前没有注意到这个问题,发现还是蛮严重的,要是不支持中文,libgdx用着就有点不愉快了。

    我们来看看BitmapFont类,这是有关文字绘制的。看一下源码:

    publicBitmapFont () {
    this(Gdx.files.classpath("com/badlogic/gdx/utils/arial-15.fnt"),
    Gdx.files.classpath("com/badlogic/gdx/utils/arial-15.png"),false,true);
    }

    这是默认的构造函数,可以看出它加载了两个文件arial-15.fnt和arial-15.png。

    arial-15.fnt文件的部分内容:

    infoface="Arial"size=15bold=0italic=0charset=""unicode=0stretchH=100smooth=1aa=1padding=0,0,0,0spacing=1,1commonlineHeight=18base=14scaleW=256scaleH=256pages=1packed=0pageid=0file="arial-15.png"charscount=189charid=32x=0y=0width=0height=0xoffset=0yoffset=14xadvance=4page=0chnl=0 charid=255x=0y=0width=8height=19xoffset=-1yoffset=0xadvance=7page=0chnl=0 charid=254x=8y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=253x=17y=0width=8height=19xoffset=-1yoffset=0xadvance=7page=0chnl=0 charid=252x=25y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=251x=34y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=250x=43y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=249x=52y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=248x=61y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=247x=70y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=246x=79y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=245x=88y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=244x=97y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=243x=106y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=242x=115y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=241x=124y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=240x=133y=0width=9height=19xoffset=1yoffset=0xadvance=8page=0chnl=0 charid=239x=142y=0width=5height=19xoffset=0yoffset=0xadvance=3page=0chnl=0 …kerningscount=374kerningfirst=49second=49amount=-1kerningfirst=121second=44amount=-1kerningfirst=121second=46amount=-1kerningfirst=119second=44amount=-1kerningfirst=119second=46amount=-1kerningfirst=118second=44amount=-1kerningfirst=118second=46amount=-1kerningfirst=114second=44amount=-1kerningfirst=114second=46amount=-1kerningfirst=89second=44amount=-2kerningfirst=89second=45amount=-1kerningfirst=89second=46amount=-2kerningfirst=89second=58amount=-1kerningfirst=89second=59amount=-1kerningfirst=89second=65amount=-1kerningfirst=89second=97amount=-1kerningfirst=89second=101amount=-1…

     

    再看看arial-15.png:

    arial-15

    可以很明显看出,libgdx的文字绘制是根据fnt文件获取对应文字的在png中的坐标位置,然后截取图片的相应部分进行绘制。

    那么要让libgdx支持中文思路就很简单了,我们自己构造fnt和png文件,其中包含我们要使用的中文即可。

    作者给我们提供了一个对应的工具:Hiero

    下载后双击运行,在右侧列表中选择一个可以用的字体,然后输入需要的中文,最好保留自动生成的英文和符号。

    hiero界面

    在右侧的Effects中可以设置效果:

    hiero界面效果

    点File—Save as BMFont Files,生成两个文件,将它们拷贝到asserts文件夹。

    生成的文件

    使用

    bitmapFont =new BitmapFont(Gdx.files.internal("cf.fnt"), Gdx.files.internal("cf.png"),false);

    指定我们生成的文件作为绘制的参考,然后绘制:

    bitmapFont.draw(spriteBatch,"FPS" + Gdx.graphics.getFramesPerSecond(),5, Gdx.graphics.getHeight() -10);
    bitmapFont.draw(spriteBatch,"祝大家光棍节快乐",0, Gdx.graphics.getHeight()/2-8);

    效果:

    libgdx显示汉字效果图

    关于多行文字:

    可以调用

    public TextBoundsdrawMultiLine (SpriteBatch spriteBatch, CharSequence str,float x,float y)

    或者

    public TextBoundsdrawMultiLine (SpriteBatch spriteBatch, CharSequence str,float x,float y,float alignmentWidth,HAlignment alignment)
  • android游戏开发框架libgdx的使用(一)–环境搭建

    android游戏开发框架libgdx的使用(一)–环境搭建

    本文使用的libgdx是0.92版本,和现在的最新版可能有一些不一样的地方。全文内容仅供参考。

    Libgdx是一款支持2D与3D游戏开发的游戏类库,兼容大多数微机平台(标准JavaSE实现,能运行在Mac、Linux、Windows等系统)与Android平台(Android1.5以上即可使用,Android2.1以上可满功率发挥)。

    logo:logo

    地址:http://code.google.com/p/libgdx/

    首先下载最新的jar,我下载的是libgdx-0.9.2。

    SpxImage

    新建一个Android项目,File -> New -> Project -> Android Project。我选的SDK是1.6的,最低选择应该是1.5.

    新建一个文件夹libs(这个名字是固定的,不能随意改),将下载到的jar复制进去,android平台只需要复制gdx.jar和gdx-backend-android.jar。

    增加引用,然后将armeabi和armeabi-v7a两个文件夹复制到libs文件夹中。

    SpxImage

    然后写个小东西测试一下环境有没有问题。

    新建类HelloGameActivity,继承AndroidApplication类。

    package com.cnblogs.htynkn;
    
    import com.badlogic.gdx.backends.android.AndroidApplication;
    
    import android.os.Bundle;
    
    publicclass HelloGameActivity extends AndroidApplication {
    @Override
    publicvoidonCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    initialize(new FirstGame(),false);
    }
    }

     

    initialize(new FirstGame(),false);

    就是启动游戏的关键,FirstGame是一个实现了ApplicationListener的类。

    代码如下

    package com.cnblogs.htynkn;
    
    import com.badlogic.gdx.ApplicationListener;
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.GL10;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    
    publicclass FirstGame implements ApplicationListener {
    //绘图用的SpriteBatch
    private SpriteBatch batch;
    @Override
    publicvoidcreate() {
    batch =new SpriteBatch();//实例化
    }
    
    @Override
    publicvoiddispose() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidpause() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidrender() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//清屏
    batch.begin();
    batch.end();
    }
    
    @Override
    publicvoidresize(int width,int height) {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidresume() {
    // TODO Auto-generated method stub
    
    }
    
    }

    因为没有写实际的东西,所以效果是一个黑黑的框。
    SpxImage

    环境搭建就说到这里,下一篇是关于图片绘制的。

    注意:

    如果仔细观察Logcat,就会发现一个error:

    E/libEGL(382): couldn’t load <libhgl.so> library (Cannot load library: load_library[984]: Library ‘libhgl.so’ not found)

    这个没什么关系,这是系统尝试加载硬件OpenGL驱动失败了,然后回到软件的处理方法上,不是缺陷或者错误。

  • android游戏开发框架libgdx的使用(二)–图形绘制

    android游戏开发框架libgdx的使用(二)–图形绘制

    本文使用的libgdx是0.92版本,和现在的最新版可能有一些不一样的地方。全文内容仅供参考。

    首先了解一下何为texture。按照英文解释来理解:一个图片从原始格式解码并上传到GPU就被称为纹理。(说实话我不是很清楚这个的定义哈,求指点)

    为了绘制texture,常常使用几何来描述,通过几何对应的顶点来描述纹理。比如要描述一个矩形,可以通过描述每个顶点来描述矩形。

     

    要绘图时,首先要绑定纹理,然后传递一个几何描述给OpenGL进行绘制。而绘图的大小和位置由几何描述和OpenGL的viewport的设置共同决定。

    当然大部分的游戏都会让viewport的大小和屏幕一致。这就意味使用像素更容易让纹理绘制在合适的大小和位置。

     

    绘制一个矩形的几何图形是非常常见的,同样让同一个纹理在不同位置以不同大小位置也是非常常见的,比如漫天的弹幕。但是每次都传递每个形状到GPU进行绘制的效率是较低的。

    所以许多相同纹理可以一起描述并一起送入GPU,这就是SpriteBatch类所要做的。

     

    SpriteBatch被赋予了纹理和坐标以便每个图形的绘制。它(SpriteBatch)汇集了很多图形而没有直接提交给GPU。如果它被赋予的纹理不同于原有的,它将保持原有的图形,并获取新的图形。

    上一篇文章其实就使用了SpriteBatch,但是没有绘制图形,现在我们来试试绘制。

    先找张图片来,分辨率必须是2的次方(如3232,256512)。

    我截取了我的桌面的一部分,分辨率调成512*512。

    image1

    拷贝到assets文件夹中,图片文件最好都是放在这个里面哈。

    SpxImage

    然后修改代码

    private Texture texture;
    实例化texture,texture=new Texture(Gdx.files.internal("image1.jpg"));
    然后来说一下为什么要将图片放在assets文件夹中。
    Gdx.files是libgdx的文件模块,主要提供以下5大功能。
    • 读取文件
    • 写文件
    • 复制文件
    • 移动文件
    • 列出文件和目录

    而获取操作文件的FileHandle有4种方法。

    1.Classpath路径相对于classpath,文件通常为只读。

    2.Internal内部文件路径相对于程序根目录或者android 的assets文件夹。

    3.External外部文件路径是相对于SD卡根目录

    4.Absolute

    assets文件夹本身就是存储资源的文件夹,而且相比resource文件夹,它其中的资源不会生成R中的ID,用来放图片很是合适。

    所以用Gdx.files.internal(“image1.jpg”)获取图片,然后调用batch.draw(texture,20,10);绘制图形,20,10是坐标,笛卡尔座标,以左下角为原点。

    完整代码:

    package com.cnblogs.htynkn;
    
    import com.badlogic.gdx.ApplicationListener;
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.GL10;
    import com.badlogic.gdx.graphics.Texture;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    
    publicclass FirstGame implements ApplicationListener {
    //绘图用的SpriteBatch
    private SpriteBatch batch;
    //纹理
    private Texture texture;
    @Override
    publicvoidcreate() {
    batch =new SpriteBatch();//实例化
    texture=new Texture(Gdx.files.internal("image1.jpg"));
    }
    
    @Override
    publicvoiddispose() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidpause() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidrender() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//清屏
    batch.begin();
    batch.draw(texture,20,10);
    batch.end();
    }
    
    @Override
    publicvoidresize(int width,int height) {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidresume() {
    // TODO Auto-generated method stub
    
    }
    
    }

    效果:

    SpxImage

    可以看到图片不能完整显示,而实际操作中我们也经常使用图片的一部分,或者将多个图片资源集合在一个图片文件中。

    而要显示图片的一部分就可以使用TextureRegion类了。

    最常用的方法是draw(TextureRegion region, float x, float y, float width, float height)

    指定初始点和长宽。

    修改代码:

    package com.cnblogs.htynkn;
    
    import com.badlogic.gdx.ApplicationListener;
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.GL10;
    import com.badlogic.gdx.graphics.Texture;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.graphics.g2d.TextureRegion;
    
    publicclass FirstGame implements ApplicationListener {
    //绘图用的SpriteBatch
    private SpriteBatch batch;
    //纹理
    private Texture texture;
    //区域
    private TextureRegion region;
    @Override
    publicvoidcreate() {
    batch =new SpriteBatch();//实例化
    texture=new Texture(Gdx.files.internal("image1.jpg"));
    region=new TextureRegion(texture,30,80,200,200);
    }
    
    @Override
    publicvoiddispose() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidpause() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidrender() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//清屏
    batch.begin();
    batch.draw(region,0,0);
    batch.end();
    }
    
    @Override
    publicvoidresize(int width,int height) {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidresume() {
    // TODO Auto-generated method stub
    
    }
    
    }

    效果:

    SpxImage

    也许你觉得TextureRegion不够强大,没有关系,还可以使用Sprite。
    Sprite不光包含TextureRegion的功能,还可以指定位置和颜色。
    关键代码:

    sprite=new Sprite(texture,80,80,400,300);
    sprite.setPosition(10,10);//位置
    sprite.setRotation(15);

    稍微想一下前几个例子就可以发现,其实Sprite的功能就是以上的集合。但是Sprite更方便,它用一个对象描述了一切。

    完整代码如下:

    package com.cnblogs.htynkn;
    
    import com.badlogic.gdx.ApplicationListener;
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.GL10;
    import com.badlogic.gdx.graphics.Texture;
    import com.badlogic.gdx.graphics.g2d.Sprite;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    
    publicclass FirstGame implements ApplicationListener {
    //绘图用的SpriteBatch
    private SpriteBatch batch;
    //纹理
    private Texture texture;
    //精灵
    private Sprite sprite;
    @Override
    publicvoidcreate() {
    batch =new SpriteBatch();//实例化
    texture=new Texture(Gdx.files.internal("image1.jpg"));
    sprite=new Sprite(texture,80,80,400,300);
    sprite.setPosition(10,10);//位置
    sprite.setRotation(15);//旋转
    }
    
    @Override
    publicvoiddispose() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidpause() {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidrender() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);//清屏
    batch.begin();
    sprite.draw(batch);
    batch.end();
    }
    
    @Override
    publicvoidresize(int width,int height) {
    // TODO Auto-generated method stub
    
    }
    
    @Override
    publicvoidresume() {
    // TODO Auto-generated method stub
    
    }
    
    }

    效果:

    SpxImage

    同时可以通过sprite的setColor方法为图形着色。

    setColor(float r,float g,float b,float a)

    其中颜色的表述都是介于0,1之间的数。

    SpxImageSpxImage

    绘制的内容基本就这么多,下一篇是关于关于2D场景的。

    写在最后:

    1.关于混合问题,默认是开启混合了的。这意味着图形绘制完成时半透明的部分已经被混合了。当混合被关闭是任何已经在场景上的东西都会被纹理代替,这适合绘制大背景。

    batch.disableBlending();
    backgroundSprite.draw(batch);
    batch.enableBlending();

    2.关于性能优化

    SpriteBatch 有个构造函数可以指定最大缓冲数目。如果数值过低会造成额外的GPU调用;过高的话将占用过多的内存。

    在SpriteBatch有个字段为maxSpritesInBatch,可以先设置一个很高的缓冲数目,然后观察maxSpritesInBatch的值以确定合适的缓冲值。

    还有一个字段renderCalls,在end被调用时,它的值表示在begin和end之间几何声明被送入GPU的次数。

    还有一个构造函数可以指定缓冲大小和数量,合理的设置可以极大地提供性能。

  • C#使用NSoup解析HTML的乱码解决

    NSoup是JSoup的Net移植版本。使用方法基本一致。

    如果项目涉及HTML的处理,强烈推荐NSoup,毕竟字符串截断太苦逼了。

    下载地址:

    http://nsoup.codeplex.com/

    简单用法如下:

    NSoup.Nodes.Document doc = NSoup.NSoupClient.Parse(HtmlString);

    处理网络上的页面:

    NSoup.Nodes.Document doc = NSoup.NSoupClient.Connect("http://www.cnblogs.com/htynkn/").Get();

    但是遗憾的是NSoup默认的编码是UTF-8,处理中文有乱码(对于编码是UTF-8的自然不会有乱码,但是有些GB2312的就可能有乱码,谢谢 forhells的提醒)。

    目前我找到两种解决办法:

    1.下载网页源代码再处理

    WebClient webClient =new WebClient();
    String HtmlString=Encoding.GetEncoding("utf-8").GetString(webClient.DownloadData("http://www.cnblogs.com/htynkn/"));
    NSoup.Nodes.Document doc = NSoup.NSoupClient.Parse(HtmlString);

    2.获得网页的流

    WebRequest webRequest=WebRequest.Create("http://www.cnblogs.com/htynkn/");
    NSoup.Nodes.Document doc = NSoup.NSoupClient.Parse(webRequest.GetResponse().GetResponseStream(),"utf-8");

    第二种用着比较方便,但是我觉得第一种比较合适,毕竟NSoup是个Html解析类,下载网页代码这种事情本来不应该交给它。

  • Android自动匹配电子邮件地址,网址,电话–谈Linkify的使用

    Android自动匹配电子邮件地址,网址,电话–谈Linkify的使用

    翻看Android Api,无意看到了Linkify。按照Api的说明,Linkify可以转化符合匹配规则的文字为可点击的连接。

    感觉这个还是有点用处,下面来试一试。

    1.新建一个项目

    SpxImage

    2.修改样式文件

    为了方便查看效果,添加一个EditText和一个TextView

    SpxImage

    代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:weightsum="1">
    <edittext android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/inputText">
    <requestfocus></requestfocus>
    </edittext>
    <textview android:layout_height="wrap_content" android:textappearance="?android:attr/textAppearanceLarge" android:layout_width="fill_parent" android:layout_weight="0.08" android:id="@+id/viewText" android:text="请输入内容"></textview>
    </linearlayout>

    3.修改AndroidLearnActivity.java

    看一下关键部分的说明

    SpxImage

    在本例子中我们使用第一个。再看一看Linkify默认支持识别什么。

    SpxImage

    MAP_ADDRESSES我没有理解到…

    下面看一下完整的代码:

    package cn.ghy.sdx;
    import android.app.Activity;
    import android.os.Bundle;
    import android.text.util.Linkify;
    import android.view.KeyEvent;
    import android.view.View;
    import android.view.View.OnKeyListener;
    import android.widget.EditText;
    import android.widget.TextView;
    public class AndroidLearnActivity extends Activity { 
    EditText editText; TextView textView;@OverridepublicvoidonCreate(Bundle savedInstanceState) 
    {super.onCreate(savedInstanceState); setContentView(R.layout.main); editText=(EditText)this.findViewById(R.id.inputText); textView=(TextView)this.findViewById(R.id.viewText); editText.setOnKeyListener(new OnKeyListener() {@OverridepublicbooleanonKey(View v,int keyCode, KeyEvent event) { textView.setText(editText.getText()); Linkify.addLinks(textView, Linkify.EMAIL_ADDRESSES|Linkify.PHONE_NUMBERS|Linkify.WEB_URLS);returnfalse; } }); 
      } 
    }

    效果如下:

    网址:

    2011-11-02-09-46-44

    电话:

    2011-11-02-09-47-30

    邮箱:

    2011-11-02-09-47-17

    学习进阶:

    Linkify自带的几种基本可以满足需要,但是有时候有更灵活的需要。比如我需要用户输入一个身份证号。

    正则我不是很清楚,用个简单的。

    textView.setText(editText.getText());
    Pattern pattern =Pattern.compile("d{15}|d{18}");
    String scheme="http://chaxun?sfz="; //这是随意写哈 Linkify.addLinks(textView, pattern, scheme);

    效果:

    2011-11-02-10-02-08

  • Android中使用Ormlite实现持久化(二)–持久化类的详细配置

    上一篇文章简单的使用了Ormlite一下,但是我觉得Ormlite出色之处就是对于需要字段,表等等的配置设计的比较好。

    下面来说说类的配置:

    如果我们开发的Android应用需要保持用户信息,那么现在新建一个类:UserAccount

    该类有六个变量:

    privateint id;private String username;private String password;private Date regTime;private String tellphone;private String email;

    用eclipse生成get和set方法:

    publicintgetId() {return id; }publicvoidsetId(int id) {this.id = id; }public StringgetUsername() {return username; }publicvoidsetUsername(String username) {this.username = username; }public StringgetPassword() {return password; }publicvoidsetPassword(String password) {this.password = password; }public DategetRegTime() {return regTime; }publicvoidsetRegTime(Date regTime) {this.regTime = regTime; }public StringgetTellphone() {return tellphone; }publicvoidsetTellphone(String tellphone) {this.tellphone = tellphone; }public StringgetEmail() {return email; }publicvoidsetEmail(String email) {this.email = email; }

    下面通过注解的方式配置该类的持久化参数:

    1.表名:

    @DatabaseTable(tableName="dataTableName")

    不指定的话表名就是类名。

    2.字段

    @DatabaseField

    这个可以配置的属性有点多。

    2.1 主键

    @DatabaseField(id=true)

    2.2 列名

    @DatabaseField(columnName="columnName")

    不指定的话就是和变量名一样的

    2.3 数据类型

    @DatabaseField(dataType=DataType.INTEGER)

    这个一般情况下都不用指定,可以根据java 类获得

    2.4 默认值

    @DatabaseField(defaultValue="0")

    2.5 长度

    @DatabaseField(width=13)

    一般用于String型

    2.6 能否为空

    @DatabaseField(canBeNull=false)

    默认为True

    2.7 是否自增长

    @DatabaseField(generatedId=true)

    这是一些比较简单的,关于外键啥的下篇文章再说吧。

  • Asp.net 获取当前目录的三种方法

    方法一:

    string sPath = System.IO.Path.GetDirectoryName(Page.Request.PhysicalPath)

    方法二:

    string sPath = System.Web.HttpContext.Current.Request.MapPath(“/“)

    方法三:

    string sPath = Page.Server.MapPath(“/“);

    我推荐使用第二种

    有时候可能出现找不到类的情况,请引用System.Web.dll

  • 为Android应用程序添加社会化分享功能

    为Android应用程序添加社会化分享功能

    正在做个android的小应用,有点想尝试一下社会化分享,比如分享到新浪微博啥的。看一下新浪,人人网的API,说实话功能很全很强大,但虽说有相对的SDK,但是总觉得不方便。

    因为正在使用友盟的统计SDK,无意间发还有个SNS的SDK,看了一下文档,感觉不错哈。

    总共需要3个包,Umeng-Android-SDK-SnsService.jar,httpmime-4.1.1.jar和commons-httpclient-3.1.jar。大小分别为63K,27K,298K。感觉有点点大,但是比较一下新浪,人人,腾讯微薄提供的API,其实大小没差好多,等下我们还可以压缩一下的嘛。

    新建一个文件夹libs,将3个包导入其中,只有3个哈,其他两个是我这个程序其他功能要使用的。

     

    在开发工具—SNS分享中 设置相关的Api key和Api Secret,没有就去申请一个。

    然后在Android的配置文件中添加两个Activity。

    <activity android:name="com.umeng.api.activity.OauthActivity" android:configchanges="orientation|keyboardHidden">
    </activity>
    
    <activity android:name="com.umeng.api.activity.UpdateStatusActivity" android:theme="@style/Theme.IOSched" android:configchanges="orientation|keyboardHidden">
    <intent-filter>
    <action android:name="android.intent.action.VIEW"></action>
    <category android:name="android.intent.category.DEFAULT"></category>
    <category android:name="android.intent.category.BROWSABLE"></category>
    <data android:scheme="schema友盟的应用KEY"></data>
    </intent-filter>
    </activity>

    官方文档的位置还要多一点点…但是我觉得那些看实际情况了。

    那个scheme那里主要是为了区分,应用KEY就是你在友盟注册的KEY,因为我有用它的统计SDK,所以有KEY,没有的话去申请一个。

    然后添加3个权限,访问网络的权限肯定是必须的,还有判断网络情况,友盟还要求一个读取终端IMEI的权限,一共三个。

     

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">
    <uses-permission android:name="android.permission.INTERNET">
    <uses-permission android:name="android.permission.READ_PHONE_STATE">

    然后是资源文件,下载的SDK有,全部复制到项目里面。

    目前友盟的SDK支持3家:新浪微博,腾讯微博,人人网。如果你只想用其中的两家或者一家可以在umeng_share_strings.xml

    中修改

    <string name="umeng_share_renr">open</string>
    <string name="umeng_share_sina">open</string>
    <string name="umeng_share_tenc">close</string>

    不用的写成Close就可以了。不过我觉得没有很大的问题还是3家都要吧,如果只是用1个布局文件有点小瑕疵..看着不顺眼。

    调用的时候也很简单

    UMSnsService.share(this, “这是内容”);

    如果使用模板的话就传一个Hashmap就去就可以了,具体可以看文档。

    我觉得友盟做的最好的就是提供其他的API,可以更灵活的使用相关功能了。

    比如

    1.获取用户授权

    UMSnsService.CallbackListener listener =new UMSnsService.CallbackListener() @OverridepublicvoidonComplete(Bundlevalue) { String uid =value.getString("uid");//这是授权完成的uid,使用其他授权服务的凭证 } @Override public void onError(UMSNSException e) { } }; UMSnsService.oauthSina(this, listener);

    2.直接分享到特定的SNS提供商

    UMSnsService.update(this, UMSnsService.SHARE_TO.SINA, “这是内容”);

    3.检查用户是否已经授权

    UMSnsService.isAuthorized(this, UMSnsService.SHARE_TO.SINA);

    更多的内容还是参考文档。

    还有一个统计数据可以查看:

      

    总的来说我觉得友盟的分享SDK做的还是不错的,虽然人人分享我一直没有配置成功,而且布局有点问题,但是毕竟大大简化了开发。

    希望友盟以后增加一些其他的SNS提供商,然后相关功能越来越强大。
  • Android中使用ormlite实现持久化–HelloOrmLite

    Android中使用ormlite实现持久化–HelloOrmLite

    Android中内置了sqlite,但是常用的开发语言java是面向对象的,而数据库是关系型的,二者之间的转化每次都很麻烦(主要是我对sql语言不熟悉)。而Java Web开发中有很多orm框架,但是想直接放到Android上用有些麻烦。尝试了一下找Android的orm框架,说实话还有好几个。

    实现考虑的是:androrm
    官网:http://androrm.the-pixelpla.net/
    说实话,这个我实在没有弄懂,一共两个包。
    一个是依赖包:Apache Commons – Lang (2.6)
    另外一个就是主包:androrm.jar 不管怎么下载的都不能使用…

    然后有考虑了一下db4o
    官网:http://www.db4o.com/
    官网上的介绍说是已经支持Android了,但是我一是觉得包有点大,而是觉得速度有点慢

    最后看到的就是ormlite
    官网:http://ormlite.com/
    一共两个包:一个是ormlite-core-4.24.jar,另一个是ormlite-android-4.24.jar
    从以下网址可以下载到:http://ormlite.com/releases/

    下面按照惯例来个Hello world
    新建Android项目:HelloOrmLite

    添加文件夹:libs,将所需的两个包复制到其中。添加引用

    新建一个model:Hello.java

    package cn.sdx.model;
    
    import com.j256.ormlite.field.DatabaseField;
    
    publicclass Hello {
    @DatabaseField(generatedId =true)
    int id;
    @DatabaseField
    String word;
    
    publicHello() {
    }
    
    @Override
    public StringtoString() {
    StringBuilder sb =new StringBuilder();
    sb.append("id=").append(id);
    sb.append(" ,word=").append(word);
    return sb.toString();
    }
    
    }

    @DatabaseField是声明id为数据库字段,generatedId =true声明id为自增长
    然后重写了toString()

    再添加一个DataHelper.java

    package cn.sdx.utils;
    
    import java.sql.SQLException;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.util.Log;
    
    
    import cn.sdx.model.Hello;
    
    import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
    import com.j256.ormlite.dao.Dao;
    import com.j256.ormlite.support.ConnectionSource;
    import com.j256.ormlite.table.TableUtils;
    
    publicclass DataHelper extends OrmLiteSqliteOpenHelper {
    
    privatestaticfinal String DATABASE_NAME ="HelloOrmlite.db";
    privatestaticfinalint DATABASE_VERSION =1;
    private Dao<Hello, Integer> helloDao =null;
    
    publicDataHelper(Context context) {
    super(context, DATABASE_NAME,null, DATABASE_VERSION);
    }
    
    @Override
    publicvoidonCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
    try {
    TableUtils.createTable(connectionSource, Hello.class);
    }catch (SQLException e) {
    Log.e(DataHelper.class.getName(),"创建数据库失败", e);
    e.printStackTrace();
    }
    }
    
    @Override
    publicvoidonUpgrade(SQLiteDatabase db, ConnectionSource connectionSource,int arg2,
    int arg3) {
    try {
    TableUtils.dropTable(connectionSource, Hello.class,true);
    onCreate(db, connectionSource);
    }catch (SQLException e) {
    Log.e(DataHelper.class.getName(),"更新数据库失败", e);
    e.printStackTrace();
    }
    }
    
    @Override
    publicvoidclose() {
    super.close();
    helloDao =null;
    }
    
    public Dao<Hello, Integer>getHelloDataDao()throws SQLException {
    if (helloDao ==null) {
    helloDao = getDao(Hello.class);
    }
    return helloDao;
    }
    }

    在布局文件中添加一个TextView
    HelloOrmliteActivity.java中添加对数据库的操作

    代码如下:

    package cn.sdx;
    
    import java.sql.SQLException;
    import java.util.List;
    
    import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
    import com.j256.ormlite.dao.Dao;
    
    import android.os.Bundle;
    import android.widget.TextView;
    import cn.sdx.model.Hello;
    import cn.sdx.utils.DataHelper;
    
    publicclass HelloOrmliteActivity extends OrmLiteBaseActivity<DataHelper> {
    /** Called when the activity is first created. */
    @Override
    publicvoidonCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    TextView tv = (TextView)this.findViewById(R.id.output);
    try {
    Dao<Hello, Integer> helloDao = getHelper().getHelloDataDao();
    // 添加数据
    for (int i =0; i <2; i++) {
    Hello hello =new Hello("Hello" + i);
    helloDao.create(hello);
    }
    tv.setText(tv.getText() +"n" +"添加数据完成");
    // 查询添加的数据
    List<Hello> hellos = helloDao.queryForAll();
    for (Hello h : hellos) {
    tv.setText(tv.getText() +"n" + h.toString());
    }
    // 删除数据第一条数据
    helloDao.delete(hellos.get(0));
    tv.setText(tv.getText() +"n" +"删除数据完成");
    // 重新查询数据
    hellos = helloDao.queryForAll();
    for (Hello h : hellos) {
    tv.setText(tv.getText() +"n" + h.toString());
    }
    // 修改数据
    Hello h1 = hellos.get(0);
    h1.setWord("这是修改过的数据");
    tv.setText(tv.getText() +"n" +"修改数据完成");
    helloDao.update(h1);
    // 重新查询数据
    hellos = helloDao.queryForAll();
    for (Hello h : hellos) {
    tv.setText(tv.getText() +"n" + h.toString());
    }
    
    }catch (SQLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    
    }
    }

    以上实现了数据库操作相关的增删改,下面是效果:

    OrmLite的功能非常强大,Model类的声明中非常重要,外键约束,非空检查等等问题都有相对的处理方法。

  • Quartz.NET 轻松实现定时删除数据库数据

    Quart是java环境下的任务调度系统,比起原始的数据库触发器标志和独立的调度器线程来说,这个开源的任务调度系统好用了不知道多少倍。最近部门的一个伙伴做了一个投票系统,投票是通过IP限制实现的,IP地址保存在数据库中,需要每天零时删除IP记录。

    系统是Asp.net的,本来想弄个Timer,但是老觉得不怎么放心,所以暂时改成手动了。

     

    最近投票弄完了闲下来研究了一下,发现有个.net环境下的Quart:
    Quart.Net

    从官方主页可以看到这个东西是从Quart移植过来的,就Down下了试了一下,发现用着很顺手。

     

    我使用的是1.03版的。

    引用Quartz.dll,新建一个类MyJob,并实现接口IJob,在public void Execute(JobExecutionContext context)方法中添加对数据库数据删除的相关代码。

    新建一个Global文件,在Application_Start中添加一下代码:

     

    ISchedulerFactory factory =new StdSchedulerFactory();
    IScheduler scheduler = factory.GetScheduler();
    scheduler.Start();
    JobDetail job =new JobDetail("MyJob",typeof(MyJob));
    CronTrigger trigger =new CronTrigger();
    trigger.CronExpressionString ="0 0 0 * * ?";
    trigger.Name ="MyJob";
    scheduler.ScheduleJob(job, trigger);

    注意:因为定时任务依附于Application,所以不要忘记IIS的自动回收,20分钟就会回收一次。比较保险的办法就是再启动一个任务,间隔15分钟访问一次网站。

    当然也可以修改IIS设置,不过不推荐。