普通にクライアント-サーバではどういう感じになるかということで書いてみました.
すいません, 動くものにしようと書いていますが, 一気に書いた状態でまだ動かしていません.
レイアウトはクライアント側で, 問題表示TextView id=question, 回答欄EditText id=answer, 判定表示TextView id=result, 回答送信Button id=finalAnswer です. ボタンは全問題終了時のクライアント終了も兼ねています.
サーバ側は使っていません.
説明を入れてみましたが, 修正すると書き込みが大きすぎになるようで消さざるをえませんでした. あくまで参考ということでお願いします.
流れを図にしてみました.
java
1public class ServerActivity extends AppCompatActivity {
2 @Override
3 protected void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 //setContentView(R.layout.activity_server);
6 try {
7 new Thread(new Server("0.0.0.0",8080)).start();
8 } catch (IOException e) {
9 e.printStackTrace();
10 }
11 }
12 private class Server implements Runnable {
13 private String host;
14 private int port;
15 Server(String host, int port) throws IOException {
16 this.host = host;
17 this.port = port;
18 }
19 @Override
20 public void run() {
21 Log.d("Server", "アドレス="+host+", ポート="+port);
22 ServerSocket ss = null;
23 try {
24 ss = new ServerSocket();
25 ss.bind(new InetSocketAddress(host, port));
26 while(true) {
27 Log.d("Server.run", "accept()");
28 Socket s = ss.accept();
29 Log.d("Server.run", "s="+s);
30 new Questioner().execute(s);
31 }
32 } catch (IOException e) {
33 Log.e("Server.run", "IOException", e);
34 } finally {
35 if(ss != null) try { ss.close(); } catch (IOException ignore) {}
36 }
37 }
38 }
39 private class Questioner extends AsyncTask<Object, Object, String> {
40 @Override
41 protected String doInBackground(Object... objects) {
42 Socket s = (Socket)objects[0]; //パラメータ1つめは Socket.
43 try {
44 BufferedWriter w = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
45 BufferedReader r = new BufferedReader(new InputStreamReader(s.getInputStream()));
46 Question q;
47 for(int number=1; (q = createQuestion(number)) != null; number++) {
48 Log.d("Questioner.doInBackground", "問題送信 linecount="+q.linecount+", text="+q.text);
49 w.write(q.linecount+"\n");
50 w.write(q.text);
51 w.flush();
52 String result;
53 do {
54 Log.d("Questioner.doInBackground", "回答受信");
55 String answer = r.readLine();
56 Log.d("Questioner.doInBackground", "answer="+answer);
57 if(answer == null) return null;
58 result = answer.equals(q.correctAnswer) ? "OK" : "NG";
59 Log.d("Questioner.doInBackground", "判定送信 result="+result);
60 w.write(result + "\n");
61 w.flush();
62 } while (result.equals("NG"));
63 }
64 Log.d("Questioner.doInBackground", "終了送信");
65 w.write("0\n");
66 w.flush();
67 } catch (IOException e) {
68 Log.e("Questioner.doInBackground", "異常", e);
69 } finally {
70 try { s.close(); } catch(IOException ignore) {}
71 }
72 return null;
73 }
74 private class Question {
75 final int linecount;
76 final String text;
77 final String correctAnswer;
78 Question(int linecount, String text, String correctAnswer) {
79 this.linecount = linecount;
80 this.text = text;
81 this.correctAnswer = correctAnswer;
82 }
83 }
84 private Question createQuestion(int questionNumber) {
85 switch(questionNumber) {
86 case 1: return new Question(3,
87 "2019年1月1日は何曜日?\n1=月曜日, 2=火曜日, 3=水曜日\n4=木曜日, 5=金曜日, 6=土曜日\n",
88 "2");
89 case 2: return new Question(1,
90 "1+2=?\n",
91 "3");
92 }
93 return null;
94 }
95 }
96}
java
1public class ClientActivity extends AppCompatActivity {
2 private TextView questionView;
3 private EditText answerView;
4 private TextView resultView;
5 private Button finalAnswer;
6 @Override
7 protected void onCreate(Bundle savedInstanceState) {
8 super.onCreate(savedInstanceState);
9 setContentView(R.layout.activity_client);
10 questionView = (TextView)findViewById(R.id.question);
11 answerView = (EditText)findViewById(R.id.answer);
12 resultView = (TextView)findViewById(R.id.result);
13 finalAnswer = (Button)findViewById(R.id.finalAnswer);
14 finalAnswer.setOnClickListener(new View.OnClickListener() {
15 @Override
16 public void onClick(View v) {
17 String answer = answerView.getText().toString();
18 if(answer.length() == 0) return;
19 new ResultReceiver().execute(answer);
20 }
21 });
22 manager = new ConnectionManager("10.0.2.2", 8181);
23 new QuestionReceiver().execute();
24 }
25 private ConnectionManager manager;
26 private class ConnectionManager {
27 private String host;
28 private int port;
29 private Socket s;
30 private BufferedWriter w;
31 private BufferedReader r;
32 ConnectionManager(String host, int port) {
33 this.host = host;
34 this.port = port;
35 }
36 void connect() throws IOException {
37 if(s == null) {
38 Log.d("ConnectionManager.connect", "接続");
39 s = new Socket(host, port);
40 try {
41 w = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
42 r = new BufferedReader(new InputStreamReader(s.getInputStream()));
43 Log.d("ConnectionManager.connect", "接続成功");
44 } catch(IOException e) {
45 Log.e("ConnectionManager.connect", "接続失敗", e);
46 try { s.close(); } catch(IOException ignore) {}
47 s = null; w = null; r = null;
48 throw e;
49 }
50 }
51 }
52 BufferedReader getReader() throws IOException { connect(); return r; }
53 BufferedWriter getWriter() throws IOException { connect(); return w; }
54 void disconnect() { if(s == null) try { s.close(); } catch(IOException ignore) {} }
55 }
56 private class QuestionReceiver extends AsyncTask<Void,Void,String> {
57 @Override
58 protected String doInBackground(Void... aVoid) {
59 try {
60 Log.d("QuestionReceiver.doInBackground", "問題受信");
61 BufferedReader r = manager.getReader();
62 int linecount = Integer.parseInt(r.readLine());
63 Log.d("QuestionReceiver.doInBackground", "linecount="+linecount);
64 if(linecount == 0) return null;
65 String text = "";
66 for(int i=0; i<linecount; i++) text += r.readLine() + "\n";
67 Log.d("QuestionReceiver.doInBackground", "text="+text);
68 return text;
69 } catch (IOException e) {
70 Log.e("QuestionReceiver.doInBackground", "問題受信異常", e);
71 e.printStackTrace();
72 }
73 return null;
74 }
75 @Override
76 protected void onPostExecute(String text) {
77 Log.d("QuestionReceiver.onPostExecute", "text="+text);
78 if(text == null) {
79 finalAnswer.setText("終わります");
80 finalAnswer.setOnClickListener(new View.OnClickListener() {
81 @Override
82 public void onClick(View v) {
83 Log.d("QuestionReceiver.onPostExecute", "finalAnswer.OnClick");
84 manager.disconnect();
85 ClientActivity.this.finish();
86 }
87 });
88 return;
89 }
90 Log.d("QuestionReceiver.onPostExecute", "問題表示");
91 questionView.setText(text);
92 answerView.setText("");
93 resultView.setText("");
94 answerView.requestFocus();
95 }
96 }
97 private class ResultReceiver extends AsyncTask<String,Object,String> {
98 @Override
99 protected String doInBackground(String... answers) {
100 String answer = answers[0];
101 try {
102 Log.d("ResultReceiver.doInBackground", "回答送信 answer="+answer);
103 BufferedWriter w = manager.getWriter();
104 w.write(answer + "\n");
105 w.flush();
106 Log.d("ResultReceiver.doInBackground", "判定受信");
107 BufferedReader r = manager.getReader();
108 return r.readLine();
109 } catch(IOException e) {
110 Log.e("ResultReceiver.doInBackground", "異常", e);
111 e.printStackTrace();
112 }
113 return null;
114 }
115 @Override
116 protected void onPostExecute(String result) {
117 Log.d("ResultReceiver.onPostExecute", "判定="+result);
118 if(result == null) return;
119 Log.d("ResultReceiver.onPostExecute", "判定表示");
120 resultView.setText(result);
121 if(result.equalsIgnoreCase("OK")) {
122 Log.d("ResultReceiver.onPostExecute", "次問題");
123 new QuestionReceiver().execute();
124 } else {
125 Log.d("ResultReceiver.onPostExecute", "再回答");
126 answerView.setText("");
127 answerView.requestFocus();
128 }
129 }
130 }
131}
xml(R.layout.activity_client.xml)
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:tools="http://schemas.android.com/tools"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 android:orientation="vertical"
7 tools:context=".ClientActivity">
8 <TextView
9 android:id="@+id/question"
10 android:layout_width="match_parent"
11 android:layout_height="wrap_content"
12 android:textAppearance="@style/TextAppearance.AppCompat.Large"
13 android:text="問題文"/>
14 <EditText
15 android:id="@+id/answer"
16 android:layout_width="match_parent"
17 android:layout_height="wrap_content"
18 android:textAppearance="@style/TextAppearance.AppCompat.Large"
19 android:text="回答欄"/>
20 <TextView
21 android:id="@+id/result"
22 android:layout_width="match_parent"
23 android:layout_height="wrap_content"
24 android:textAppearance="@style/TextAppearance.AppCompat.Large"
25 android:text="結果"/>
26 <Button
27 android:id="@+id/finalAnswer"
28 android:layout_width="wrap_content"
29 android:layout_height="wrap_content"
30 android:text="回答送信"/>
31</LinearLayout>