Monthly Archives: 三月 2014

Linux下SVN服务搭建

1. SVN服务安装

yum install subversion

在我安装的时候出现了错误:

File “/usr/lib/python2.4/threading.py”, line 416, in start
_start_new_thread(self.__bootstrap, ())
thread.error: can’t start new thread

解决办法是:

编辑/etc/yum/pluginconf.d/fastestmirror.conf

将enabled=1改为enabled=0,禁用该功能

2. SVN配置

创建svn目录

mkdir /data/svn

svnadmin create /data/svn/repo

修改配置文件

进入/data/svn/repo/conf下

编辑svnserve.conf

将anon-access = read 注释去掉,并将read改为none
将authz-db=authz , password-db=passwd 前面注释去掉

1) 设置密码

编辑passwd和authz 文件

passwd格式:

user1=passwd1
user2=passwd2
例如:
zhangchuan=zhangchuan123
kongming=kongming123

2)分配权限

编辑authz文件

authz格式:

2.1). 添加用户组

[groups]
group1=user1,user2,…
group2=user3,user4,…

例如:
[groups]
g1_users=zhangchuan,kongming,guanyu
g2_users=zhangchuan,kongming

2.2)设置用户组的权限

@group1=只读
@group2=读写

例如:
[repo:/]
@g1_users=r
@g2_users=rw

启动svn服务

svnserve -d -r /data/svn/

可以通过netstat -atln查看3690端口是否被使用

到时svn搭建完毕,svn地址为:

svn://服务器IP/repo

 

android小试之答题王

这几天利用空余的时间学习了下android,选择了类似答题的应用来边做边学,美名曰:答题王

既然刚开始,也不搞那么难,能做一个简单的就ok了

首先我定义了三个页面:

1) 首页:FirstPageActivity

2) 答题页面:AnswerQuestionActivity

3) 结果页面:ResultActivity

具体流程是:

1) 用户在首页选择试题类型(有3套题目)

2) 根据用户选择的题型在数据库中查找对应的题目,用户答题

3) 显示用户答题的成绩,并获取用户的排名

主要知识点:

1)android简单布局,元素使用及监听

2)android数据存储及查询(sqlite使用)

3)页面之间数据传递

4)访问服务端接口获取数据

1. 首页

使用3个button,每个button监听用户是否点击

Activity的主要代码是:

Button button1;
Button button2;
Button button3;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.firstpage);
    button1 = (Button)this.findViewById(R.id.Button01);
    button2 = (Button)this.findViewById(R.id.Button02);
    button3 = (Button)this.findViewById(R.id.Button03);
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startNewActivity(1);
        }
    });

    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startNewActivity(2);
        }
    });

    button3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            startNewActivity(3);
        }
    });
}

private void startNewActivity(int parm) {
    Intent i = new Intent();
    i.setClass(FirstPageActivity.this, AnswerQuestionActivity.class);
    i.putExtra("exam_id", parm);
    startActivity(i);
    FirstPageActivity.this.finish();
}

以上使用Intent类作为页面之间的跳转,并且可以在页面之间传递参数。

2. 答题页面

1) 首先需要通过首页传过来的参数查询数据库,数据库使用的是sqlite,里面有一张表t_question,在查询数据库之前首先要将数据库放入应用程序的数据目录下:切换到DDMS视图下,选择File Explorer标签,进入/data/data/(package)/databases,在右上角可以看到有一个代右箭头的图标,点击这个图标,选择需要导入的数据库文件。

查询数据库的代码:

private List> loadData() {
    Intent intent = this.getIntent();
    int exam_id = intent.getIntExtra("exam_id", 0);
    mSQLiteDatabase = this.openOrCreateDatabase("dati_db.s3db", MODE_PRIVATE, null);
    String sql = "select * from t_questions where exam_id="+exam_id;
    Cursor cursor = mSQLiteDatabase.rawQuery(sql, null);
    List> datas = new ArrayList>();
    if(cursor != null) {
        Log.v("loadData", "cursor is not null");
        HashMap map = null;
        if(cursor.moveToFirst()) {
            do{
                try {
                    map = new HashMap();
                    int questionColumnIdx = cursor.getColumnIndex("question");
                    byte[] question = cursor.getBlob(questionColumnIdx);
                    map.put("question", new String(question,"GBK"));
                    int answersColumnIdx = cursor.getColumnIndex("answer");
                    byte[] answer = cursor.getBlob(answersColumnIdx);
                    map.put("answer", new String(answer,"GBK"));
                    int correct_answer = cursor.getInt(cursor.getColumnIndex("correct_answer"));
                    map.put("correct_answer", String.valueOf(correct_answer));
                    datas.add(map);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }while(cursor.moveToNext());
        }
    }
    return datas;
}

以上使用了SQLiteDatabase类(mSQLiteDatabase)操作数据库,将查询的数据封装成一个List对象,值得注意的是,因为数据库中有中文,我使用了cursor.getBlob()方法获取数据后再转化编码的方式。

答题页面的样式为一个文本标题,另外还有答案选项,答案选项我使用的是单项选择类RadioGroup和RadioButton,所以有一个方法:resetQuestion(设置问题)

private void resetQuestion(List> datas, int question_index) {
    if(question_index < datas.size()) {
         question_text.setText(datas.get(question_index).get("question"));
         String answers = datas.get(question_index).get("answer");
         String[] ansArr = answers.split("\\|");
         ans_radioGroup.removeAllViews();
         for(String s : ansArr) {
             RadioButton radioButton = new RadioButton(this.getApplicationContext());
             radioButton.setText(s);
             radioButton.setTextColor(Color.BLACK);
             ans_radioGroup.addView(radioButton);
         }
         correct_answer = Integer.parseInt(datas.get(question_index).get("correct_answer"));
    }else {
        String deviceId = tm.getDeviceId();
        Log.v("deviceId", deviceId);
        String rankStr = RequestUtil.sendGet("http://XXX.XX.XX.XX/rank.php", "user="+deviceId+"&total="+datas.size()+"&correct="+correct_number);

        Log.v("rankResult", rankStr);
        try {
            JSONObject jsonObj = new JSONObject(rankStr);
            int rank = Integer.parseInt(jsonObj.get("rank").toString());
            Log.v("rank", String.valueOf(rank));
            this.goIntoResultView(rank);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

question_index为定义的一个全局变量,当用户回答的问题数小于总数,则执行初始化题目的页面,这里使用一个ans_radioGroup变量就可以了,监听用户的行为,代码后面会讲到,每次都需要使用ans_radioGroup.removeAllViews()清除掉上次的答案选项,再根据下次答案选项初始化单选按钮的个数,correct_answer也是一个全局变量,记录当前题目的正确选项。

当用户答玩所有的题目后获取用户的排名,跳转到成绩页面,这里通过获取手机的设备号来标识唯一用户,使用:

final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
String deviceId = tm.getDeviceId();

另外向服务端请求数据,我封装了一个类RequestUtil,发送一个GET请求,具体代码如下:

/**
 * 向指定URL发送GET方法的请求
 * 
 * @param url
 *        发送请求的URL
 * @param params
 *        请求参数,请求参数应该是name1=value1&name2=value2的形式。
 * @return URL所代表远程资源的响应
 */
public static String sendGet(String url, String params) {
    String result = "";
    BufferedReader in = null;
    try {
        String urlName = url + "?" + params;
        URL realUrl = new URL(urlName);
        // 打开和URL之间的连接
        URLConnection conn = realUrl.openConnection();
        // 设置通用的请求属性
        conn.setRequestProperty("accept", "*/*");
        conn.setRequestProperty("connection", "Keep-Alive");
        conn.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
        in = new BufferedReader(
                new InputStreamReader(conn.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            result += "\n" + line;
        }
    } catch (Exception e) {
        System.out.println("发送GET请求出现异常!" + e);
        e.printStackTrace();
    }
    finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    return result.length()>1?result.substring(1):result;
}

4)ans_radioGroup监听用户的行为:

ans_radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
    Log.v("correct_answer", String.valueOf(correct_answer));
    RadioButton correctButton = getRadioButton(correct_answer); 
    if(checkedId == correctButton.getId()) {
        displayToast("回答正确");
        correct_number ++;
    }else {
        displayToast("回答错误");
    }
    question_index ++;
    resetQuestion(datas, question_index);
}
});

里面有两个小方法:

4.1) getRadioButton(correct_answer),根据正确答案,获取对应的RadioButton,correct_answer我在数据库中存储的是题目的编号,具体方法代码如下:

private RadioButton getRadioButton(int correct_answer) {
    return (RadioButton)ans_radioGroup.getChildAt(correct_answer - 1);
}

因为RadioGroup是从0开始计数的

4.2)  displayToast(str),提示框,具体介绍可查看这里,代码如下:

private Toast displayToast(String str) {
    Toast toast = Toast.makeText(this, str, Toast.LENGTH_SHORT);
    toast.setGravity(Gravity.TOP, 0, 220);
    toast.show();
    return toast;
}

 3. 成绩页面

很简单,获取答题页面传过来的参数,显示即可。