1、搭建一个简单的服务器,将考试题目和答案以XML格式存放在服务器上(5题,每题20分);
2、应用程序的启动界面有一个按钮,点击按钮开始考试,同时发送HTTP请求,对XML格式数据进行解析,显示出来;
3、用户根据题目答题;
4、完成全部题目后,根据答题情况给用户打分,如果小于80分(每小题20分),判定为考试不合格,用户可以选择重新考试;
界面跳转一般是这样的:(示例是从FirstActivity跳转到SecondActivity)
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
如何传递数据?使用putExtra()函数
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("name",xxx);
startActivity(intent);
接收数据:
// 首先获取到意图对象
Intent intent = getIntent();
// 获取到传递过来的姓名
String xxx = intent.getStringExtra("name");
还可以传递图片等复杂数据的,在这里先不作讨论。
可见(visible)
XML文件:android:visibility=“visible”
Java代码:view.setVisibility(View.VISIBLE);
不可见(invisible)
XML文件:android:visibility=“invisible”
Java代码:view.setVisibility(View.INVISIBLE);
隐藏(GONE)
XML文件:android:visibility=“gone”
Java代码:view.setVisibility(View.GONE);
隐藏和不可见的区别:
不可见会让view看不见,但是实际还在那里,隐藏会让view整个移除,实际不在那里(不占位)
另:隐藏和不可见设置都会使控件的点击事件失效,也就是无法点击
如果不使用handler就直接在子线程中setText,则会报错,因为android中相关的view和控件不是线程安全的,我们必须单独做处理。
(下面这段代码是放在子线程的run函数下面的)
// 在子线程中实例化Handler同样是可以的,只要在构造函数的参数中传入主线程的Looper即可
Handler handler = new Handler(Looper.getMainLooper());
// 通过Handler的post Runnable到UI线程的MessageQueue中去即可
handler.post(new Runnable() {
@Override
public void run() {
// 在MessageQueue出队该Runnable时进行的操作
int quesCount = 0;
for(Question aQues:questions) {
ques_title[quesCount].setText(aQues.getTitle());
quesRadioButton[quesCount].setText(aQues.getChoiceA());
quesRadioButton[quesCount + 5].setText(aQues.getChoiceB());
if(!aQues.getChoiceC().equals("")){
quesRadioButton[quesCount + 10].setText(aQues.getChoiceC());
quesRadioButton[quesCount + 15].setText(aQues.getChoiceD());
}
ques_group[quesCount].setVisibility(View.VISIBLE);
quesCount++;
}
}
});
关于Handler的用法可以参考:Android基础夯实–你了解Handler有多少?
这里是参考了安卓开发之解析XML和JSON格式数据
感觉网络这一块他讲得很清楚了,这里就不多赘述。
不过他是用的apache作服务端,我因为本身就有javaEE开发经验,所以是直接使用了eclipse用tomcat了,这样也可以的哈。
然后解释一下为什么要开一个新线程:
在Android4.0以后,在主线程中的HTTP请求,运行时都会报错 ANRs (“Application Not Responding”),”应用没有响应“。
所以当进行网络请求的时候 还是需要开辟一个子线程,然后等到数据返回成功后再刷新UI。
单选的话就是用RadioGroup和RadioButton,每个RadioGroup下有多个RadioButton,但只有一个能够被选中。
获取用户的值方法1:使用setOnCheckedChangeListener监听
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int id = group.getCheckedRadioButtonId();
RadioButton radioBtn = MainActivity.this.findViewById(id);
String text = radioBtn.getText().toString();
}
});
获取用户值方法2:对radiogroup中组件进行循环,依次判断组件是否isChecked,从而找到选中的组件
//该RadioGroup下有几个RadioButon
int count = radioGroup.getChildCount();
//遍历RadioButon
for(int j = 0 ;j < count;j++){
RadioButton rb = (RadioButton)radioGroup.getChildAt(j);
if(rb.isChecked()){
String text = rb.getText().toString();
//userAnswer[i] = text.split("\\.")[0];//这里是进行了分割然后存入了答案数组
}
}
打开app: 点击开始考试后:
提交试卷:<80不合格,>=80合格
<questions>
<question>
<id>1id>
<title>驾驶机动车在道路上违反道路交通安全法的行为,属于什么行为?title>
<choiceA>违章行为choiceA>
<choiceB>违法行为choiceB>
<choiceC>过失行为choiceC>
<choiceD>违规行为choiceD>
<answer>Banswer>
question>
<question>
<id>2id>
<title>机动车驾驶人违法驾驶造成重大交通事故构成犯罪的,依法追究什么责任?title>
<choiceA>刑事责任choiceA>
<choiceB>民事责任choiceB>
<choiceC>经济责任choiceC>
<choiceD>直接责任choiceD>
<answer>Aanswer>
question>
<question>
<id>3id>
<title>机动车驾驶人造成事故后逃逸构成犯罪的,吊销驾驶证且多长时间不得重新取得驾驶证?title>
<choiceA>5年内choiceA>
<choiceB>10年内choiceB>
<choiceC>终生choiceC>
<choiceD>20年内choiceD>
<answer>Canswer>
question>
<question>
<id>4id>
<title>驾驶机动车违反道路交通安全法律法规发生交通事故属于交通违章行为。title>
<choiceA>正确choiceA>
<choiceB>错误choiceB>
<answer>Banswer>
question>
<question>
<id>5id>
<title>驾驶机动车在道路上违反道路通行规定应当接受相应的处罚。title>
<choiceA>正确choiceA>
<choiceB>错误choiceB>
<answer>Aanswer>
question>
questions>
在app下的build.gradle文件中:
dependencies{
implementation 'com.squareup.okhttp3:okhttp:3.13.1'
}
如果添加依赖出现问题,则参考解决无法添加okhttp依赖的问题(Could not resolve com.sqaureup.okhttp3:okhttp:3.x.x)
主要就是一个按钮和一个ScrollView
ScrollView控件可以以滚动的形式查看屏幕外部分的内容
ScrollView只能包含一个子视图或视图组,在实际项目中,通常包含的是一个垂直的LinearLayout
ScrollView是一个滚动视图的容器,对于一些自带了滚动效果的控件必须ListView,是无法和它一起被混合使用的
还有一点就是ScrollView只能有一个孩子,也就是说直接把很多个RadioGroup放在它下面是不行的,一定要先在多个RadioGroup外面套一个比如LinearLayout。
<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=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/send_request"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始考试"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/ques_title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="18dp"
android:layout_marginTop="20dp"/>
<RadioGroup
android:id="@+id/ques_choices1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible">
<RadioButton
android:id="@+id/choiceA1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"/>
<RadioButton
android:id="@+id/choiceB1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceC1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceD1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
RadioGroup>
<TextView
android:id="@+id/ques_title2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="18dp"
android:layout_marginTop="20dp"/>
<RadioGroup
android:id="@+id/ques_choices2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible">
<RadioButton
android:id="@+id/choiceA2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceB2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceC2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceD2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
RadioGroup>
<TextView
android:id="@+id/ques_title3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="18dp"
android:layout_marginTop="20dp"/>
<RadioGroup
android:id="@+id/ques_choices3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible">
<RadioButton
android:id="@+id/choiceA3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceB3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceC3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceD3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
RadioGroup>
<TextView
android:id="@+id/ques_title4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="18dp"
android:layout_marginTop="20dp"/>
<RadioGroup
android:id="@+id/ques_choices4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible">
<RadioButton
android:id="@+id/choiceA4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceB4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
RadioGroup>
<TextView
android:id="@+id/ques_title5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textSize="18dp"
android:layout_marginTop="20dp"/>
<RadioGroup
android:id="@+id/ques_choices5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible">
<RadioButton
android:id="@+id/choiceA5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
<RadioButton
android:id="@+id/choiceB5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp" />
RadioGroup>
LinearLayout>
ScrollView>
LinearLayout>
android.support.constraint.ConstraintLayout>
package com.example.yogi.networktest;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.StringReader;
import java.util.ArrayList;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button sendReq;
private ArrayList<Question> questions = new ArrayList<>();
private RadioGroup ques_group[] = new RadioGroup[5];
private RadioButton quesRadioButton[] = new RadioButton[18];
private String userAnswer[] = new String[50];
private TextView ques_title[] = new TextView[5];
//private int userAnsLoop = 0;//用于设置用户答案时的循环
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
sendReq = findViewById(R.id.send_request);
sendReq.setOnClickListener(this);
ques_group[0] = findViewById(R.id.ques_choices1);
ques_group[1] = findViewById(R.id.ques_choices2);
ques_group[2] = findViewById(R.id.ques_choices3);
ques_group[3] = findViewById(R.id.ques_choices4);
ques_group[4] = findViewById(R.id.ques_choices5);
ques_title[0] = findViewById(R.id.ques_title1);
ques_title[1] = findViewById(R.id.ques_title2);
ques_title[2] = findViewById(R.id.ques_title3);
ques_title[3] = findViewById(R.id.ques_title4);
ques_title[4] = findViewById(R.id.ques_title5);
quesRadioButton[0] = findViewById(R.id.choiceA1);
quesRadioButton[1] = findViewById(R.id.choiceA2);
quesRadioButton[2] = findViewById(R.id.choiceA3);
quesRadioButton[3] = findViewById(R.id.choiceA4);
quesRadioButton[4] = findViewById(R.id.choiceA5);
quesRadioButton[5] = findViewById(R.id.choiceB1);
quesRadioButton[6] = findViewById(R.id.choiceB2);
quesRadioButton[7] = findViewById(R.id.choiceB3);
quesRadioButton[8] = findViewById(R.id.choiceB4);
quesRadioButton[9] = findViewById(R.id.choiceB5);
quesRadioButton[10] = findViewById(R.id.choiceC1);
quesRadioButton[11] = findViewById(R.id.choiceC2);
quesRadioButton[12] = findViewById(R.id.choiceC3);
quesRadioButton[15] = findViewById(R.id.choiceD1);
quesRadioButton[16] = findViewById(R.id.choiceD2);
quesRadioButton[17] = findViewById(R.id.choiceD3);
for(int i = 0;i < quesRadioButton.length;i++){
if(i != 13 && i != 14)
quesRadioButton[i].setOnClickListener(this);
}
/*
for(userAnsLoop = 0;userAnsLoop < ques_group.length;userAnsLoop++){
ques_group[userAnsLoop].setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int id = group.getCheckedRadioButtonId();
RadioButton radioBtn = MainActivity.this.findViewById(id);
String text = radioBtn.getText().toString();
userAnswer[userAnsLoop] = text.split("\\.")[0];
Log.d("MainActivity", "userAnsLoop: "+userAnsLoop+"值:"+userAnswer[userAnsLoop]);
}
});
}
*/
}
public void onClick(View v){
if(v.getId() == R.id.send_request){
if(sendReq.getText().toString().equals("开始考试")){
//发送http请求并解析、显示题目
sendRequestWithOkHttp();
sendReq.setText("提交试卷");
}else if(sendReq.getText().toString().equals("提交试卷")){
//获得每一题的答案
for(int i = 0;i < ques_group.length;i++){
//该RadioGroup下有几个RadioButon
int count = ques_group[i].getChildCount();
//遍历RadioButon,如果被选中则存入答案数组
for(int j = 0 ;j < count;j++){
RadioButton rb = (RadioButton)ques_group[i].getChildAt(j);
if(rb.isChecked()){
String text = rb.getText().toString();
userAnswer[i] = text.split("\\.")[0];
Log.d("MainActivity", "序号: "+i+" 值:"+userAnswer[i]);
}
}
}
getScoresAndSkip();
}
}
}
private void getScoresAndSkip() {
int score = 0;
int i = 0;
for(Question ques:questions){
if(ques.getAnswer().equals(userAnswer[i])){
score+=20;
}
i++;
}
Intent intent = new Intent(MainActivity.this,ResultActivity.class);
intent.putExtra("score",String.valueOf(score));
startActivity(intent);
}
//有许多出色的网络通信库都可以替代原生的HttpURLConnection,其中OkHttp是比较出色的一个
private void sendRequestWithOkHttp() {
//开启线程来发起网络请求(使用get方法提交请求)
/*
如果是Post方法:
先构建一个RequestBody对象来存放待提交的数据
RequestBody requestBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.builder();
然后在Request.Builder构造器调用post()方法将RequestBody对象传入
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(requestBody)
.build();
其他相同
*/
new Thread(new Runnable () {
@Override
public void run() {
try {
//创建OkHttpClient实例
OkHttpClient client = new OkHttpClient();
//创建Request对象
Request request = new Request.Builder()
//.url("http://localhost:8080/AndroidOnlineExamQues/question.xml") //通过url()方法设定目标的网络地址
.url("http://10.0.2.2:8080/AndroidOnlineExamQues/question.xml")//注意这里不能像上面一样用localhost,因为虚拟机会以为是自己的localhost而不是电脑的
.build();
//创建一个Call对象,并调用它的execute()方法来发送请求和接受服务器返回的数据
Response response = client.newCall(request).execute();
//使用Response对象接受服务器返回的数据 然后使用response.body().string()方法获得具体的内容
String responseData = response.body().string();
parseXMLWithPull(responseData);
} catch(Exception e) {
e.printStackTrace();
}
// 在子线程中实例化Handler同样是可以的,只要在构造函数的参数中传入主线程的Looper即可
Handler handler = new Handler(Looper.getMainLooper());
// 通过Handler的post Runnable到UI线程的MessageQueue中去即可
handler.post(new Runnable() {
@Override
public void run() {
// 在MessageQueue出队该Runnable时进行的操作
int quesCount = 0;
for(Question aQues:questions) {
ques_title[quesCount].setText(aQues.getTitle());
quesRadioButton[quesCount].setText(aQues.getChoiceA());
quesRadioButton[quesCount + 5].setText(aQues.getChoiceB());
if(!aQues.getChoiceC().equals("")){
quesRadioButton[quesCount + 10].setText(aQues.getChoiceC());
quesRadioButton[quesCount + 15].setText(aQues.getChoiceD());
}
ques_group[quesCount].setVisibility(View.VISIBLE);
quesCount++;
}
}
});
}
}).start();
}
private void parseXMLWithPull(String xmlData) {
try {
//获得一个XmlPullParserFactory实例
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//得到XmlPullParser对象
XmlPullParser xmlPullParser = factory.newPullParser();
//调用xmlPullParser的setInput方法将服务器返回的XML数据传入开始解析
xmlPullParser.setInput(new StringReader(xmlData));
//获得当前的解析事件
int eventType = xmlPullParser.getEventType();
String title="";
String choiceA="";
String choiceB="";
String choiceC="";
String choiceD="";
String ans="";
String quesId="";
int quesCount = 0;
while (eventType != XmlPullParser.END_DOCUMENT) {
//注意这个不能写在这里,不然每次都初始化为0,每道题都是1不会有2、3、4、5
//int quesCount = 0;
//getName()方法获得当前节点的名字
String nodeName = xmlPullParser.getName();
//如果发现节点名等于title等等,就调用nextText()方法来获取节点内具体的内容
switch(eventType) {
//开始解析节点,START_TAG和END_TAG分别表示开始标签和结束标签,例如为开始标签,而 为结束标签
case XmlPullParser.START_TAG: {
if ("title".equals(nodeName)) {
quesCount++;
title = String.valueOf(quesCount)+"."+xmlPullParser.nextText();
//aNewQues.setTitle(xmlPullParser.nextText());
//Log.d("MainActivity", "title: "+xmlPullParser.nextText());
} else if ("choiceA".equals(nodeName)) {
choiceA = "A." + xmlPullParser.nextText();
//aNewQues.setChoiceA(xmlPullParser.nextText());
} else if ("choiceB".equals(nodeName)) {
choiceB = "B." + xmlPullParser.nextText();
//aNewQues.setChoiceB(xmlPullParser.nextText());
}else if ("choiceC".equals(nodeName)) {
choiceC = "C." + xmlPullParser.nextText();
//aNewQues.setChoiceC(xmlPullParser.nextText());
}else if ("choiceD".equals(nodeName)) {
choiceD = "D." + xmlPullParser.nextText();
//aNewQues.setChoiceD(xmlPullParser.nextText());
}else if ("answer".equals(nodeName)) {
ans = xmlPullParser.nextText();
//aNewQues.setAnswer(xmlPullParser.nextText());
}else if ("id".equals(nodeName)) {
quesId = xmlPullParser.nextText();
//aNewQues.setId(xmlPullParser.nextText());
}
break;
}
//完成解析某道题目,就把题目放到list里
case XmlPullParser.END_TAG: {
if("question".equals(nodeName)) {
Question aNewQues = new Question(quesId,title,ans,choiceA,choiceB,choiceC,choiceD);
choiceC = "";
choiceD = "";
questions.add(aNewQues);
}
break;
}
default:
break;
}
eventType = xmlPullParser.next();
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yogi.networktest">
……
<uses-permission android:name="android.permission.INTERNET" />
manifest>
注意我们接下来要建新的活动,如果是右键新建Activity,那么会自动帮我们在这里注册,如果新建的是java则需要自己注册一下。
package com.example.yogi.networktest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class ResultActivity extends AppCompatActivity implements View.OnClickListener{
TextView score,isPass;
Button retest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
score = findViewById(R.id.score);
isPass = findViewById(R.id.isPass);
Intent intent = getIntent();
String s = intent.getStringExtra("score");
if(s != null){
score.setText("您的分数为:"+s);
int sc = Integer.valueOf(s);
if(sc < 80){
isPass.setText("不及格,您可以点击下方按钮重新考试。");
retest = findViewById(R.id.retest);
retest.setOnClickListener(this);
retest.setVisibility(View.VISIBLE);
}else{
isPass.setText("恭喜,通过考试。");
}
}
}
@Override
public void onClick(View v){
Intent intent = new Intent(ResultActivity.this,MainActivity.class);
startActivity(intent);
}
}
<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=".ResultActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp"
android:layout_marginTop="20dp"/>
<TextView
android:id="@+id/isPass"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="21dp"
android:layout_marginVertical="10dp"/>
<Button
android:id="@+id/retest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
android:text="重新考试"/>
LinearLayout>
android.support.constraint.ConstraintLayout>