学校开了Android课,最后让交一个大作业。正好拿来练练手,记录下思路。也希望能给有需要的朋友们一些帮助。恩,纯小白教程,大神们可以绕路了。
作业的题目是这样的:
考试APP系统:
1)要求有用户登陆功能:从远程服务器进行登陆验证。
2)要有考试测试界面,主要是选择、判断、简答题目测试。
3)要有统计成绩界面和错题显示界面。
评分标准:
1、界面设计占评分的30%
2、系统运行正确; 功能完善;工作量充分; 系统实现有一定的技术的难度。50%
3、要求有适当的系统主要模块的文档说明和代码注释。
4、直接将数据库文件(数据库一定要备份成SQL语句格式,指明数据库)和项目文件提交。
乍一看挺简单的,真要研究起来,写的实用一些,还真有点不知如何下手,那跟着我的思路,一起来吧!恩,不想看思路的,可以直接戳Android源码下载源码来看了。
下载地址:
可以直接下载,github我也正在整理,有空了会放上去。
https://download.csdn.net/download/zheng_weichao/10891978
百度网盘放了一份(服务器代码和数据库都有),应该可以下载。如果失效了我再更新。
链接: https://pan.baidu.com/s/1uFhsBpkQdtTvUmBj4T4pbA 提取码: kexy
功能需求设计:
- 登录注册
- 答题:选择题,判断题,简答题
- 答题得分计算
- 错题查看
最后效果
总体思路
总体思路是这样的,App通过http连接服务器,进行登录或者注册服务,登录成功之后,服务器查询数据库并以json的形式返回试题数据。App接收数据之后,解析并存到本地数据库,然后展示给用户答题。点击交卷按钮后,进行评分并可进行错题查看。内容比较杂乱,大家可以根据目录来快速查看自己需要或者感兴趣的地方。
文章目录
- 下载地址:
- 功能需求设计:
- 最后效果
- 总体思路
- 数据库设计
- jsp程序
- 登录注册
- 登录
- 注册
- json格式设计
- 答题
- json格式设计
- Android程序设计
- 应该有哪些界面?
- 用到了哪些知识?依赖了什么第三方框架?
- 页面详解
- BaseActivity(Activity基类)
- SplashActivity(启动页面)
- LoginActivity(登录页面)
- SignupActivity(注册页面)
- AnswerActivity ,AnswerFragment(答题页面)
数据库设计
首先,就登录注册的功能来说,得先有一个用户表,包含用户名,密码,id号这些基本的内容。我在这里又加了一个权限字段,用来返回状态。(设置权限字段,方便日后进行扩展,可设置用不同数字代表不同等级或身份)
tbl_user_info
字段 | 类型 | 含义 |
---|---|---|
id | int(自增长主键) | 用户唯一标识符 |
username | varchar | 用户 |
password | varchar | 密码 |
perssion | varchar(默认为0) | 权限 |
其次,就是题库了。为了使项目具有实用性,减小安装包体积,便于更新修正,题库同样也需要放在服务器上才合适。
tbl_question
字段 | 类型 | 含义 |
---|---|---|
id | int(自增长主键) | 题目唯一标识id |
q_type: | int | 题型: 1:选择 2:判断 3:简答 |
title: | varchar | 问题 |
optionA: | varchar | 选项A |
optionB: | varchar | 选项B |
optionC: | varchar | 选项C |
optionD: | varchar | 选项D |
tips: | varchar | 提示 |
answer: | varchar | 答案 |
explain: | varchar | 解释 |
write_answer: | varchar | 你的答案 |
jsp程序
jsp依赖了两个jar包,分别是连接mysql的驱动:mysql-connector-java-5.1.34-bin还有生成json用的:json 。为了减少代码的耦合性,这里采用MVC模式进行设计。(自以为是MVC)。目录结构如下:
登录注册
###连接数据库
数据库操作类,封装了连接,查询,关闭数据库的方法。大家如果使用这部分代码,别忘了把数据库连接常量改成自己的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82//****连接数据库**DBManager*** public class DBManager { // 数据库连接常量 public static final String DRIVER = "com.mysql.jdbc.Driver"; public static final String USER = "root"; public static final String PASS = "root"; public static final String URL = "jdbc:mysql://localhost:3306/shop"; // 静态成员,支持单态模式 private static DBManager per = null; private Connection conn = null; private Statement stmt = null; // 单态模式-懒汉模式 private DBManager() { } public static DBManager createInstance() { if (per == null) { per = new DBManager(); per.initDB(); } return per; } // 加载驱动 public void initDB() { try { Class.forName("com.mysql.jdbc.Driver"); } catch (Exception e) { e.printStackTrace(); } } // 连接数据库,获取句柄+对象 public void connectDB() { System.out.println("Connecting to database..."); try { conn = DriverManager.getConnection(URL, USER, PASS); stmt = conn.createStatement(); } catch (SQLException e) { e.printStackTrace(); } System.out.println("SqlManager:Connect to database successful."); } // 关闭数据库 关闭对象,释放句柄 public void closeDB() { System.out.println("Close connection to database.."); try { stmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } System.out.println("Close connection successful"); } // 查询 public ResultSet executeQuery(String sql) { ResultSet rs = null; try { rs = stmt.executeQuery(sql); } catch (SQLException e) { e.printStackTrace(); } return rs; } // 增添/删除/修改 public int executeUpdate(String sql) { int ret = 0; try { ret = stmt.executeUpdate(sql); } catch (SQLException e) { e.printStackTrace(); } return ret; } }
登录
客户端提交过来一个用户名,一个密码,jsp连接数据库查询,如果两者都符合,返回登录成功信息,否则返回登录失败信息。(我这里用权限来代表,当权限>-1即为登录成功)。
注册
客户端同样提交过来一个用户名,一个密码,但是需要首先查询数据库,看看该用户名是否已被注册,若没有,则执行数据库插入操作。成功则返回注册成功,否则返回失败信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105//****服务代码**** public class StartService { /** * 登录方法 * @param username * @param password * @return 登录成功与否 */ public HashMap<String, String> login(String username, String password) { HashMap<String, String> hashMap = new HashMap<String, String>(); // 获取Sql查询语句 String logSql = "select perssion from userinfo where username ='" + username + "' and password ='" + password + "'"; System.out.println(logSql); // 获取DB对象 DBManager sql = DBManager.createInstance(); sql.connectDB(); hashMap.put("permission", "-1"); hashMap.put("username", username); // 操作DB对象 try { ResultSet rs = sql.executeQuery(logSql); if (rs.next()) { hashMap.put("permission", rs.getInt(1) + ""); System.out.print("权限===" + rs.getInt(1) + "t"); sql.closeDB(); return hashMap; } } catch (SQLException e) { e.printStackTrace(); } sql.closeDB(); return hashMap; } /** * 注册方法 * @param username * @param password * @return 注册成功与否 */ public HashMap<String, String> register(String username, String password) { HashMap<String, String> hashMap = new HashMap<String, String>(); hashMap.put("username", username); hashMap.put("msg", "notok"); if (this.namerepeat(username)) { hashMap.put("msg", "rename"); } else { // 获取Sql查询语句 String regSql = "insert into userinfo(username,password) values('" + username + "','" + password + "')"; System.out.println(regSql); // 获取DB对象 DBManager sql = DBManager.createInstance(); sql.connectDB(); int ret = sql.executeUpdate(regSql); if (ret != 0) { hashMap.put("msg", "ok"); sql.closeDB(); return hashMap; } sql.closeDB(); } return hashMap; } /** * 检测该账户是否已经注册 * * @param username * @return 注册状态 */ public Boolean namerepeat(String username) { String checkSql = "select username from userinfo where username ='" + username + "'"; // 获取Sql查询语句 System.out.println(checkSql); // 获取DB对象 DBManager sql = DBManager.createInstance(); sql.connectDB(); // 操作DB对象 try { ResultSet rs = sql.executeQuery(checkSql); if (rs.next()) { sql.closeDB(); return true; } } catch (SQLException e) { e.printStackTrace(); } sql.closeDB(); return false; } }
登录注册部分的代码基本一样,只把 serv.login变成serv.reglet就可以了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34//****登录代码**** String username = request.getParameter("username"); String password = request.getParameter("password"); username = new String(username.getBytes("ISO-8859-1"), "UTF-8"); System.out.println("客户端参数:" + username + " ====== " + password); // 新建服务对象,默认权限为-1(未登录状态) StartService serv = new StartService(); int permission = -1; HashMap<String, String> logiii = serv.login(username, password); String a = logiii.get("username"); // 登陆验证处理(权限>-1为登录成功) if ("-1".equals(logiii.get("permission"))) { // 登录失败 System.out.print("登录失败Failed"); } else { // 登陆成功 permission = Integer.parseInt(logiii.get("permission")); } JSONObject jsonObj = new JSONObject(); try { jsonObj.put("username", username); jsonObj.put("permission", permission); System.out.println(jsonObj); // 返回信息到客户端 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.print(jsonObj); out.flush(); out.close(); } catch (JSONException e) { e.printStackTrace(); }
json格式设计
注册结果
1
2
3
4
5{ "username": "001", "msg": "ok" }
登录结果
1
2
3
4
5{ "username": "001", "permission": 0 }
答题
json格式设计
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29{ "status": ok, //连接状态 "code": "200" //错误代码 "messages": [ //题目内容 { "_id": 1, //题目id "title": "1+1=?" //题目 "q_type": 0, //题目类型 "optionA": "1", //A选项 "optionB": "2", //B选项 "optionC": "3", //C选项 "optionD": "4", //D选项 "tips”:"这么简单还要提示?", //提示 "answer": "B", //答案 }, { "_id": 2, "title": "2+2=?" "q_type": 0, "optionA": "1", "optionB": "2", "optionC": "3", "optionD": "4", "tips":"这么简单还要提示?", "answer": "D", } ], }
Android程序设计
恩,这才是全文的重点好不好?毕竟这是Android课的大作业诶。开发工具Android studio,依赖的库比较多,所以代码相当简单。话不多说,开撸了!
应该有哪些界面?
- SplashActivity(启动页面):展示下logo,还可以做一些耗时操作。
- LoginActivity(登录页面):用来登录
- SignupActivity(注册页面):用来注册
- AnswerActivity(答题页面):答题,上面设置的viewpager绑定的fragment。
- GradeActivity(得分页面):答题结束后用来展示分数。
- AnswerFragment:绑定在AnswerActivity之上,根据题目数量动态创建
关系图大概就是下面这个样子。
用到了哪些知识?依赖了什么第三方框架?
恩……这部分是写在文档里的,想了想,一并拿出来吧。工程联网部分依赖以okhttp为基础的OkGo框架,数据库部分采用GreenDao框架。其他的,都是特别基础的一些知识,大致如下:
- 页面intent跳转,参数的传递
- 联网操作以及json数据的解析
- sqlite数据库的连接以及增删改查
- viewpager与fragment的绑定。
- 计时器的设计实现
- 主题样式的自定义设置
- 自定义对话框
- 背景选择器selector的使用
- 页面跳转动画效果的设计与实现
- listview数据填充及优化
页面详解
BaseActivity(Activity基类)
为了让增强代码可读性,减少重复代码,所以把一些共性代码做了抽取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59public abstract class BaseActivity extends FragmentActivity implements View.OnClickListener { @Override protected final void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //得到布局文件 setContentView(getLayoutId()); //初始化 initView(); initData(); initListener(); } /** * @return 布局文件id */ abstract int getLayoutId(); /** * 初始化View */ void initView() { } /** * 初始化界面数据 */ void initData() { } /** * 绑定监听器与适配器 */ void initListener() { } /** * 对统一的按钮进行统一处理 * * @param v 点击的View */ @Override public void onClick(View v) { switch (v.getId()) { default: processClick(v); break; } } /** * 点击事件 * * @param v 点击的View */ void processClick(View v) { } }
SplashActivity(启动页面)
绑定activity_splash布局文件,延时2秒钟跳转主页面。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class SplashActivity extends BaseActivity { @Override int getLayoutId() { return R.layout.activity_splash; } @Override void initData() { //延时2s,跳转。 new Handler().postDelayed(new Runnable() { @Override public void run() { //跳转主页面 Intent intent = new Intent(SplashActivity.this, MainActivity.class); startActivity(intent); finish(); } }, 2000); } }
LoginActivity(登录页面)
java代码LoginActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154public class LoginActivity extends BaseActivity { private static final int REQUEST_SIGNUP = 0; EditText et_username; EditText et_password; Button btn_login; TextView tv_signup; @Override int getLayoutId() { return R.layout.activity_login; } @Override void initView() { //通过id找控件 et_username = (EditText) findViewById(R.id.input_username); et_password = (EditText) findViewById(R.id.input_password); btn_login = (Button) findViewById(R.id.btn_login); tv_signup = (TextView) findViewById(R.id.link_signup); } @Override void initListener() { //登录按钮,注册链接设置点击监听事件 btn_login.setOnClickListener(this); tv_signup.setOnClickListener(this); } @Override void processClick(View v) { switch (v.getId()) { //点击登录按钮,执行登录操作 case R.id.btn_login: login(); break; //如果点击了注册链接,则跳转到注册页面 case R.id.link_signup: Intent intent = new Intent(getApplicationContext(), SignupActivity.class); startActivityForResult(intent, REQUEST_SIGNUP); finish(); //动画效果 overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); break; default: break; } } /** * 登录方法 */ public void login() { //如果内容不合法,则直接返回,显示错误。 if (!validate()) { onLoginFailed(); return; } //输入合法,将登录按钮置为不可用,显示圆形进度对话框 btn_login.setEnabled(false); final ProgressDialog progressDialog = new ProgressDialog(LoginActivity.this, R.style.AppTheme_Dark_Dialog); progressDialog.setIndeterminate(true); progressDialog.setMessage("登录中..."); progressDialog.show(); //获取输入内容 String username = et_username.getText().toString().trim(); String password = et_password.getText().toString().trim(); //联网,获取数据 OkGo.get(CONFIG.URL_LOGIN) .params("username", username) .params("password", password) .execute(new StringCallback() { @Override public void onSuccess(String s, Call call, Response response) { Gson gson = new Gson(); JsonLoginBean jsonLoginBean = gson.fromJson(s, JsonLoginBean.class); //如果得到权限>0,则登录成功。 if (jsonLoginBean.getPermission() > 0) { Log.e("zwc", "onSuccess: ==="); onLoginSuccess(); progressDialog.dismiss(); } else { onLoginFailed(); progressDialog.dismiss(); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_SIGNUP) { if (resultCode == RESULT_OK) { this.finish(); } } } /** * 重写返回键的返回方法 */ @Override public void onBackPressed() { // Disable going back to the MainActivity moveTaskToBack(true); } /** * 登录成功 */ public void onLoginSuccess() { btn_login.setEnabled(true); Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); } /** * 登录失败 */ public void onLoginFailed() { Toast.makeText(getBaseContext(), "登陆失败", Toast.LENGTH_LONG).show(); btn_login.setEnabled(true); } /** * @return 判断是否账号密码是否合法 */ public boolean validate() { //设置初值,默认为合法 boolean valid = true; //获取输入内容 String email = et_username.getText().toString().trim(); String password = et_password.getText().toString().trim(); //判断账号 if (email.isEmpty()) { et_username.setError("请输入你的账号"); valid = false; } else { et_username.setError(null); } //判断密码 if (password.isEmpty()) { et_password.setError("请输入你的密码"); valid = false; } else { et_password.setError(null); } return valid; } }
布局文件activity_login.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:fitsSystemWindows="true"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="56dp" android:paddingLeft="24dp" android:paddingRight="24dp"> <ImageView android:src="@drawable/logo" android:layout_width="wrap_content" android:layout_height="72dp" android:layout_marginBottom="24dp" android:layout_gravity="center_horizontal" /> <!-- 账号 --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp"> <EditText android:id="@+id/input_username" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" android:hint="账号" /> </android.support.design.widget.TextInputLayout> <!-- 密码 --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:layout_marginBottom="8dp"> <EditText android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="密码"/> </android.support.design.widget.TextInputLayout> <android.support.v7.widget.AppCompatButton android:id="@+id/btn_login" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:layout_marginBottom="24dp" android:padding="12dp" android:text="登录"/> <TextView android:id="@+id/link_signup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:text="没有账号?创建一个" android:gravity="center" android:textSize="16dip"/> </LinearLayout> </ScrollView>
SignupActivity(注册页面)
SignupActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143public class SignupActivity extends BaseActivity { EditText _nameText; EditText _emailText; EditText _passwordText; EditText _reEnterPasswordText; Button _signupButton; TextView _loginLink; @Override int getLayoutId() { return R.layout.activity_signup; } @Override void initView() { //根据id找控件 _nameText = (EditText) findViewById(R.id.input_name); _emailText = (EditText) findViewById(R.id.input_username); _passwordText = (EditText) findViewById(R.id.input_password); _reEnterPasswordText = (EditText) findViewById(R.id.input_reEnterPassword); _signupButton = (Button) findViewById(R.id.btn_signup); _loginLink = (TextView) findViewById(R.id.link_login); _signupButton.setOnClickListener(this); _loginLink.setOnClickListener(this); } @Override void processClick(View v) { switch (v.getId()) { case R.id.btn_signup: signup(); break; case R.id.link_login: //点击登录连接,跳转到登录页面 Intent intent = new Intent(getApplicationContext(), LoginActivity.class); startActivity(intent); finish(); overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); break; default: break; } } public void signup() { //判断是否合法 if (!validate()) { onSignupFailed(0); return; } _signupButton.setEnabled(false); //显示圆形进度条对话框 final ProgressDialog progressDialog = new ProgressDialog(SignupActivity.this, R.style.AppTheme_Dark_Dialog); progressDialog.setIndeterminate(true); progressDialog.setMessage("创建账号..."); progressDialog.show(); //获取数据 String username = _nameText.getText().toString(); String password = _passwordText.getText().toString(); // 联网获取数据 OkGo.get(CONFIG.URL_SIGNUP) .params("username", username) .params("password", password) .execute(new StringCallback() { @Override public void onSuccess(String s, Call call, Response response) { Gson gson = new Gson(); JsonSignupBean jsonSignupBean = gson.fromJson(s, JsonSignupBean.class); //如果得到返回消息为ok,则注册成功。 if (jsonSignupBean.getMsg().equals("ok")) { Log.e("zwc", "onSuccess: 注册成功"); onSignupSuccess(); //对话框消失 progressDialog.dismiss(); } else { onSignupFailed(1); progressDialog.dismiss(); } } }); } /** * 登陆成功 */ public void onSignupSuccess() { _signupButton.setEnabled(true); Intent intent = new Intent(SignupActivity.this, MainActivity.class); startActivity(intent); finish(); } /** * 注册失败,按钮置为可用 * 依据传参不同,进行不同吐司 */ public void onSignupFailed(int i) { if (i == 1) { Toast.makeText(getBaseContext(), "该用户名已经被注册", Toast.LENGTH_LONG).show(); } else { Toast.makeText(getBaseContext(), "注册失败", Toast.LENGTH_LONG).show(); } _signupButton.setEnabled(true); } /** * @return 输入内容是否合法 */ public boolean validate() { boolean valid = true; //从控件中获取数据 String name = _nameText.getText().toString(); String password = _passwordText.getText().toString(); String reEnterPassword = _reEnterPasswordText.getText().toString(); //检测账号是否正确 if (name.isEmpty()) { _nameText.setError("账号不能为空"); valid = false; } else { _nameText.setError(null); } //检测密码是否正确 if (password.isEmpty()) { _passwordText.setError("请输入密码"); valid = false; } else { _passwordText.setError(null); } //检测重复密码是否正确 if (reEnterPassword.isEmpty() || !(reEnterPassword.equals(password))) { _reEnterPasswordText.setError("两次密码不一致"); valid = false; } else { _reEnterPasswordText.setError(null); } return valid; } }
布局文件 activity_signup.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:fitsSystemWindows="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingLeft="24dp" android:paddingRight="24dp" android:paddingTop="56dp"> <ImageView android:layout_width="wrap_content" android:layout_height="72dp" android:layout_gravity="center_horizontal" android:layout_marginBottom="24dp" android:src="@drawable/logo" /> <!-- 账号 --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginTop="8dp"> <EditText android:id="@+id/input_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="账号" android:inputType="textPersonName" /> </android.support.design.widget.TextInputLayout> <!-- 密码 --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginTop="8dp"> <EditText android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="密码" android:inputType="textPassword" /> </android.support.design.widget.TextInputLayout> <!-- 重复密码 --> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginTop="8dp"> <EditText android:id="@+id/input_reEnterPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="重复密码" android:inputType="textPassword" /> </android.support.design.widget.TextInputLayout> <android.support.v7.widget.AppCompatButton android:id="@+id/btn_signup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:layout_marginTop="24dp" android:padding="12dp" android:text="创建账号" /> <TextView android:id="@+id/link_login" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:gravity="center" android:text="已有账号?马上登陆" android:textSize="16dip" /> </LinearLayout> </ScrollView>
AnswerActivity ,AnswerFragment(答题页面)
回答问题的页面。当到达AnswerActivity页面的时候,会联网获取题目数据,并将题目存入本地数据库。然后通过viewpager绑定n个AnswerFragment,对题目进行展示。作答后,进行存库操作。(n由题目数量决定)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247public class AnswerActivity extends BaseActivity implements Chronometer.OnChronometerTickListener { private Chronometer chronometer; private ViewPager vp_answer; private ArrayList<Fragment> fragmentlists; private int minute = 0; private int second = 0; private AlertDialog.Builder builder; private ArrayList<String> a; private Button btn_previous; private Button btn_submit; private Button btn_next; private int nowpager = 0; private List<QuestBean> messages; private String type; @Override int getLayoutId() { return R.layout.activity_answer; } /** * 初始化布局 */ @Override void initView() { chronometer = (Chronometer) findViewById(R.id._chro_exam); vp_answer = (ViewPager) findViewById(R.id.vp_answer); btn_previous = (Button) findViewById(R.id._btn_previous); btn_submit = (Button) findViewById(R.id._btn_submit); btn_next = (Button) findViewById(R.id._btn_next); // 获取传递来的变量 type = getIntent().getExtras().get("type").toString().trim(); // 联网获取数据 initNet(type); btn_previous.setOnClickListener(this); btn_submit.setOnClickListener(this); btn_next.setOnClickListener(this); vp_answer.setOnPageChangeListener(new MyOnPageChangeListener()); setChronometer(); } /** * 设置计时器 */ private void setChronometer() { chronometer.setText(nowtime()); chronometer.start(); chronometer.setOnChronometerTickListener(this); chronometer.setOnClickListener(this); } /** * 计时器规则 * * @param chronometer */ @Override public void onChronometerTick(Chronometer chronometer) { second++; if (second == 59) { minute++; second = 00; } } /** * 现在时间 * * @return */ private String nowtime() { if (second < 10) { return (minute + ":0" + second); } else { return (minute + ":" + second); } } /** * 初始化网络连接 * @param type */ private void initNet(String type) { a = new ArrayList<>(); fragmentlists = new ArrayList<>(); //进度条对话框 final ProgressDialog progressDialog = new ProgressDialog(AnswerActivity.this, R.style.AppTheme_Dark_Dialog); progressDialog.setIndeterminate(true); progressDialog.setMessage("获取题目中..."); progressDialog.show(); // 联网 OkGo.get(CONFIG.URL_GETQUEST1) .params("type", type) .execute(new StringCallback() { @Override public void onSuccess(String s, Call call, Response response) { //gson解析 Gson gson = new Gson(); JsonQuestBean jsonQuestBean = gson.fromJson(s, JsonQuestBean.class); messages = jsonQuestBean.getMessages(); for (int i = 0; i < messages.size(); i++) { QuestBean questBeanQ = messages.get(i); questBeanQ.setId(i); fragmentlists.add(new AnswerFragment(questBeanQ)); LoveDao.insertLove(questBeanQ); a.add(questBeanQ.getId() + ""); } // 设置适配器 vp_answer.setAdapter(new MainAdapter(getSupportFragmentManager())); progressDialog.dismiss(); } @Override public void onError(Call call, Response response, Exception e) { } }); } /** * viewpager适配器 */ class MainAdapter extends FragmentPagerAdapter { public MainAdapter(FragmentManager fm) { super(fm); } //获取条目 @Override public Fragment getItem(int position) { return fragmentlists.get(position); } //数目 @Override public int getCount() { return fragmentlists.size(); } } @Override void processClick(View v) { switch (v.getId()) { // 点击上一题按钮 case R.id._btn_previous: // 如果是第一题,则谈吐司提醒,否则上移一道题 if (nowpager == 0) { Toast.makeText(AnswerActivity.this, "已经到头啦!", Toast.LENGTH_SHORT).show(); } else { vp_answer.setCurrentItem(--nowpager); } break; // 点击提交按钮 case R.id._btn_submit: // 简答题不进行提交评分 if (type.equals("3")) { Toast.makeText(this, "简答题目前暂不支持评分", Toast.LENGTH_SHORT).show(); return; } // 否则初始化并展示提交对话框 initAlertDialog(); builder.show(); break; // 点击下一题按钮 case R.id._btn_next: // 如果是最后一题,则谈吐司提醒,否则下移一道题 if (nowpager == fragmentlists.size()) { Toast.makeText(AnswerActivity.this, "已经是最后一题了!", Toast.LENGTH_SHORT).show(); } else { vp_answer.setCurrentItem(++nowpager); } break; default: break; } } // 弹出是否确认交卷的对话框 private void initAlertDialog() { //新建对话框 builder = new AlertDialog.Builder(AnswerActivity.this); builder.setTitle("提示"); builder.setMessage("是否确定交卷?"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO: 2017/6/14 交卷操作 // 计算分数 int grade = 0; // 判断题 if (type.equals("2")) { for (int i = 0; i < messages.size(); i++) { // 查询 QuestBean questBeenA = LoveDao.queryLove(Integer.parseInt(a.get(i))); // 判断 if (questBeenA.getAnswer().equals("对") && questBeenA.getMyanswer().equals("A") || questBeenA.getAnswer().equals("错") && questBeenA.getMyanswer().equals("B")) { grade += 20; } ; } } // 选择题 else { for (int i = 0; i < messages.size(); i++) { QuestBean questBeenA = LoveDao.queryLove(Integer.parseInt(a.get(i))); if (questBeenA.getAnswer().equals(questBeenA.getMyanswer())) { grade += 20; } ; } } // 传递分数 Intent intent = new Intent(AnswerActivity.this, GradeActivity.class); intent.putExtra("grade", "" + grade); // 传递题目列表 intent.putStringArrayListExtra("timu", a); startActivity(intent); finish(); } }); builder.setNegativeButton("取消", null); } /** * viewpager监听事件 */ private class MyOnPageChangeListener implements ViewPager.OnPageChangeListener { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { nowpager = position; } @Override public void onPageScrollStateChanged(int state) { } }
恩,现在就写了这么多,对于作业来说应该是够了。不过还是有很多需要改善的地方。以后有时间的话,会继续完善一下。最后,本文挺长的。真诚的感谢一下你能看到这里。
最后
以上就是要减肥煎蛋最近收集整理的关于Android:答题APP的设计与实现(mysql+jsp+Android)下载地址:功能需求设计:最后效果总体思路数据库设计jsp程序Android程序设计的全部内容,更多相关Android:答题APP内容请搜索靠谱客的其他文章。
发表评论 取消回复