安卓项目在线考试系统,防驾考宝典,送给在愁期末项目的学弟学妹们

在此声明,此在线考试系统是利用业余时间写的一个Demo,功能并没有完善,还有两个功能模块没写完,代码注释详细,

并且我会在文章结尾附上源码的下载地址。

我们先来看两个功能模块的效果图,觉得喜欢你再下载源码,由于github账号忘记了,所以源码只能放在博客里.

注:次项目没用到网络,考试题目都来自己本地数据库里面的数据 数据表在res  raw下,名为kaoshi.db

如有看不懂的地方,或者源码跑不起来可关注我的快手id:北海狂鲛

私聊我 我看到了就会帮你解决

功能模块一  顺序练习

功能模块二 随机练习



下面上一部分代码,代码有点多,我就不全部贴上来了

首先在总布局里面我用到了约束布局 需要导入一个依赖

compile 'com.android.support.constraint:constraint-layout:1.0.2'

然后就是一个db文件的数据库, 数据结构如下(如果不会查看db文件,可查看我的上一篇博客,有介绍怎么查看数据表)

接下来是总体的布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hnkjxy.z.onlinetestsystemsdemo.MainActivity">

    <LinearLayout
        android:id="@+id/main_activity_headings"
        android:gravity="center"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:background="@color/LightBlue"
        android:layout_height="40dp">
        <TextView
            android:text="在线考试系统"
            android:textSize="20dp"
            android:textColor="@color/white"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
             />
    </LinearLayout>

    <LinearLayout
        app:layout_constraintTop_toBottomOf="@+id/main_activity_Wrong_topic_practise_imageView"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:background="@drawable/layout_round_a"
        android:layout_width="250dp"
        android:gravity="center"
        android:layout_height="250dp">
        <LinearLayout
            android:id="@+id/l2"
            android:gravity="center"
            android:background="@drawable/layout_round_b"
            android:layout_width="220dp"
            android:layout_height="220dp">
            <LinearLayout
                android:id="@+id/l3"
                android:background="@drawable/layout_round_c"
                android:layout_width="180dp"
                android:gravity="center"
                android:layout_height="180dp">
                <TextView
                    android:text="在线考试"
                    android:textColor="@color/white"
                    android:textSize="30dp"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

    <ImageView
        android:id="@+id/main_activity_simulation_test_imageView"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/main_activity_headings"
        android:background="@mipmap/monikaoshi"
        android:layout_width="50dp"
        android:layout_height="50dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="30dp"/>
    <TextView
        android:id="@+id/main_activity_simulation_test_text"
        android:text="@string/simulationTest"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/main_activity_simulation_test_imageView"
        app:layout_constraintLeft_toLeftOf="@id/main_activity_simulation_test_imageView"
        android:textSize="12dp"
        app:layout_constraintRight_toRightOf="@id/main_activity_simulation_test_imageView"
        android:layout_marginTop="10dp"/>

    <ImageView
        android:id="@+id/main_activity_Wrong_topic_practise_imageView"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/main_activity_headings"
        android:background="@mipmap/cuoti"
        android:layout_width="50dp"
        android:layout_height="50dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginRight="30dp"/>
    <TextView
        android:id="@+id/main_activity_wrong_topic_practise_text"
        android:text="@string/wrongTopicpractise"
        android:textSize="12dp"
        app:layout_constraintLeft_toLeftOf="@id/main_activity_Wrong_topic_practise_imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/main_activity_Wrong_topic_practise_imageView"
        app:layout_constraintRight_toRightOf="@id/main_activity_Wrong_topic_practise_imageView"
        android:layout_marginTop="10dp"/>

    <ImageView
        android:id="@+id/main_activity_random_contact_imageView"
        app:layout_constraintTop_toBottomOf="@id/main_activity_Wrong_topic_practise_imageView"
        android:layout_marginTop="240dp"
        android:background="@mipmap/suiji"
        android:layout_width="50dp"
        android:layout_height="50dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginRight="30dp"/>
    <TextView
        android:id="@+id/main_activity_random_contact_text"
        android:text="@string/RandomContact"
        android:textSize="12dp"
        app:layout_constraintLeft_toLeftOf="@id/main_activity_random_contact_imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/main_activity_random_contact_imageView"
        app:layout_constraintRight_toRightOf="@id/main_activity_random_contact_imageView"
        android:layout_marginTop="10dp"/>

    <ImageView
        android:id="@+id/main_activity_my_collect_imageView"
        app:layout_constraintTop_toBottomOf="@id/main_activity_simulation_test_imageView"
        android:layout_marginTop="240dp"
        android:background="@mipmap/shoucang"
        android:layout_width="50dp"
        android:layout_height="50dp"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginLeft="30dp"/>
    <TextView
        android:id="@+id/main_activity_my_collect_text"
        android:text="@string/myCollect"
        android:textSize="12dp"
        app:layout_constraintLeft_toLeftOf="@id/main_activity_my_collect_imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/main_activity_my_collect_imageView"
        app:layout_constraintRight_toRightOf="@id/main_activity_my_collect_imageView"
        android:layout_marginTop="10dp"/>
</android.support.constraint.ConstraintLayout>

 注:布局里面用到了一些文字,图片,还有背景样式都在源码里,这里我就贴部分出来,图片就不贴了,源码里有

  接下来是背景,自定义的圆角

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    android:useLevel="false">
    <solid android:color="@color/a"/>
    <padding
        android:left="2dp"
        android:top="1dp"
        android:right="2dp"
        android:bottom="1dp" />
    <size android:width="15dp"
        android:height="15dp" />

</shape>

 还有就是文字了 我也贴一下吧

<resources>
    <string name="app_name">OnlineTestSystemsDemo</string>
    <string name="simulationTest">顺序练习</string>
    <string name="wrongTopicpractise">错题练习</string>
    <string name="myCollect">我的收藏</string>
    <string name="RandomContact">随机练习</string>
</resources>

接下来就是MainActivity的代码了,分别为几个功能模块的点击事件

package com.hnkjxy.z.onlinetestsystemsdemo;

import android.Manifest;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.hnkjxy.z.onlinetestsystemsdemo.othersActivity.OnlinetestActivity;
import com.hnkjxy.z.onlinetestsystemsdemo.othersActivity.RandomPracticeActivity;
import com.hnkjxy.z.onlinetestsystemsdemo.othersActivity.SimulationActivity;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    ImageView main_activity_simulation_test_imageView, main_activity_Wrong_topic_practise_imageView,
            main_activity_my_collect_imageView, main_activity_random_contact_imageView;
    TextView main_activity_simulation_test_text, main_activity_wrong_topic_practise_text,
            main_activity_my_collect_text, main_activity_random_contact_text;
    LinearLayout l3;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //        找activity_main布局的方法
        activityMainFindViewById();
//        安卓动态申请权限  因为在高版本的安卓手机上跑不申请会闪退  记住同时在Manifest里配置权限
    //检查权限
        if(ActivityCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
//            申请权限
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
            }

        if(ActivityCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)!= PackageManager.PERMISSION_GRANTED){
//            申请权限
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS},1);
        }
        if(ActivityCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
//            申请权限
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
        }
    }

    //        找activity_main布局的方法
    private void activityMainFindViewById() {
//        布局四个角落的图片id
        main_activity_simulation_test_imageView = (ImageView) findViewById(R.id.main_activity_simulation_test_imageView);
        main_activity_Wrong_topic_practise_imageView = (ImageView) findViewById(R.id.main_activity_Wrong_topic_practise_imageView);
        main_activity_my_collect_imageView = (ImageView) findViewById(R.id.main_activity_my_collect_imageView);
        main_activity_random_contact_imageView = (ImageView) findViewById(R.id.main_activity_random_contact_imageView);
//     布局四个图片下的文字的id
        main_activity_simulation_test_text = (TextView) findViewById(R.id.main_activity_simulation_test_text);
        main_activity_wrong_topic_practise_text = (TextView) findViewById(R.id.main_activity_wrong_topic_practise_text);
        main_activity_my_collect_text = (TextView) findViewById(R.id.main_activity_my_collect_text);
        main_activity_random_contact_text = (TextView) findViewById(R.id.main_activity_random_contact_text);
//       linearlayout的布局id
        l3 = (LinearLayout) findViewById(R.id.l3);
//
//     布局id找到后开始给他们注册点击事件
//       注册点击事件的方法
        registrationSetOnClickListener();
    }

    //    注册点击事件方法
    private void registrationSetOnClickListener() {
        main_activity_simulation_test_imageView.setOnClickListener(this);
        main_activity_Wrong_topic_practise_imageView.setOnClickListener(this);
        main_activity_my_collect_imageView.setOnClickListener(this);
        main_activity_random_contact_imageView.setOnClickListener(this);

        main_activity_simulation_test_text.setOnClickListener(this);
        main_activity_wrong_topic_practise_text.setOnClickListener(this);
        main_activity_my_collect_text.setOnClickListener(this);
        main_activity_random_contact_text.setOnClickListener(this);

        l3.setOnClickListener(this);
    }


    //    这是实现OnClickListener接口必须写的一个方法  ,在里面写点击之后的逻辑
//    在代码的第十行实现的接口
    @Override
    public void onClick(View v) {
        Intent intent;
        AlertDialog.Builder ad = new AlertDialog.Builder(MainActivity.this);
        switch (v.getId()) {
//            模拟考试和文字点击事件的跳转
            case R.id.main_activity_simulation_test_imageView:
                intent = new Intent(MainActivity.this, SimulationActivity.class);
                startActivity(intent);
                break;
            case R.id.main_activity_simulation_test_text:
                intent = new Intent(MainActivity.this, SimulationActivity.class);
                startActivity(intent);
                break;
//          在线考试的点击事件
            case R.id.l3:
                intent = new Intent(MainActivity.this, OnlinetestActivity.class);
                startActivity(intent);
                break;
// 随机练习文字的击事件
            case R.id.main_activity_random_contact_text:
                intent = new Intent(MainActivity.this, RandomPracticeActivity.class);
                startActivity(intent);
                break;
//                随机练习图片的点击事件
            case R.id.main_activity_random_contact_imageView:
                intent = new Intent(MainActivity.this, RandomPracticeActivity.class);
                startActivity(intent);
                break;

//                收藏的图标点击
            case R.id.main_activity_my_collect_imageView:
                ad.setTitle("通知");
                ad.setMessage("此功能暂未实现,对代码有疑问或者不懂可以私聊我快手号\r\n快手id:北海狂鲛");
                ad.setPositiveButton("我知道了", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int i) {
//                        点击隐藏对话框
                        dialog.dismiss();
                    }
                });
//                创建对话框
                ad.create();
//                让用户必须选择对话框,解决弹出对话框点击空白对话框消失的问题
                ad.setCancelable(false);
//                显示对话框
                ad.show();

                break;
//               收藏的文字点击
            case R.id.main_activity_my_collect_text:
                ad.setTitle("通知");
                ad.setMessage("此功能暂未实现,对代码有疑问或者不懂可以私聊我快手号\r\n快手id:北海狂鲛");
                ad.setPositiveButton("我知道了", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int i) {
//                        点击隐藏对话框
                        dialog.dismiss();
                    }
                });
//                创建对话框
                ad.create();
//                让用户必须选择对话框,解决弹出对话框点击空白对话框消失的问题
                ad.setCancelable(false);
//                显示对话框
                ad.show();
                break;
//                错题练习图片点击事件
            case R.id.main_activity_Wrong_topic_practise_imageView:
                break;
//                错题练习文字点击事件
            case R.id.main_activity_wrong_topic_practise_text:
//                AlertDialog.Builder add=new AlertDialog.Builder(MainActivity.this);
//                add.setTitle("通知");
//                add.setMessage("暂无错题数据");
//                add.setPositiveButton("我知道了", new DialogInterface.OnClickListener() {
//                    @Override
//                    public void onClick(DialogInterface dialog, int which) {
//                        dialog.dismiss();
//                    }
//                });
                break;
        }
    }
}

还有几个工具类我也贴出来吧,第一个是存放变量名的类

package com.hnkjxy.z.onlinetestsystemsdemo.Finally;

import android.os.Environment;

import java.io.File;

/**
 * Created by zhouweixiong on 2017/12/21.
 */

/**
 * 定义一些常量
 * 一些表名和字段名
 * 不可修改字段名,否则会得不到数据
 * 在res目录下面有一个raw文件夹,raw里面有一个数据表
 * 如果要android studio查看此表,就去下载一个插件 database
 */

public class MyFinally {
    public static final String TABLE_NAME = "t_question";//表名
    public static final String TABLE_SOUCANG_NAME = "t_soucang";//表名
    //    字段名
    public static final String T01_COLUMN_ID = "question_id";
    public static final String T01_COLUMN_OPTION_TYPE = "option_type";
    public static final String T01_COLUMN_SOU_TYPE = "sou_type";
    public static final String T01_COLUMN_ERROR_TYPE = "error_type";
    //Environment.getExternalStorageDirectory()  获得根路径
//File.separator是用来分隔同一个路径字符串中的目录的,例如:
//    C:\Program Files\Common Files
//    就是指“\”
    public static final String FILE_PAPER_PATH = Environment.getExternalStorageDirectory() + File.separator + "kaoshi";
    //  文件的详细地址,找到此文件
//    FILE_PAPER_PATH 是第31行的地址,拼起来就是详细的文件地址和文件名
    public static final String FILE_PATH = FILE_PAPER_PATH + File.separator + "kaoshi.db";
}

再就是创建系统文件夹和把数据表写入文件夹里的工具类

package com.hnkjxy.z.onlinetestsystemsdemo.Dao;

import android.content.Context;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import com.hnkjxy.z.onlinetestsystemsdemo.Finally.MyFinally;
import com.hnkjxy.z.onlinetestsystemsdemo.R;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

/**
 * Created by zhouweixiong on 2017/12/22.
 */

public class DBWriteSDCard {
    private static final String TAG = "ReleaseDataBase";
    private Context context;

    public DBWriteSDCard(Context context) {
        super();
        this.context = context;
    }


    public void whetherToWriteFile() {// 把raw下的sq写进sd卡
        //        如果你的储存卡存在并且可用
//        只有在SD卡状态为MEDIA_MOUNTED时/mnt/sdcard目录才是可读可写,并且可以创建目录及文件
        // 判断sd卡是否挂载
        if (Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState())) {

            // 建立sd卡对象
            File file = new File(MyFinally.FILE_PAPER_PATH);
//            如果没有此文件夹就创建
            if (!file.exists()) {
//                创建
                file.mkdirs();
            } else {
                Log.d(TAG,"sd已有");
            }
//            实例化文件名对象
            File filePath = new File(MyFinally.FILE_PATH);// 建立sd卡下 的db文件
//             如果文件不存在
            if (!filePath.exists()) {
//                不存在就把raw目录下的kaoshi文件通过流读出来,读出来是为了等会好写进去
                InputStream in = this.context.getResources().openRawResource(
                        R.raw.kaoshi);
//                对程序异常奔溃的捕捉 try catch
                try {
//                  FileOutputStream是文件输出流,是用于将数据写入File或 FileDescriptor的输出流
//                  实例化文件输入流对象(文件名)
                    FileOutputStream fileOutputStream = new FileOutputStream(MyFinally.FILE_PATH);// 得到输出流 文件夹下文件路径
//                    定义了一个byte类型的数组,数组长度为8192
                    byte[] buffer = new byte[8192];
                    int t = 0;
                    while ((t = in.read(buffer)) != -1) {// 半读边写
                        fileOutputStream.write(buffer, 0, t);
                    }
//                    开了流就一定要记得关  因为会占用系统资源
//                   文件读写完 关闭流
                    in.close();
                    fileOutputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }


        }

    }


}

接下来是一个比较重要重要的类了,解析本地数据库的类,其他功能模块都到了此类里的方法来获取题目

package com.hnkjxy.z.onlinetestsystemsdemo.Dao;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

import com.hnkjxy.z.onlinetestsystemsdemo.Finally.MyFinally;
import com.hnkjxy.z.onlinetestsystemsdemo.entityClass.Question;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;

/**
 * Created by zhouweixiong on 2017/12/21.
 */

public class ExamDao {
    //调错用的
    private static final String TAG = "ExamDao";
    //  用来操控数据表的,获取数据等
//    建议百度 SQLiteDatabase 的详细用法
    public static SQLiteDatabase sqLiteDatabase ;
    //上下文
//    其他功能模块要用到的
    private Context context;

    public ExamDao(Context context) {
        this.context = context;
    }

    //    定义一个指数
    private static int index = 0;

    //    打开数据库的方法
    public void openDatabase() {
//        判断如果没有数据表就打开数据表
        if (sqLiteDatabase == null) {
//            DBWriteSDCard这个类的作用是 判断是否有没有此文件夹和此文件,没有就创建,和写入数据库到SD卡的
//            有的话就不会创建
            DBWriteSDCard dbWriteSDCard = new DBWriteSDCard(context);
//            whetherToWriteFile方法里面写的就是上述的注释
            dbWriteSDCard.whetherToWriteFile();
//        建议详细去了解SQLiteDatabase的方法  MyFinally.FILE_PATH 是MyFinally类写的常量的路径,也就是打开文件的路径
            sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(MyFinally.FILE_PATH, null);

        }
    }

    //    关闭数据库的方法
    public void closeDatabase() {
//判断如果打开了就关闭
        if (sqLiteDatabase != null) {
//            SQLiteDatabase的close方法
            sqLiteDatabase.close();
            sqLiteDatabase = null;
        }
    }

    // 按顺序查询得到题目的方法
//    返回一个ArrayList<Question>的集合
    public ArrayList<Question> sequenceQuery() {
//        实例化一个集合 用来保存数据
        ArrayList<Question> arrayList = new ArrayList<Question>();
//  判断有没有打开数据库 没有就打开
        if (sqLiteDatabase == null) {
//            上面写的打开数据库的方法
            openDatabase();
        }
//  判断有没有打开数据库 有就进行操作
        if (sqLiteDatabase != null) {
// 对于数据库记录的操作,可以使用Cursor(游标)来进行
//            sqLiteDatabase.query 查询数据表,后面的null是查询条件,这里是按顺序获得所有数据
            Cursor cursor = sqLiteDatabase.query(MyFinally.TABLE_NAME,
                    null, null, null, null,
                    null, null);
//循环 添加下一条
            while (cursor != null && cursor.moveToNext()) {
//                把得到的数据添加到数组中去
//                对应Question类的数据   参数是表示列数
                arrayList.add(new Question(cursor.getInt(0), cursor.getInt(1),
                        cursor.getString(2), cursor.getString(3),
                        cursor.getBlob(4), cursor.getInt(5),
                        cursor.getString(6), cursor.getString(7), cursor.getString(8),
                        cursor.getString(9), cursor.getString(10), cursor.getInt(11), cursor.getInt(12),
                        cursor.getInt(13), cursor.getInt(14)));
            }
//  循环执行完关闭cursor
            cursor.close();
        }
//        关闭数据库的连接
         closeDatabase();
//        返回数组(已获得的数据都在数组里面)
        return arrayList;
    }


    //得到所以题目试题
    public ArrayList<Question> getAllTopic(int type) {
//        同上面方法注释
        ArrayList<Question> arrayList = new ArrayList<Question>();

        if (sqLiteDatabase == null) {
            openDatabase();
        }
        if(sqLiteDatabase != null){
//            type=0就得到一百题  否则就得到所有题目
            if(type==0){
//               limit 设置query语句返回行的数量,相当于SQL语句中的“LIMIT”关键字,
//            传递null表示没有设置limit语句。注意格式为String,传递的时候需要传递数字字符串,例如“12
//                  这里的代码意思是只能出一百题  type=0就只有一百题
                Cursor cursor = sqLiteDatabase.query(MyFinally.TABLE_NAME, null, null, null, null,
                        null,null,"100" );
                while (cursor != null&&cursor.moveToNext()) {
                    arrayList.add(new  Question(cursor.getInt(0),cursor.getInt(1),
                            cursor.getString(2), cursor.getString(3),
                            cursor.getBlob(4), cursor.getInt(5),
                            cursor.getString(6), cursor.getString(7), cursor.getString(8),
                            cursor.getString(9),cursor.getString(10),cursor.getInt(11),cursor.getInt(12),
                            cursor.getInt(13),cursor.getInt(14)));
                }
                cursor.close();
            }else{
                Cursor cursor = sqLiteDatabase.query(MyFinally.TABLE_NAME, null, null, null, null,
                        null, null,null);
                while (cursor != null&&cursor.moveToNext()) {
                    arrayList.add(new  Question(cursor.getInt(0),cursor.getInt(1),
                            cursor.getString(2), cursor.getString(3),
                            cursor.getBlob(4), cursor.getInt(5),
                            cursor.getString(6), cursor.getString(7), cursor.getString(8),
                            cursor.getString(9),cursor.getString(10),cursor.getInt(11),cursor.getInt(12),
                            cursor.getInt(13),cursor.getInt(14)));
                }
                cursor.close();
            }
        }
        closeDatabase();
        return arrayList;

    }

//    更新 也就是修改数据  values:代表想要更新的数据   这个方法只传了三个参数进来  修改数据则有四个参数,因为第一个参数
//    表名是固定了的
    public int updateQuestion(ContentValues values  , String where  , String []  param){
        int questens=0;
        if (sqLiteDatabase == null) {
            openDatabase();
        }
        if(sqLiteDatabase != null){
//            sqLiteDatabase更新数据表的方法 第一个参数是表名  第二个是要更新的数据
//            第三第四连起来用的 第三个是哪一条(这里传字段名+占位符,占位符就是?号) 第四个就是那一条的具体数据 就是第三个占位符
            questens =sqLiteDatabase.update("t_question", values, where, param);
        }
        closeDatabase();
        return questens;
    }

    public  ArrayList<Question> RandomgetTopic() {
//        注释同上面一样
        HashSet<Question> questions = new HashSet<Question>();
        if (sqLiteDatabase == null) {
            openDatabase();
        }
        if(sqLiteDatabase != null){
//            先查询数据表
            Cursor cursor1 = sqLiteDatabase.query(MyFinally.TABLE_NAME, null, null, null, null,
                    null, null,null);
//            得到数据表的行数 count是126 意思就是有126条数据
            int count = cursor1.getCount();
//            只是这里的差别 随机得到题目
            index =    count/100;
            Random  random = new Random();
            index=  (random.nextInt(index)*10);

            Log.d(TAG, "random.nextInt(index);="+index);


            Cursor cursor = sqLiteDatabase.query(MyFinally.TABLE_NAME, null, null, null, null,
                    null, null,index+","+(100));
            while (cursor != null&&cursor.moveToNext()) {

                questions.add(new  Question(cursor.getInt(0),cursor.getInt(1),
                        cursor.getString(2), cursor.getString(3),
                        cursor.getBlob(4), cursor.getInt(5),
                        cursor.getString(6), cursor.getString(7), cursor.getString(8),
                        cursor.getString(9),cursor.getString(10),cursor.getInt(11),cursor.getInt(12),
                        cursor.getInt(13),cursor.getInt(14)));
            }
            cursor.close();
        }
        closeDatabase();
//      set转list
        ArrayList<Question> arrayList = new ArrayList<Question>(questions);
        return arrayList;
    }

}

接下贴一个功能模块的代码,就贴在线考试这个功能模块的代码的,首先是这个功能模块的布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hnkjxy.z.onlinetestsystemsdemo.othersActivity.OnlinetestActivity">

    <LinearLayout
        android:id="@+id/activity_onlinetest_headings"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@color/LightBlue"
        android:gravity="center"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="在线考试"
            android:textColor="@color/white"
            android:textSize="20dp" />
    </LinearLayout>

    <Chronometer
        android:id="@+id/activity_onlinetest_countdown"
        android:textSize="20dp"
        android:gravity="center"
        android:textColor="@color/red"
        app:layout_constraintTop_toBottomOf="@id/activity_onlinetest_headings"
        android:layout_width="match_parent"
        android:layout_below="@id/activity_onlinetest_headings"
        android:layout_height="30dp" />

    <android.support.v4.view.ViewPager
        android:id="@+id/activity_onlinetest_viewPager"
        android:layout_width="match_parent"
        app:layout_constraintTop_toBottomOf="@id/activity_onlinetest_countdown"
        android:layout_height="390dp"
        >

    </android.support.v4.view.ViewPager>
    <LinearLayout
        android:orientation="horizontal"
        app:layout_constraintBottom_toTopOf="parent"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:id="@+id/activity_onlinetest_their_papers"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:text="交卷"
            android:gravity="center"
            android:textColor="@color/black"
            android:layout_height="match_parent" />

    </LinearLayout>
</android.support.constraint.ConstraintLayout>

接下来是代码了,此功能模块还有一个倒计时的功能,因为在线考试嘛,没有时间限制不好,源码会有注释,这里我就不多哗哗

package com.hnkjxy.z.onlinetestsystemsdemo.othersActivity;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;


import com.hnkjxy.z.onlinetestsystemsdemo.Dao.ExamDao;
import com.hnkjxy.z.onlinetestsystemsdemo.MainActivity;
import com.hnkjxy.z.onlinetestsystemsdemo.R;
import com.hnkjxy.z.onlinetestsystemsdemo.entityClass.Question;

import java.util.ArrayList;

public class OnlinetestActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener,
        View.OnClickListener, RadioGroup.OnCheckedChangeListener, Chronometer.OnChronometerTickListener {

    //    定义控件id
    private RadioButton onlinetest_radioA;
    private RadioButton onlinetest_radioB;
    private RadioButton onlinetest_radioC;
    private RadioButton onlinetest_radioD;

    //  计时器
    public Chronometer chronometer;
    //    考试题目显示
    private TextView onlinetest_show_question;
    //    考试图片显示
    private ImageView onlinetest_imageview;
    // 做题选择
    private RadioGroup onlinetest_radioGroup;

    private TextView activity_onlinetest_their_papers;
    private ViewPager viewpager;
    private static ArrayList<View> viewpagelist;
    //    对错多少题
    private Integer errorCount = 0;
    private Integer scoreCount = 0;
    private Integer rightCount = 0;
    //   指数
    private int index;
    //倒计时的时间
    int minutes = 44, seconds = 59;//45
    //    做题的页数,做完滑动的
    private Integer viewpagerIndex = 0;
    //
    private static OnlinetestActivity onlinetestActivity;
    //    实例化获得题目的类
    private ExamDao examDao;
    //   所有考试题目
    public static ArrayList<Question> arrayList;
    //  答题选项
    public int answer;
    //
    public Intent intent;
    //  标记
    public int flag;
    //自己定义的view的myadapter
    private myadapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_onlinetest);
        //        实例化ExamDao
        examDao = new ExamDao(this);
//
        intent = getIntent();
// flag 传参数用的
        initData();
        init();
    }

    @SuppressLint("WrongConstant")
    public void init() {
        viewpager = (ViewPager) findViewById(R.id.activity_onlinetest_viewPager);
        viewpager.setOnPageChangeListener(this);
//        实例化自己定义的myadapter
        adapter = new myadapter();
//        viewpager.setAdapter(new myadapter());
        viewpager.setAdapter(adapter);
        //初始化交卷
        activity_onlinetest_their_papers = (TextView) findViewById(R.id.activity_onlinetest_their_papers);
        //初始化时间
        chronometer = (Chronometer) findViewById(R.id.activity_onlinetest_countdown);
        //初始化时间显示
        SharedPreferences shar = getSharedPreferences("saveTime",
                Activity.MODE_PRIVATE);

//        倒计时设置  nowtime()是下面写的一个方法
        chronometer.setText(nowtime());
        chronometer.setVisibility(0);
        chronometer.start();
        chronometer.setOnChronometerTickListener(this);
//        点击事件
        activity_onlinetest_their_papers.setOnClickListener(this);
//        设置页码
        viewpager.setCurrentItem(viewpagerIndex);
    }

    private CharSequence nowtime() {
        if (seconds < 10) {
            return (minutes + ":0" + seconds);
        } else {
            return (minutes + ":" + seconds);
        }

    }

    @SuppressLint("WrongConstant")
    public void initData() {
        arrayList = examDao.getAllTopic(0);// 查询所有题目

        LayoutInflater inflter = LayoutInflater.from(this);
        StringBuffer questionId = new StringBuffer();
        viewpagelist = new ArrayList<View>();
        for (int i = 0; i < arrayList.size(); i++) {
            Question q = arrayList.get(i);
            // arrayList.get(i)    应该改成    Question q = arrayList.get(i);  你那样写有效率问题
            if (i == arrayList.size() - 1) {
                questionId.append(q.getQuestion_id());
            } else {
                questionId.append(q.getQuestion_id() + "#");
            }

            View view = inflter.inflate(R.layout.activity_onlinetest_viewpager, null);
            onlinetest_show_question = (TextView) view.findViewById(R.id.onlinetest_show_question);
            onlinetest_show_question.setText(q.getLabel() + q.getQuestion());
            /**
             * 获取图片
             */
            onlinetest_imageview = (ImageView) view.findViewById(R.id.onlinetest_imageview);

            if (null != q.getBlob()) {
                // 0意思是可见的
                onlinetest_imageview.setVisibility(0);
                // 获取图片
                Bitmap bitmap = BitmapFactory.decodeByteArray(q
                        .getBlob(), 0, q.getBlob().length);
                onlinetest_imageview.setImageBitmap(bitmap);

            } else {
                onlinetest_imageview.setVisibility(8);
                // 常量值为4,意思是不可见的
                // 常量值为8,意思是不可见的,而且不占用布局空间
            }
            onlinetest_radioA = view.findViewById(R.id.onlinetest_radioA);
            /**
             * 获得a选项内容
             */
            onlinetest_radioA.setText(q.getOptionA());

            onlinetest_radioB = view.findViewById(R.id.onlinetest_radioB);
            /**
             * 获得b选项内容
             */
            onlinetest_radioB.setText(q.getOptionB());

            onlinetest_radioC = view.findViewById(R.id.onlinetest_radioC);

            /**
             * 获得c选项内容
             * 为什么C,D会有判断了,因为有的题目是判断题,判断题没有C,D选择  所以判断一下
             * 没有内容不要显示C,D选项
             */
            if ("null".equals(q.getOptionC())) {
                onlinetest_radioC.setVisibility(View.GONE);
            } else {
                onlinetest_radioC.setText(q.getOptionC());
                onlinetest_radioC.setVisibility(0);
            }
            onlinetest_radioD = view.findViewById(R.id.onlinetest_radioD);

            /**
             * 获得d选项内容
             */
            if ("null".equals(q.getOptionD())) {
                onlinetest_radioD.setVisibility(View.GONE);
            } else {
                onlinetest_radioD.setText(q.getOptionD());
                onlinetest_radioD.setVisibility(0);
            }
            if (q.getOption_type() == 1) {

                if (q.getUser_Answer() == 1) {
                    onlinetest_radioA.setChecked(true);
                } else if (q.getUser_Answer() == 2) {
                    onlinetest_radioB.setChecked(true);
                } else if (q.getUser_Answer() == 3) {
                    onlinetest_radioC.setChecked(true);
                } else {
                    onlinetest_radioD.setChecked(true);
                }

                onlinetest_radioA.setEnabled(false);
                onlinetest_radioB.setEnabled(false);
                onlinetest_radioC.setEnabled(false);
                onlinetest_radioD.setEnabled(false);
                viewpagerIndex += 1;


            }
            onlinetest_radioGroup = view.findViewById(R.id.onlinetest_radioGroup);
            onlinetest_radioGroup.setOnCheckedChangeListener(this);
            viewpagelist.add(view);

        }
    }


    //    内部类  viewpager适配器   即做完题左右滑动切换下一道上一道
    class myadapter extends PagerAdapter {

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return viewpagelist.size();
        }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {
            // TODO Auto-generated method stub
            return arg0 == arg1;
        }

        @Override
        public Object instantiateItem(View container, int position) {
            ((ViewPager) container).addView(viewpagelist.get(position));
            return viewpagelist.get(position);
        }

        @Override
        public void destroyItem(View container, int position, Object object) {
            ((ViewPager) container).removeView(viewpagelist.get(position));
        }

    }

    public void onPageScrollStateChanged(int arg0) {
        // TODO Auto-generated method stub

    }

    public void onPageScrolled(int arg0, float arg1, int arg2) {
        // TODO Auto-generated method stub

    }

    public void onPageSelected(int v) {

    }

    @SuppressLint("WrongConstant")
    public void onClick(View v) {
//        交卷的点击事件
        switch (v.getId()) {
            case R.id.activity_onlinetest_their_papers:
                Toast.makeText(OnlinetestActivity.this, "得分" + scoreCount + "\r\n对题" + rightCount
                        + "\r\n错题" + errorCount, Toast.LENGTH_SHORT).show();
                AlertDialog.Builder ad = new AlertDialog.Builder(OnlinetestActivity.this);

                ad.setTitle("结束考试?");
                ad.setMessage("考试还没结束,是否交卷?\r\n再检查一下看还有未做题吧");
                ad.setPositiveButton("是", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int i) {
//                        点击是结束当前Activity
                        finish();

                    }
                });
                ad.setNegativeButton("接着考试", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int i) {
//                        让对话框从屏幕上消失
                        dialog.dismiss();

                    }
                });
//                创建对话框
                ad.create();
//                让用户必须选择对话框,解决弹出对话框点击空白对话框消失的问题
                ad.setCancelable(false);
//                显示对话框
                ad.show();
//得分,答错多少题 答对多少题
                int score = 0;
                int answerCount = 0;
                int error = 0;
                int size = arrayList.size();
                for (int i = 0; i < size; i++) {
                    Question q = arrayList.get(i);
                    if (q.getOption_type() == 1) {
                        answerCount += 1;
                        if (q.getAnswer() == q.getUser_Answer()) {
                            score += 10;
                        } else {
                            error += 1;
                        }
                    }
                }
                break;
        }

    }

    @SuppressLint("WrongConstant")
    public void onCheckedChanged(RadioGroup arg0, int checkid) {
        boolean isRigth = false;
        boolean isOnChangge = false;
        switch (checkid) {

//            ABCD四个选项,判断你选择的答案对不对
            case R.id.onlinetest_radioA:
                isOnChangge = true;
//                选择之后禁止选择选项的点击
                noClick();
//                  清除选中状态
                onlinetest_radioGroup.clearCheck();
                //  判断答案是否正确
                answer = 1;
                if (arrayList.get(viewpager.getCurrentItem()).getAnswer() == answer) {
                    isRigth = true;
                }
//                自动滑到下一页
                viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);
                break;

            case R.id.onlinetest_radioB:
                isOnChangge = true;
                noClick();
                onlinetest_radioGroup.clearCheck();

                answer = 2;
                if (arrayList.get(viewpager.getCurrentItem()).getAnswer() == answer) {
                    isRigth = true;
                }
                viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);
                break;
            case R.id.onlinetest_radioC:
                isOnChangge = true;
                noClick();
                onlinetest_radioGroup.clearCheck();

                answer = 3;
                if (arrayList.get(viewpager.getCurrentItem()).getAnswer() == answer) {
                    isRigth = true;
                }
                viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);
                break;
            case R.id.onlinetest_radioD:
                isOnChangge = true;
                noClick();//1
                onlinetest_radioGroup.clearCheck();//2      1和2放在前面才有效果

                answer = 4;
                if (arrayList.get(viewpager.getCurrentItem()).getAnswer() == answer) {
                    isRigth = true;
                }
                viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);
                break;
        }
        if (isRigth) {
//            分数一道题十分
            scoreCount += 1;
//            对的题数
            rightCount += 1;
        } else {
            if (isOnChangge) {
//                错题数累加
                errorCount += 1;
//                Toast.makeText 测试同的
//                Toast.makeText(OnlinetestActivity.this, "错,答案"+arrayList.get(viewpager.getCurrentItem()-1).getAnswer(), Toast.LENGTH_SHORT).show();
//               ContentValues 是名值对 不是键值对,对我没打错 可能你妹听过名值对,这里建议去百度一下,说不清
                ContentValues values = new ContentValues();
                values.put("error_type", 1);
//                把错题加入数据库
                examDao.updateQuestion(values, "question_id= ?",
                        new String[]{arrayList.get(viewpager.getCurrentItem() - 1).getQuestion_id() + ""});
//                arrayList.get(viewpager.getCurrentItem() - 1).setError_type(1);
            }

            //      选择完题目判断错题个数  判断如果错了十题就停止考试
//            if (errorCount == 10) {
//                AlertDialog.Builder ad = new AlertDialog.Builder(OnlinetestActivity.this);
//
//                ad.setTitle("模拟考试已结束");
//                ad.setMessage("模拟考试结束,因为你已答错十题");
//
//                ad.setPositiveButton("离开考试", new DialogInterface.OnClickListener() {
//
//                    @Override
//                    public void onClick(DialogInterface dialog, int i) {
//                        Intent intent = new Intent(OnlinetestActivity.this, MainActivity.class);
//                        startActivity(intent);
////                    销毁掉当前Activity
//                        finish();
//                    }
//                });
//
////                创建对话框
//                ad.create();
////            解决弹出对话框点击空白和返回键消失的问题
//                ad.setCancelable(false);
////                显示对话框
//                ad.show();
//                return;
//
//            }
        }
//        更新
        if (isOnChangge) {
            ContentValues values = new ContentValues();
//            这个
            values.put("option_type", 1);
//        记住之前做了的题你选择的答案
            values.put("USER_ANSWER", answer);
            //LIST 下标示重0开始的 , 应该要减一
            arrayList.get(viewpager.getCurrentItem() - 1).setOption_type(1);
        }


    }

    //时间显示
    public void onChronometerTick(Chronometer moni_chronometer) {

        // TODO Auto-generated method stub
        seconds--;
        if (seconds == -1) {
            minutes--;
            seconds = 59;
        }
        if (minutes == 0 && seconds == 00) {
            moni_chronometer.stop();
//            因为一些问题 在倒计时结束时 强制让他变成0:00
//            可以把这行代码注释掉跑下看看
            moni_chronometer.setText("0:00");

            AlertDialog.Builder ad = new AlertDialog.Builder(OnlinetestActivity.this);

            ad.setTitle("结束已考试");
            ad.setMessage("考试时间到停止作答");
            ad.setPositiveButton("交卷", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int i) {
                    Intent intent = new Intent(OnlinetestActivity.this, MainActivity.class);
                    startActivity(intent);
//                    销毁掉当前Activity
                    finish();
                }
            });
//                创建对话框
            ad.create();
            ad.setCancelable(false);
//                显示对话框
            ad.show();


        } else {
            moni_chronometer.setTextColor(Color.RED);
            moni_chronometer.setText(nowtime());
        }


    }

    /**
     * 禁止点击的方法
     */
    public void noClick() {
        initRadioButton();
        onlinetest_radioA.setEnabled(false);
        onlinetest_radioB.setEnabled(false);
        onlinetest_radioC.setEnabled(false);
        onlinetest_radioD.setEnabled(false);
    }

    /**
     * 初始化radiobutton  这个方法决定点击有没有用
     */
    public void initRadioButton() {
        onlinetest_radioA = viewpagelist.get(viewpager.getCurrentItem()).findViewById(R.id.onlinetest_radioA);
        onlinetest_radioB = viewpagelist.get(viewpager.getCurrentItem()).findViewById(R.id.onlinetest_radioB);
        onlinetest_radioC = viewpagelist.get(viewpager.getCurrentItem()).findViewById(R.id.onlinetest_radioC);
        onlinetest_radioD = viewpagelist.get(viewpager.getCurrentItem()).findViewById(R.id.onlinetest_radioD);
    }


    //    监听手机自带的按键
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
//        如果点击的返回键
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            AlertDialog.Builder ad = new AlertDialog.Builder(OnlinetestActivity.this);

            ad.setTitle("结束考试?");
            ad.setMessage("考试还没结束,是否交卷?\r\n再检查一下看还有未做题吧");
            ad.setPositiveButton("是", new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int i) {
//                        点击是结束当前Activity
                    finish();

                }
            });
            ad.setNegativeButton("接着考试", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int i) {
//                        让对话框从屏幕上消失
                    dialog.dismiss();

                }
            });
//                创建对话框
            ad.create();
//                让用户必须选择对话框,解决弹出对话框点击空白对话框消失的问题
            ad.setCancelable(false);
//                显示对话框
            ad.show();
        }
        return false;

    }

}

    复制上面代码修改一些地方是可以跑出一个功能模块的

    希望对大家有帮助,写的不好的地方还请多多指教

   对了贴上源码下载地址在线考试系统下载地址

猜你喜欢

转载自blog.csdn.net/qq_34783437/article/details/80771057
今日推荐