質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

1回答

710閲覧

Socketでの接続処理とは別のクラスでデータ送信を行いたい

abcdssh

総合スコア1

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

0クリップ

投稿2022/06/03 07:53

編集2022/06/06 06:44

Socketでの接続処理とは別のクラスでデータ送信を行いたい

私はandroidstudioでアプリ開発を行っている初心者です。

MainActivityでSocketの接続処理を行っておりこの処理は動作が確認できました。MyDialogFragmentクラスでダイアログを表示し、ダイアログのOKボタンを押したときに3つのEditTextの内容をサーバーへ送信したいと考えています。

このような場合MainActivityのSocketの内容をMyDialogFragmentに反映させるにはどうしたらいいのでしょうか?

また、Socket.connect();での接続はできるのですが、切断処理がわかりません。こちらもわかる方がいましたらお願いします。

#MainActivity.java

java

1package to.msn.wings.dialogargs; 2 3import androidx.appcompat.app.AppCompatActivity; 4import androidx.fragment.app.DialogFragment; 5 6import android.content.Intent; 7import android.os.Bundle; 8import android.os.Parcelable; 9import android.widget.Button; 10import android.widget.CompoundButton; 11import android.widget.EditText; 12import android.widget.Toast; 13import android.widget.ToggleButton; 14 15import java.io.IOException; 16import java.io.PrintWriter; 17import java.net.InetSocketAddress; 18import java.net.Socket; 19 20public class MainActivity extends AppCompatActivity { 21 22 @Override 23 24 protected void onCreate(Bundle savedInstanceState) { 25 super.onCreate(savedInstanceState); 26 setContentView(R.layout.activity_main); 27 28 Button btn = findViewById(R.id.button1); 29 ToggleButton toggle = findViewById(R.id.toggleButton); 30 31 btn.setOnClickListener(view -> { 32 EditText txtName1 = findViewById(R.id.editText1); 33 EditText txtName2 = findViewById(R.id.editText2); 34 EditText txtName3 = findViewById(R.id.editText3); 35 36 DialogFragment dialog = new MyDialogFragment(); 37 Bundle args = new Bundle(); 38 args.putString("txtName1", txtName1.getText().toString()); 39 args.putString("txtName2", txtName2.getText().toString()); 40 args.putString("txtName3", txtName3.getText().toString()); 41 dialog.setArguments(args); 42 dialog.show(getSupportFragmentManager(), "dialog_basic"); 43 }); 44 45 toggle.setOnCheckedChangeListener((buttonView, isChecked) ->{ 46 String ip = "10.22.18.109"; 47 int port = 50015; 48 InetSocketAddress address = new InetSocketAddress(ip, port); 49 Socket socket = new Socket(); 50 if (isChecked) { 51 new Thread (() -> { 52 try { 53 socket.connect(address, 3000); 54 MainActivity.this.runOnUiThread(() -> 55 Toast.makeText(MainActivity.this, "接続に成功しました。", Toast.LENGTH_LONG).show()); 56 } catch (Exception e) { 57 MainActivity.this.runOnUiThread(() -> 58 Toast.makeText(MainActivity.this, "接続に失敗しました。", Toast.LENGTH_LONG).show()); 59 } 60 PrintWriter pw = null; 61 try { 62 pw = new PrintWriter(socket.getOutputStream(), true); 63 } catch (IOException e) { 64 e.printStackTrace(); 65 } 66 pw.println("タブレット端末接続開始"); 67 }).start(); 68 } else { 69 // The toggle is disabled 70 try { 71 socket.close(); 72 } catch (IOException e) { 73 e.printStackTrace(); 74 } 75 } 76 }); 77 } 78

#MyDialogFragment.java

java

1package to.msn.wings.dialogargs; 2 3import android.app.AlertDialog; 4import android.app.Dialog; 5import android.os.Bundle; 6import android.content.Intent; 7import androidx.annotation.NonNull; 8import androidx.fragment.app.DialogFragment; 9 10import java.io.IOException; 11import java.io.PrintWriter; 12import java.net.Socket; 13 14 15 16public class MyDialogFragment extends DialogFragment { 17 @NonNull 18// @Override 19 /*組立・仕分けST*/ 20 21 22 public Dialog onCreateDialog(Bundle savedInstanceState) { 23 Bundle args = requireArguments(); 24 String txtName1 = args.getString("txtName1"); 25 String txtName2 = args.getString("txtName2"); 26 String txtName3 = args.getString("txtName3"); 27 28 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 29 30 builder.setTitle(" !!最終確認!!") 31 .setMessage(String.format("X座標 : %30s\n\n" + "Y座標 : %30s\n\n" + "Z座標 : %30s", txtName1, txtName2, txtName3)) 32 .setPositiveButton("OK", (dialog, id) -> { 33 //OKボタンを押したときの動作 34// Socket socket = getIntent().getExtra("txtName"); 35 Socket socket = new Socket(); 36 PrintWriter pw = null; 37 try { 38 pw = new PrintWriter(socket.getOutputStream(), true); 39 pw.println(txtName1); 40 pw.println(txtName2); 41 pw.println(txtName3); 42 } catch (IOException e) { 43 e.printStackTrace(); 44 } 45 }) 46 .setIcon(R.drawable.chuui) 47 .setNegativeButton("キャンセル", null); 48 49 return builder.create(); 50 } 51}

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/06/03 08:10

ダイアログのOKボタンを押した時にも new Socket が書いてありますが、そのまま、メインで行っている接続をダイアログに移動させるのではダメなのでしょうか。
jimbe

2022/06/03 09:19

ご質問にタグ付けされている "Socket.IO" は js のライブラリのことですので、関係ありません。外されたほうが良いように思います。
guest

回答1

0

ベストアンサー

例えば、 Thread で接続した結果として PrintWriter をフィールドにし、 DialogFragment が OK されたら FragmentResultListener 経由で Main で出力というのは如何でしょう。

MainActivity.java

java

1import androidx.appcompat.app.*; 2 3import android.os.*; 4import android.util.Log; 5import android.widget.*; 6 7import java.io.*; 8import java.net.*; 9 10public class MainActivity extends AppCompatActivity { 11 public static final String LOG_TAG = "MainActivity"; 12 private static String CONFIRM_SEND_REQUESTKEY = "confirmSend"; 13 14 private Socket socket; 15 private BufferedReader br; 16 private PrintWriter pw; 17 18 @Override 19 protected void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 23 getSupportFragmentManager().setFragmentResultListener(CONFIRM_SEND_REQUESTKEY, this, (requestKey, result) -> { 24 new Thread (() -> { 25 try { 26 String name1 = result.getString(MyDialogFragment.RESULT_TXTNAME1); 27 String name2 = result.getString(MyDialogFragment.RESULT_TXTNAME2); 28 String name3 = result.getString(MyDialogFragment.RESULT_TXTNAME3); 29 Log.d(LOG_TAG, "send:" + name1); 30 pw.println(name1); 31 String line = br.readLine(); 32 if(!line.endsWith(":OK")) Log.e(LOG_TAG, "Error: "+line); 33 Log.d(LOG_TAG, "send:" + name2); 34 pw.println(name2); 35 line = br.readLine(); 36 if(!line.endsWith(":OK")) Log.e(LOG_TAG, "Error: "+line); 37 Log.d(LOG_TAG, "send:" + name3); 38 pw.println(name3); 39 line = br.readLine(); 40 if(!line.endsWith(":OK")) Log.e(LOG_TAG, "Error: "+line); 41 } catch(IOException e) { 42 e.printStackTrace(); 43 } 44 }).start(); 45 }); 46 47 EditText txtName1 = findViewById(R.id.editText1); 48 EditText txtName2 = findViewById(R.id.editText2); 49 EditText txtName3 = findViewById(R.id.editText3); 50 51 Button btn = findViewById(R.id.button1); 52 btn.setEnabled(false); 53 btn.setOnClickListener(view -> { 54 String name1 = txtName1.getText().toString(); 55 String name2 = txtName2.getText().toString(); 56 String name3 = txtName3.getText().toString(); 57 MyDialogFragment.newInstance(CONFIRM_SEND_REQUESTKEY, name1, name2, name3).show(getSupportFragmentManager(), null); 58 }); 59 60 ToggleButton toggle = findViewById(R.id.toggleButton); 61 toggle.setOnCheckedChangeListener((buttonView, isChecked) -> { 62 String ip = "10.22.18.109"; 63 //String ip = "10.0.2.2"; //エミュレータホスト 64 int port = 50015; 65 InetSocketAddress address = new InetSocketAddress(ip, port); 66 socket = new Socket(); 67 if (isChecked) { 68 Log.d(LOG_TAG, "connect start"); 69 new Thread (() -> { 70 try { 71 socket.connect(address, 3000); 72 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); 73 pw = new PrintWriter(socket.getOutputStream(), true); 74 pw.println("タブレット端末接続開始"); 75 String line = br.readLine(); 76 if(line.endsWith(":OK")) { 77 MainActivity.this.runOnUiThread(() -> { 78 Log.d(LOG_TAG, "接続に成功しました。"); 79 Toast.makeText(MainActivity.this, "接続に成功しました。", Toast.LENGTH_LONG).show(); 80 btn.setEnabled(true); 81 }); 82 } else { 83 throw new IOException(line); 84 } 85 } catch (Exception e) { 86 Log.d(LOG_TAG, "接続に失敗しました。"); 87 MainActivity.this.runOnUiThread(() -> Toast.makeText(MainActivity.this, "接続に失敗しました。", Toast.LENGTH_LONG).show()); 88 e.printStackTrace(); 89 } 90 }).start(); 91 } else { 92 Log.d(LOG_TAG, "disconnect start"); 93 btn.setEnabled(false); 94 try { 95 br.close(); 96 } catch (IOException ignore) {} 97 pw.close(); 98 try { 99 socket.close(); 100 } catch (IOException ignore) {} 101 socket = null; 102 pw = null; 103 br = null; 104 } 105 }); 106 } 107}

MyDialogFragment.java

java

1import android.app.Dialog; 2import android.os.Bundle; 3 4import androidx.annotation.NonNull; 5import androidx.appcompat.app.AlertDialog; 6import androidx.fragment.app.DialogFragment; 7 8public class MyDialogFragment extends DialogFragment { 9 static final String RESULT_TXTNAME1 = "txtName1"; 10 static final String RESULT_TXTNAME2 = "txtName2"; 11 static final String RESULT_TXTNAME3 = "txtName3"; 12 13 private static final String PARAM_REQUESTKEY = "requestKey"; 14 private static final String PARAM_TXTNAME1 = "txtName1"; 15 private static final String PARAM_TXTNAME2 = "txtName2"; 16 private static final String PARAM_TXTNAME3 = "txtName3"; 17 18 static MyDialogFragment newInstance(String requestKey, String name1, String name2, String name3) { 19 MyDialogFragment dialog = new MyDialogFragment(); 20 Bundle args = new Bundle(); 21 args.putString(PARAM_REQUESTKEY, requestKey); 22 args.putString(PARAM_TXTNAME1, name1); 23 args.putString(PARAM_TXTNAME2, name2); 24 args.putString(PARAM_TXTNAME3, name3); 25 dialog.setArguments(args); 26 return dialog; 27 } 28 29 @NonNull 30 public Dialog onCreateDialog(Bundle savedInstanceState) { 31 Bundle args = requireArguments(); 32 String requestKey = args.getString(PARAM_REQUESTKEY); 33 String txtName1 = args.getString(PARAM_TXTNAME1); 34 String txtName2 = args.getString(PARAM_TXTNAME2); 35 String txtName3 = args.getString(PARAM_TXTNAME3); 36 37 return new AlertDialog.Builder(requireActivity()).setTitle("!!最終確認!!") 38 //.setIcon(R.drawable.chuui) 39 .setMessage(String.format("X座標 : %30s\n\n" + "Y座標 : %30s\n\n" + "Z座標 : %30s", txtName1, txtName2, txtName3)).setPositiveButton("OK", (dialog, id) -> { 40 Bundle result = new Bundle(); 41 result.putString(PARAM_TXTNAME1, txtName1); 42 result.putString(PARAM_TXTNAME2, txtName2); 43 result.putString(PARAM_TXTNAME3, txtName3); 44 getParentFragmentManager().setFragmentResult(requestKey, result); 45 }).setNegativeButton("キャンセル", null).create(); 46 } 47}

以下はテストに使用したサーバプログラムです。

java

1import java.io.*; 2import java.net.ServerSocket; 3import java.net.Socket; 4 5public class Server { 6 public static void main(String[] args) throws IOException { 7 try(ServerSocket ss = new ServerSocket(50015);) { 8 System.out.println("start."); 9 try(Socket client = ss.accept(); 10 BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); 11 PrintWriter pw = new PrintWriter(client.getOutputStream(), true);) { 12 for(String line; (line = br.readLine()) != null; ) { 13 System.out.println("[client] " + line); 14 pw.println(line + ":OK"); 15 } 16 } 17 System.out.println("end."); 18 } 19 } 20}

実行操作
トグル ON → X:10, Y:12, Z:14 を入力 → SEND 押下 → ダイアログ OK 押下 → トグル OFF

実行結果(クライアント側ログ)

plain

1D/MainActivity: connect start 2D/MainActivity: 接続に成功しました。 3D/MainActivity: send:10 4D/MainActivity: send:12 5D/MainActivity: send:14 6D/MainActivity: disconnect start

実行結果(サーバ側)

plain

1start. 2[client] タブレット端末接続開始 3[client] 10 4[client] 12 5[client] 14 6end.

投稿2022/06/03 09:18

編集2022/06/06 08:23
jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

abcdssh

2022/06/06 00:57

ありがとうございます。回答のように書き換え実行しましたが、「接続が成功しました」と表示された直後に「接続が失敗しました」となってしまいます。また、btn.setOnClickListenerのボタンを押すとアプリが停止してしまうのですが原因などわかりますでしょうか?
jimbe

2022/06/06 03:56 編集

「成功しました」の後すぐに「失敗しました」と出るとすれば、 PrintWriter で「タブレット端末接続開始」と送信するところで異常が発生したのではないでしょうか。 回答のコードでは「失敗しました」とトーストした場合は e.printStackTrace していますので、 logcat 等に詳細が出力されているはずですので、それらをお調べください。 なお、通信するプログラムですので、当然通信相手 (サーバ) の動作の影響を受けます。通信相手とのやり取りの方法はご提示のコードであっているのでしょうか。 ボタンを押した場合に「停止」という表現をされましても、直接見ていない側としましては何が起きているのかを想像することは困難です。 ボタンを押したら最後、アプリが何の操作も受け付けなくなるのでしょうか。それとも画面に「停止しました」と表示されるのでしょうか。 もし回答のコード通りに書き換えられたとすれば、「失敗しました」と表示された場合はポタンは Disable になっていて押せないはずですが(^^; 可能でしたら、ご質問の編集・追加等で「書き換え実行した」コードをご提示いただけますか。また、通信相手の仕様(プロトコル?)等もあるとこちらでも実験できます。
abcdssh

2022/06/06 06:25 編集

プログラムとしては回答のコードをそのまま使ったので変更はないです。 また停止するといった件につきましては、btn.setOnClickListenerのボタンを押すとDialogが表示される前にアプリが落ちてしまい画面には「停止しています」または「繰り返し停止しています」と表示されます。 サーバとしてはUbuntuを用いておりJAVAではないのですが以下のようになっています --------------------------- #include <stdio.h> #include <ctype.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <signal.h> #include <sys/param.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <sys/wait.h> #define SRV_IP "10.22.18.45" #define PORTNO 50015 int ServerSocket(char* srvIP, int portnum); int AcceptLoop(int s); int SendRecvLoop(int acc); int main(void) { int sockDesctipt; sockDesctipt = ServerSocket(SRV_IP, PORTNO); fprintf(stderr, "ready for accept\n"); AcceptLoop(sockDesctipt); close(sockDesctipt); return 0; } int ServerSocket(char* srvIP, int portnum){ int s; int opt; struct sockaddr_in ssock; /*----- set address -----*/ memset(&ssock, 0, sizeof(ssock)); ssock.sin_family = AF_INET; ssock.sin_addr.s_addr = inet_addr(srvIP); /*----- port number -----*/ ssock.sin_port = htons(portnum); fprintf(stderr, "port = %d \n", ntohs(ssock.sin_port)); /*-----generate of socket-----*/ s = socket(AF_INET, SOCK_STREAM, 0); if(s < 0){ printf("socket erro !!\n"); return -1; } /*----- set of socket option -----*/ opt = 1; if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, (socklen_t)sizeof(int)) != 0){ perror("setsockopt"); close(s); return(-1); } /*----- set address in socket -----*/ if(bind(s, (struct sockaddr *)&ssock, sizeof(ssock)) == -1){ perror("bind"); close(s); return(-1); } /*----- listen -----*/ if(listen(s, SOMAXCONN) == -1){ perror("listen"); close(s); return(-1); } return(s); } int AcceptLoop(int s){ int acc; int len; struct sockaddr_in from; while(1){ len = sizeof(from); /*----- accept -----*/ acc = accept(s, (struct sockaddr *)&from, (socklen_t *)&len); if(acc < 0){ printf("error : accept\n"); return -1; } else{ printf("accept : %s : %d \n", inet_ntoa(from.sin_addr), ntohs(from.sin_port)); } SendRecvLoop(acc); close(acc); acc = 0; } return(0); } int SendRecvLoop(int acc){ int len; char buf[512], *ptr; while(1){ /*----- receive -----*/ len = recv(acc, buf, sizeof(buf), 0); if(len < 0){ return (-1); } buf[len] = '\0'; /*----- return code -----*/ if((ptr = strpbrk(buf, "\r\n")) != NULL){ *ptr = '\0'; } fprintf(stderr, "[client]%s \n", buf); /*----- echo to client -----*/ strcat(buf, ":OK\r\n"); len = strlen(buf); /*----- send -----*/ send(acc, buf, len, 0); } return (0); } ----------------------------------
abcdssh

2022/06/06 06:52 編集

何度もすみません btnを押したときの動作の画像を上に追加しております またlogcatには次のようなエラーが出るといった現状となっています --------------------------- 2022-06-06 15:51:06.958 7646-7646/to.msn.wings.dialogargs E/AndroidRuntime: FATAL EXCEPTION: main Process: to.msn.wings.dialogargs, PID: 7646 java.lang.IllegalStateException: Fragment to.msn.wings.dialogargs.MyDialogFragment must be a public static class to be properly recreated from instance state. at androidx.fragment.app.FragmentTransaction.doAddOp(FragmentTransaction.java:249) at androidx.fragment.app.BackStackRecord.doAddOp(BackStackRecord.java:183) at androidx.fragment.app.FragmentTransaction.add(FragmentTransaction.java:171) at androidx.fragment.app.DialogFragment.show(DialogFragment.java:259) at to.msn.wings.dialogargs.MainActivity.lambda$onCreate$1$MainActivity(MainActivity.java:46) at to.msn.wings.dialogargs.MainActivity$$ExternalSyntheticLambda0.onClick(Unknown Source) at android.view.View.performClick(View.java:5657) at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119) at android.view.View$PerformClick.run(View.java:22314) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:241) at android.app.ActivityThread.main(ActivityThread.java:6217) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) ---------------------------------------------
jimbe

2022/06/06 07:13 編集

有難う御座います。 linux-c の再現は少し時間がかかりますが、調べてみます。 基本的には受信した文字列に ok を付けて返すだけのようですが、文字列が一回で全部 recv 出来る前提の作りなのが気になりますが…。
jimbe

2022/06/06 07:44

すみません、発生している例外は、MyDialogFragment が public で無いということですね。つい Main と同じファイル内に書いてしまいました。 ご質問のオリジナル通り、 MyDailogFrament を MainActivity と別ファイルとして public クラスとしてください。 他にも問題がありましたので、それまた修正出来次第お知らせ致します。
abcdssh

2022/06/06 07:49

すみませんありがとうございます
jimbe

2022/06/06 08:26

ボタンの有効/無効処理を Main スレッドでやっていなかったり、逆にダイアログで OK した後の送信を Main スレッドでやっていたりで怒られていました^^;;; かなり雑な状態になっていますが、一応送信が確認出来ましたので回答コードを修正しました。
abcdssh

2022/06/10 06:55

返信遅くなってすみません。数日空けておりました。 修正後のプログラムで実行したところ送信動作ができることを確認できました!ありがとうございました。今後細かな修正、また実行動作の追加がありましたらまたお世話になるかもしれません。そのときはよろしくお願いします。
jimbe

2022/06/10 08:44

お疲れ様です(^^ 他にも ViewModel を介する方法とかあると思いますので、時間があればこの方法に拘らず他にも探されたら…と思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問