Android答題APP的設(shè)計與實現(xiàn)
還沒有整理完,待續(xù)……
學(xué)校開了Android課,最后讓交一個大作業(yè)。正好拿來練練手,記錄下思路。也希望能給有需要的朋友們一些幫助。恩,純小白教程,大神們可以繞路了。
作業(yè)的題目是這樣的:
考試APP系統(tǒng):
1)要求有用戶登陸功能:從遠程服務(wù)器進行登陸驗證。
2)要有考試測試界面,主要是選擇、判斷、簡答題目測試。
3)要有統(tǒng)計成績界面和錯題顯示界面。
評分標準:
1、界面設(shè)計占評分的30%
2、系統(tǒng)運行正確; 功能完善;工作量充分; 系統(tǒng)實現(xiàn)有一定的技術(shù)的難度。50%
3、要求有適當?shù)南到y(tǒng)主要模塊的文檔說明和代碼注釋。
4、直接將數(shù)據(jù)庫文件(數(shù)據(jù)庫一定要備份成SQL語句格式,指明數(shù)據(jù)庫)和項目文件提交。
乍一看挺簡單的,真要研究起來,寫的實用一些,還真有點不知如何下手,那跟著我的思路,一起來吧!恩,不想看思路的,可以直接戳Android源碼下載源碼來看了。
功能需求設(shè)計:
登錄注冊
答題:選擇題,判斷題,簡答題
答題得分計算
錯題查看
最后效果

總體思路
總體思路是這樣的,App通過http連接服務(wù)器,進行登錄或者注冊服務(wù),登錄成功之后,服務(wù)器查詢數(shù)據(jù)庫并以json的形式返回試題數(shù)據(jù)。App接收數(shù)據(jù)之后,解析并存到本地數(shù)據(jù)庫,然后展示給用戶答題。點擊交卷按鈕后,進行評分并可進行錯題查看。內(nèi)容比較雜亂,大家可以根據(jù)目錄來快速查看自己需要或者感興趣的地方。
數(shù)據(jù)庫設(shè)計
首先,就登錄注冊的功能來說,得先有一個用戶表,包含用戶名,密碼,id號這些基本的內(nèi)容。我在這里又加了一個權(quán)限字段,用來返回狀態(tài)。(設(shè)置權(quán)限字段,方便日后進行擴展,可設(shè)置用不同數(shù)字代表不同等級或身份)
tbl_user_info

其次,就是題庫了。為了使項目具有實用性,減小安裝包體積,便于更新修正,題庫同樣也需要放在服務(wù)器上才合適。
tbl_question

jsp程序
jsp依賴了兩個jar包,分別是連接mysql的驅(qū)動:mysql-connector-java-5.1.34-bin還有生成json用的:json 。為了減少代碼的耦合性,這里采用MVC模式進行設(shè)計。(自以為是MVC)。目錄結(jié)構(gòu)如下:

登錄注冊
1.連接數(shù)據(jù)庫
數(shù)據(jù)庫操作類,封裝了連接,查詢,關(guān)閉數(shù)據(jù)庫的方法。大家如果使用這部分代碼,別忘了把數(shù)據(jù)庫連接常量改成自己的。
//****連接數(shù)據(jù)庫**DBManager***
public class DBManager {
// 數(shù)據(jù)庫連接常量
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";
// 靜態(tài)成員,支持單態(tài)模式
private static DBManager per = null;
private Connection conn = null;
private Statement stmt = null;
// 單態(tài)模式-懶漢模式
private DBManager() {
}
public static DBManager createInstance() {
if (per == null) {
per = new DBManager();
per.initDB();
}
return per;
}
// 加載驅(qū)動
public void initDB() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e) {
e.printStackTrace();
}
}
// 連接數(shù)據(jù)庫,獲取句柄+對象
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.");
}
// 關(guān)閉數(shù)據(jù)庫 關(guān)閉對象,釋放句柄
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;
}
}
2.登錄
客戶端提交過來一個用戶名,一個密碼,jsp連接數(shù)據(jù)庫查詢,如果兩者都符合,返回登錄成功信息,否則返回登錄失敗信息。(我這里用權(quán)限來代表,當權(quán)限>-1即為登錄成功)。
3.注冊
客戶端同樣提交過來一個用戶名,一個密碼,但是需要首先查詢數(shù)據(jù)庫,看看該用戶名是否已被注冊,若沒有,則執(zhí)行數(shù)據(jù)庫插入操作。成功則返回注冊成功,否則返回失敗信息。
//****服務(wù)代碼****
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("權(quán)限===" + 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;
}
/**
* 檢測該賬戶是否已經(jīng)注冊
*
* @param username
* @return 注冊狀態(tài)
*/
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就可以了。
//****登錄代碼****
String username = request.getParameter("username");
String password = request.getParameter("password");
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
System.out.println("客戶端參數(shù):" + username + " ====== " + password);
// 新建服務(wù)對象,默認權(quán)限為-1(未登錄狀態(tài))
StartService serv = new StartService();
int permission = -1;
HashMap<String, String> logiii = serv.login(username, password);
String a = logiii.get("username");
// 登陸驗證處理(權(quán)限>-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();
}
4.json格式設(shè)計
注冊結(jié)果
{
"username": "001",
"msg": "ok"
}
登錄結(jié)果
{
"username": "001",
"permission": 0
}
答題
json格式設(shè)計
{
"status": ok, //連接狀態(tài)
"code": "200" //錯誤代碼
"messages": [ //題目內(nèi)容
{
"_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程序設(shè)計
恩,這才是全文的重點好不好?畢竟這是Android課的大作業(yè)誒。開發(fā)工具Android studio,依賴的庫比較多,所以代碼相當簡單。話不多說,開擼了!
應(yīng)該有哪些界面?
SplashActivity(啟動頁面):展示下logo,還可以做一些耗時操作。
LoginActivity(登錄頁面):用來登錄
SignupActivity(注冊頁面):用來注冊
AnswerActivity(答題頁面):答題,上面設(shè)置的viewpager綁定的fragment。
GradeActivity(得分頁面):答題結(jié)束后用來展示分數(shù)。
AnswerFragment:綁定在AnswerActivity之上,根據(jù)題目數(shù)量動態(tài)創(chuàng)建
關(guān)系圖大概就是下面這個樣子。

用到了哪些知識?依賴了什么第三方框架?
恩……這部分是寫在文檔里的,想了想,一并拿出來吧。工程聯(lián)網(wǎng)部分依賴以okhttp為基礎(chǔ)的OkGo框架,數(shù)據(jù)庫部分采用GreenDao框架。其他的,都是特別基礎(chǔ)的一些知識,大致如下:
- 頁面intent跳轉(zhuǎn),參數(shù)的傳遞
- 聯(lián)網(wǎng)操作以及json數(shù)據(jù)的解析
- sqlite數(shù)據(jù)庫的連接以及增刪改查
- viewpager與fragment的綁定。
- 計時器的設(shè)計實現(xiàn)
- 主題樣式的自定義設(shè)置
- 自定義對話框
- 背景選擇器selector的使用
- 頁面跳轉(zhuǎn)動畫效果的設(shè)計與實現(xiàn)
- listview數(shù)據(jù)填充及優(yōu)化
頁面詳解
BaseActivity(Activity基類)
為了讓增強代碼可讀性,減少重復(fù)代碼,所以把一些共性代碼做了抽取。
public 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() {
}
/**
* 初始化界面數(shù)據(jù)
*/
void initData() {
}
/**
* 綁定監(jiān)聽器與適配器
*/
void initListener() {
}
/**
* 對統(tǒng)一的按鈕進行統(tǒng)一處理
*
* @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秒鐘跳轉(zhuǎn)主頁面。
public class SplashActivity extends BaseActivity {
@Override
int getLayoutId() {
return R.layout.activity_splash;
}
@Override
void initData() {
//延時2s,跳轉(zhuǎn)。
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//跳轉(zhuǎn)主頁面
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
}, 2000);
}
}
LoginActivity(登錄頁面)
java代碼LoginActivity.java
public 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() {
//登錄按鈕,注冊鏈接設(shè)置點擊監(jiān)聽事件
btn_login.setOnClickListener(this);
tv_signup.setOnClickListener(this);
}
@Override
void processClick(View v) {
switch (v.getId()) {
//點擊登錄按鈕,執(zhí)行登錄操作
case R.id.btn_login:
login();
break;
//如果點擊了注冊鏈接,則跳轉(zhuǎn)到注冊頁面
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() {
//如果內(nèi)容不合法,則直接返回,顯示錯誤。
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();
//獲取輸入內(nèi)容
String username = et_username.getText().toString().trim();
String password = et_password.getText().toString().trim();
//聯(lián)網(wǎng),獲取數(shù)據(jù)
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);
//如果得到權(quán)限>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() {
//設(shè)置初值,默認為合法
boolean valid = true;
//獲取輸入內(nèi)容
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
<?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="沒有賬號?創(chuàng)建一個"
android:gravity="center"
android:textSize="16dip"/>
</LinearLayout>
</ScrollView>
SignupActivity(注冊頁面)
SignupActivity.java
public 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() {
//根據(jù)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:
//點擊登錄連接,跳轉(zhuǎn)到登錄頁面
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("創(chuàng)建賬號...");
progressDialog.show();
//獲取數(shù)據(jù)
String username = _nameText.getText().toString();
String password = _passwordText.getText().toString();
// 聯(lián)網(wǎng)獲取數(shù)據(jù)
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();
}
/**
* 注冊失敗,按鈕置為可用
* 依據(jù)傳參不同,進行不同吐司
*/
public void onSignupFailed(int i) {
if (i == 1) {
Toast.makeText(getBaseContext(), "該用戶名已經(jīng)被注冊", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getBaseContext(), "注冊失敗", Toast.LENGTH_LONG).show();
}
_signupButton.setEnabled(true);
}
/**
* @return 輸入內(nèi)容是否合法
*/
public boolean validate() {
boolean valid = true;
//從控件中獲取數(shù)據(jù)
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);
}
//檢測重復(fù)密碼是否正確
if (reEnterPassword.isEmpty() || !(reEnterPassword.equals(password))) {
_reEnterPasswordText.setError("兩次密碼不一致");
valid = false;
} else {
_reEnterPasswordText.setError(null);
}
return valid;
}
}
布局文件 activity_signup.xml
<?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>
<!-- 重復(fù)密碼 -->
<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="重復(fù)密碼"
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="創(chuàng)建賬號" />
<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(答題頁面)
回答問題的頁面。當?shù)竭_AnswerActivity頁面的時候,會聯(lián)網(wǎng)獲取題目數(shù)據(jù),并將題目存入本地數(shù)據(jù)庫。然后通過viewpager綁定n個AnswerFragment,對題目進行展示。作答后,進行存庫操作。(n由題目數(shù)量決定)
public 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();
// 聯(lián)網(wǎng)獲取數(shù)據(jù)
initNet(type);
btn_previous.setOnClickListener(this);
btn_submit.setOnClickListener(this);
btn_next.setOnClickListener(this);
vp_answer.setOnPageChangeListener(new MyOnPageChangeListener());
setChronometer();
}
/**
* 設(shè)置計時器
*/
private void setChronometer() {
chronometer.setText(nowtime());
chronometer.start();
chronometer.setOnChronometerTickListener(this);
chronometer.setOnClickListener(this);
}
/**
* 計時器規(guī)則
*
* @param chronometer
*/
@Override
public void onChronometerTick(Chronometer chronometer) {
second++;
if (second == 59) {
minute++;
second = 00;
}
}
/**
* 現(xiàn)在時間
*
* @return
*/
private String nowtime() {
if (second < 10) {
return (minute + ":0" + second);
} else {
return (minute + ":" + second);
}
}
/**
* 初始化網(wǎng)絡(luò)連接
* @param type
*/
private void initNet(String type) {
a = new ArrayList<>();
fragmentlists = new ArrayList<>();
Log.e("zwc", "initNet: 開始聯(lián)網(wǎng)…………");
//進度條對話框
final ProgressDialog progressDialog = new ProgressDialog(AnswerActivity.this, R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("獲取題目中...");
progressDialog.show();
// 聯(lián)網(wǎng)
OkGo.get(CONFIG.URL_GETQUEST1)
.params("type", type)
.execute(new StringCallback() {
@Override
public void onSuccess(String s, Call call, Response response) {
Log.i("zwc", "onSuccess: ========---------======" + s);
//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() + "");
Log.e("zwc", i + "ooooooonSuccessssssssssss: " + questBeanQ.getId() + questBeanQ.getTitle());
}
// 設(shè)置適配器
vp_answer.setAdapter(new MainAdapter(getSupportFragmentManager()));
progressDialog.dismiss();
}
@Override
public void onError(Call call, Response response, Exception e) {
Log.i("zwc", "onError///////////////////");
}
});
Log.e("zwc", "initNet: 聯(lián)網(wǎng)結(jié)束…………");
}
/**
* viewpager適配器
*/
class MainAdapter extends FragmentPagerAdapter {
public MainAdapter(FragmentManager fm) {
super(fm);
}
//獲取條目
@Override
public Fragment getItem(int position) {
return fragmentlists.get(position);
}
//數(shù)目
@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, "已經(jīng)到頭啦!", 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, "已經(jīng)是最后一題了!", 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 交卷操作
// 計算分數(shù)
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;
}
;
}
}
// 傳遞分數(shù)
Intent intent = new Intent(AnswerActivity.this, GradeActivity.class);
intent.putExtra("grade", "" + grade);
// 傳遞題目列表
intent.putStringArrayListExtra("timu", a);
startActivity(intent);
finish();
}
});
builder.setNegativeButton("取消", null);
}
/**
* viewpager監(jiān)聽事件
*/
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) {
}
}
恩,現(xiàn)在就寫了這么多,對于作業(yè)來說應(yīng)該是綽綽有余了。不過還是有很多需要改善的地方。以后有時間的話,會繼續(xù)完善一下。最后,本文挺長的。真誠的感謝一下你能看到這里。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android APP編寫簡單答題器
- Android實現(xiàn)簡單的答題系統(tǒng)
- Android通過手勢實現(xiàn)答題器翻頁效果
- android自定義倒計時控件示例
- android實現(xiàn)倒計時功能代碼
- Android實現(xiàn)計時與倒計時的常用方法小結(jié)
- Android實現(xiàn)加載廣告圖片和倒計時的開屏布局
- Android 實現(xiàn)閃屏頁和右上角的倒計時跳轉(zhuǎn)實例代碼
- Android中使用TextView實現(xiàn)高仿京東淘寶各種倒計時效果
- Android賬號注冊實現(xiàn)點擊獲取驗證碼倒計時效果
- 基于Android實現(xiàn)答題倒計時功能
相關(guān)文章
Android 使用 SharedPreferences 保存少量數(shù)據(jù)的實現(xiàn)代碼
這篇文章主要介紹了Android 使用 SharedPreferences 保存少量數(shù)據(jù)的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04
Android大圖監(jiān)測系統(tǒng)的三種實現(xiàn)方式
在Android應(yīng)用中,大圖的加載和顯示可能導(dǎo)致內(nèi)存占用過高,進而引發(fā)OOM(Out Of Memory)異常,影響應(yīng)用的穩(wěn)定性和用戶體驗,為了更好地管理大圖資源,我們需要建立起一套可靠的大圖監(jiān)測系統(tǒng),文中有詳細的代碼示例供大家參考,需要的朋友可以參考下2024-01-01
Android設(shè)備上非root的抓包實現(xiàn)方法(Tcpdump方法)
通常我們在Android應(yīng)用中執(zhí)行某個命令時會使用“Runtime.getRuntime().exec("命令路徑")”這種方式,但是當我們執(zhí)行抓包操作時,使用這條命令無論如何都不行,通過下面代碼打印結(jié)果發(fā)現(xiàn),該命令一定要在root權(quán)限下才能執(zhí)行,具體實現(xiàn)思路,請參考本教程2016-11-11
Android采取BroadcastReceiver方式自動獲取驗證碼
這篇文章主要介紹了Android采取BroadcastReceiver方式自動獲取驗證碼,感興趣的小伙伴們可以參考一下2016-08-08
Android 中無法取消標題欄的問題小結(jié)(兩種方法)
我們都知道取消標題欄有兩種方式,一種是在Java代碼中取消,另一種通過設(shè)置styles.xml文件中的Theme即可,下面就兩種方法給大家簡答介紹下2016-12-12

