Android答题APP的设计与实现

还没有整理完,待续……

学校开了Android课,最后让交一个大作业。正好拿来练练手,记录下思路。也希望能给有需要的朋友们一些帮助。恩,纯小白教程,大神们可以绕路了。

作业的题目是这样的:

考试APP系统:

1)要求有用户登陆功能:从远程服务器进行登陆验证。
2)要有考试测试界面,主要是选择、判断、简答题目测试。
3)要有统计成绩界面和错题显示界面。

评分标准:

1、界面设计占评分的30%
2、系统运行正确; 功能完善;工作量充分; 系统实现有一定的技术的难度。50%
3、要求有适当的系统主要模块的文档说明和代码注释。
4、直接将数据库文件(数据库一定要备份成SQL语句格式,指明数据库)和项目文件提交。

乍一看挺简单的,真要研究起来,写的实用一些,还真有点不知如何下手,那跟着我的思路,一起来吧!恩,不想看思路的,可以直接戳Android源码下载源码来看了。

功能需求设计:

登录注册
答题:选择题,判断题,简答题
答题得分计算
错题查看

最后效果

总体思路

总体思路是这样的,App通过http连接服务器,进行登录或者注册服务,登录成功之后,服务器查询数据库并以json的形式返回试题数据。App接收数据之后,解析并存到本地数据库,然后展示给用户答题。点击交卷按钮后,进行评分并可进行错题查看。内容比较杂乱,大家可以根据目录来快速查看自己需要或者感兴趣的地方。

数据库设计

首先,就登录注册的功能来说,得先有一个用户表,包含用户名,密码,id号这些基本的内容。我在这里又加了一个权限字段,用来返回状态。(设置权限字段,方便日后进行扩展,可设置用不同数字代表不同等级或身份)

tbl_user_info

其次,就是题库了。为了使项目具有实用性,减小安装包体积,便于更新修正,题库同样也需要放在服务器上才合适。

tbl_question

jsp程序

jsp依赖了两个jar包,分别是连接mysql的驱动:mysql-connector-java-5.1.34-bin还有生成json用的:json 。为了减少代码的耦合性,这里采用MVC模式进行设计。(自以为是MVC)。目录结构如下:

登录注册

1.连接数据库

数据库操作类,封装了连接,查询,关闭数据库的方法。大家如果使用这部分代码,别忘了把数据库连接常量改成自己的。

//****连接数据库**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;
 }
}

2.登录

客户端提交过来一个用户名,一个密码,jsp连接数据库查询,如果两者都符合,返回登录成功信息,否则返回登录失败信息。(我这里用权限来代表,当权限>-1即为登录成功)。

3.注册

客户端同样提交过来一个用户名,一个密码,但是需要首先查询数据库,看看该用户名是否已被注册,若没有,则执行数据库插入操作。成功则返回注册成功,否则返回失败信息。

//****服务代码****
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就可以了。

//****登录代码****
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();
 }

4.json格式设计

注册结果

{
 "username": "001",
 "msg": "ok"
}

登录结果

{
 "username": "001",
 "permission": 0
}

答题

json格式设计

{
 "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基类)

为了让增强代码可读性,减少重复代码,所以把一些共性代码做了抽取。

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() {
 }

 /**
  * 初始化界面数据
  */
 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秒钟跳转主页面。

public 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

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() {
  //登录按钮,注册链接设置点击监听事件
  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

<?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

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() {
  //根据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

<?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由题目数量决定)

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();

//  联网获取数据
  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<>();
  Log.e("zwc", "initNet: 开始联网…………");
  //进度条对话框
  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) {
      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());
      }
//      设置适配器
      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: 联网结束…………");
 }

 /**
  * 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通过手势实现答题器翻页效果
  • Android实现简单的答题系统
(0)

相关推荐

  • Android通过手势实现答题器翻页效果

    本文实例为大家分享了Android答题器翻页功能,主要使用ViewFilpper和GestureDetector来实现,供大家参考,具体内容如下 1.效果图 2.实现思路 把Activity的TouchEvent事件交个GestureDetector来处理,然后使用ViewFilpper使用动画控制多个组件的之间的切换效果.手势的一个Api就不详细说了,大家如果不了解可以查一下. 3.实现的步骤 1).构建手势检测器 2).准备数据 3).为ViewFilpper添加子控件. 4).初始化Ani

  • Android实现简单的答题系统

    本文实例为大家分享了Android实现答题系统的具体代码,供大家参考,具体内容如下 Question: package com.example.lenovo.exam; /** * Created by lenovo on 2017/12/4. */ //保存从数据库中读取的记录 public class Question { public String question; public String answerA; public String answerB; public String a

  • Android答题APP的设计与实现

    还没有整理完,待续-- 学校开了Android课,最后让交一个大作业.正好拿来练练手,记录下思路.也希望能给有需要的朋友们一些帮助.恩,纯小白教程,大神们可以绕路了. 作业的题目是这样的: 考试APP系统: 1)要求有用户登陆功能:从远程服务器进行登陆验证. 2)要有考试测试界面,主要是选择.判断.简答题目测试. 3)要有统计成绩界面和错题显示界面. 评分标准: 1.界面设计占评分的30% 2.系统运行正确; 功能完善:工作量充分: 系统实现有一定的技术的难度.50% 3.要求有适当的系统主要模

  • Android用户注册界面简单设计

    本文实例为大家分享了Android用户注册界面的设计,供大家参考,具体内容如下 I. 实例目标 设计一个用户注册界面,在其中要使用到一些基础控件,如 文本框.编辑框.按钮.复选框等控件 II. 技术分析 首先在布局文件中使用控件的标记来配置所需要的各个控件,然后在 主Activity中获取到该控件,给其添加监听器来监听其操作,最后在控制台输出所操作的内容. III. 实现步骤 在Eclipse中创建 Android项目,名称为 TestUserRegister .设计一个用户注册界面,在其中要使

  • 基于SQLite的Android登录APP

    基于SQLite的Android登录APP 该登录APP主要包括三个模块: 1.登录:用户选择登录方式.登录身份,输入账号密码,完成登录. 2.忘记密码:用户输入新密码及验证码修改登录密码. 3.个人信息:用户完成登录后设置个人信息并显示. 使用控件: 1.单选按钮RadioButton:区分是密码登录还是验证码登录. 2.下拉框Spinner:区分是个人用户还是公司用户. 3.编辑框EditText:输入手机号和密码(或验证码). 4.复选框CheckBox:判断是否记住密码. 5.相对布局R

  • android studio实验: UI设计 ListView及事件响应

    实验目的: 1.学习使用ListView及其事件响应方法. 2.阅读sdk/doc/index脱机文档或者在Android developer开发者网站上,学习使用弹出菜单PopupMenu及其事件响应方法. 实验要求: 1.实现一个列表,其中显示班级学号姓名,提供添加功能 2.对添加的选项,通过长按某项,调用弹出菜单显示删除功能,并删除该选项. package com.example.shiyan3; import androidx.annotation.NonNull; import and

  • Android实现APP秒表功能

    本文实例为大家分享了Android实现APP秒表功能的具体代码,供大家参考,具体内容如下 这几天一直在看安卓,也正好赶上老师布置的作业,所以就做了一个秒表.自己参考了一下别人的图标,有了一些灵感所以顺便也设计了一下界面.下面先贴一下秒表的界面: 打开秒表后的第一个界面 点击开始计时,开始键变为暂停,记录和停止开始变实: 点击记录: 记录满了之后自动上移,通过滑动可以查看前面的: 点击暂停: 停止: 重新开始和记录: 双击返回键退出: 下面贴出Activity的代码: package com.ex

  • 详解Android更改APP语言模式的实现过程

    一.效果图 二.描述 更改Android项目中的语言,这个作用于只用于此APP,不会作用于整个系统 三.解决方案 (一)布局文件 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" a

  • Android判断App前台运行还是后台运行(运行状态)

    本文通过图文并茂的方式给大家介绍android判断app状态的相关内容,具体详情如下所示: 要了解这块,首先需要明白一些概念,app,process,task 1.process就是进程,是linux的概念. 2.一般一个app拥有一个uid,运行在一个进程里,如果app中给service等定义不同的uid,那Service就运行在另外一个进程里,也就是说uid就相当于进程的id一样,一个uid就代表一个进程:也可以几个app定义一个uid,那他们就运行在一个进程里了. 3.task是andro

  • Android的App启动时白屏的问题解决办法

    Android的App启动时白屏的问题解决办法 在手机上调试后第一次启动后会等待很长时间白屏, 设置style样式,给activity加上设置的样式,完美解决 参考一下下面的代码.就可以解决(亲测好用) <style name="SplashTheme" parent="AppBaseTheme"> <!-- 将splash图片设置在这,这样这张图片取代白屏 --> <item name="android:windowBack

  • Android直播app送礼物连击动画效果(实例代码)

    最近在做公司的直播项目,需要实现一个观看端连击送礼物的控件: 直接上代码: /** * @author yangyinglong on 2017/7/11 16:52. * @Description: todo(这里用一句话描述这个类的作用) * @Copyright Copyright (c) 2017 Tuandai Inc. All Rights Reserved. */ public class CustomGiftView extends LinearLayout { private

  • Android中App字体大小不随系统改变而改变

    在 "设置" , "显示" , "字体大小" 里面我们可以设置系统字体大小 App界面字体,如果被修改之后,可能就达不到理想状态的效果,界面布局就发生了变化. 未修改过的效果(测试机型:Nexus 5): 正常 小 超大 修改之后的效果(测试机型:Nexus 5): 正常 小 超大 我们从这两组对比图中可以直观的看到修改后的App字体大小不随系统改变而改变. 其实实现起来很简单,无需设置布局文件里面的 "textSize",只

随机推荐