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

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

ただいまの
回答率

90.84%

  • Java

    12849questions

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

  • Android Studio

    3374questions

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

クラス間の変数の共有

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 262
退会済みユーザー

退会済みユーザー

私はandroidstudioでアプリ開発を行っています。

Macからandroidへソケット通信を用いて下のコードにより獲得することができますがそのコードにあるString line;をこの関数の外で(他クラスで)使えるようにするにはどうしたらいいのでしょうか?

ちなみにこのコードはMainActivityの@Override onCreateの中にあり,String line;を使いたいのは他クラスに書いている@Override onDrawFrameです。

MainActivity.java

public class MainActivity extends Activity {
  private MyGLSurfaceView glView;

 @Override
  protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
    glView=new MyGLSurfaceView(this);
    setContentView(glView);   
  }

   @Override
    public void onResume() {
    //中略
    }
  @Override
    public void onPause() {
  //中略
    }

}

MyGLSurfaceView.java

public class MyGLSurfaceView extends GLSurfaceView {
    private final Context mContext;
    public GLRenderer renderer;
    private static final String TAG = "MyGLSurfaceView";


    public MyGLSurfaceView(Context context) {
        super(context);
        mContext=context;
        setEGLContextClientVersion(2);
        setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        renderer = new GLRenderer(context);
        setRenderer(renderer);
    }
}

GLRenderer.java

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.AsyncTask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;



public class GLRenderer implements GLSurfaceView.Renderer {

    private String line = "0";

    private Object sync = new Object();
    //システム
    private final Context mContext;
    private boolean validProgram=false; //シェーダプログラムが有効
    private RotationSensor myRotationSensor=null; //加速度方位GPSセンサ

    private float aspect;//アスペクト比
    private float viewingangle = 45f; //視野角(画面長手方向に対応する視野角[deg])


    //光源の座標 x,y,z
    private  float[] LightPos={-10f,1.5f,20f,1f};//x,y,z,1

    //変換マトリックス
    private  float[] pMatrix=new float[16]; //プロジェクション変換マトリックス
    private  float[] mMatrix=new float[16]; //モデル変換マトリックス
    private  float[] cMatrix=new float[16]; //カメラビュー変換マトリックス


    private Sphere MySphere=new Sphere(40,20);


    //シェーダのattribute属性の変数に値を設定していないと暴走するのでそのための準備
    private static float[] DummyFloat= new float[1];
    private static final FloatBuffer DummyBuffer=BufferUtil.makeFloatBuffer(DummyFloat);

    GLRenderer(final Context context) {
        mContext = context;
        connect();
    }

    //サーフェイス生成時に呼ばれる
    @Override
    public void onSurfaceCreated(GL10 gl10,EGLConfig eglConfig) {
        //プログラムの生成
        validProgram = GLES.makeProgram();

        //頂点配列の有効化
        GLES20.glEnableVertexAttribArray(GLES.positionHandle);
        GLES20.glEnableVertexAttribArray(GLES.normalHandle);
        GLES20.glEnableVertexAttribArray(GLES.texcoordHandle);

        //デプスバッファの有効化
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

        // カリングの有効化
        GLES20.glEnable(GLES20.GL_CULL_FACE); //裏面を表示しないチェックを行う

        // 裏面を描画しない
        GLES20.glFrontFace(GLES20.GL_CCW); //表面のvertexのindex番号はCCWで登録
        GLES20.glCullFace(GLES20.GL_BACK); //裏面は表示しない

        //光源色の指定 (r, g, b,a)
        GLES20.glUniform4f(GLES.lightAmbientHandle, 0.15f, 0.15f, 0.15f, 1.0f); //周辺光
        GLES20.glUniform4f(GLES.lightDiffuseHandle, 0.5f, 0.5f, 0.5f, 1.0f); //乱反射光
        GLES20.glUniform4f(GLES.lightSpecularHandle, 0.9f, 0.9f, 0.9f, 1.0f); //鏡面反射光

        //背景色の設定
        GLES20.glClearColor(0f, 0f, 0f, 1.0f);

        //テクスチャの有効化
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);

        // 背景とのブレンド方法を設定します。
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);    // 単純なアルファブレンド



    }

    public void setRotationSensor(RotationSensor s) {

        myRotationSensor=s;
    }

    public void connect() {
        new AsyncTask<Void, String, String>() {
            @Override
            protected String doInBackground(Void... voids) {
                try {
                    while (true) {
                        Socket socket = new Socket("アドレス", 4000);
                        BufferedReader reader = new BufferedReader(
                                new InputStreamReader(socket.getInputStream()));

                        String temp = reader.readLine();
                        synchronized (sync) { // 別スレッドでlineを書き換えるので、synchronizedで同期を取る
                            line = temp;
                        }

                        reader.close();
                        socket.close();

                        //return temp;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }


                return null;
            }
        }.execute();
    }

    //画面サイズ変更時に呼ばれる
    @Override
    public void onSurfaceChanged(GL10 gl10,int w,int h) {
        //ビューポート変換
        GLES20.glViewport(0,0,w,h);
        aspect=(float)w/(float)h;
    }

    //毎フレーム描画時に呼ばれる
    @Override
    public void onDrawFrame(GL10 glUnused) {
        if (!validProgram) return;
        //シェーダのattribute属性の変数に値を設定していないと暴走するのでここでセットしておく。この位置でないといけない
        GLES20.glVertexAttribPointer(GLES.positionHandle, 3, GLES20.GL_FLOAT, false, 0, DummyBuffer);
        GLES20.glVertexAttribPointer(GLES.normalHandle, 3, GLES20.GL_FLOAT, false, 0, DummyBuffer);
        GLES20.glVertexAttribPointer(GLES.texcoordHandle, 2, GLES20.GL_FLOAT, false, 0, DummyBuffer);

        GLES.disableTexture();  //テクスチャ機能を無効にする。(デフォルト)
        GLES.enableShading();   //シェーディング機能を有効にする。(デフォルト)

        //画面のクリア
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT |
                GLES20.GL_DEPTH_BUFFER_BIT);

        //プロジェクション変換(射影変換)--------------------------------------
        //透視変換(遠近感を作る)
        //カメラは原点に有り,z軸の負の方向を向いていて,上方向はy軸+方向である。
        GLES.gluPerspective(pMatrix,
                viewingangle,  //Y方向の画角
                aspect, //アスペクト比
                .1f,   //ニアクリップ   z=-.1から
                20.0f);//ファークリップ  Z=-10までの範囲を表示することになる
        GLES.setPMatrix(pMatrix);

        float[] c1Matrix=new float[16]; //カメラ視点変換マトリックス作成用
        float[] c2Matrix=new float[16]; //カメラ視点変換マトリックス作成用


        //カメラビュー変換(視野変換)-----------------------------------
        //portraitで使うアプリを想定
        //カメラ視点が原点になるような変換 カメラを下向き,長手方向奥側を2D画面の上にする
        Matrix.setLookAtM(c1Matrix, 0,//アイポイント、ビューの中心、アップベクトルの観点からのビュー変換を定義します。
                0f,0f,0f,  //カメラの視点 x,y,z
                0.0f, 0.0f, -1.0f, //カメラの焦点
                0.0f, 1.0f, 0.0f);//カメラの上方向  画面長手方向前方

        c2Matrix = myRotationSensor.getRotMatrix();


        Matrix.translateM(c2Matrix,0,3f,0f,0f);

        Matrix.multiplyMM(cMatrix, 0, c1Matrix, 0, c2Matrix, 0); //cMatrix = c1Matrix * c2Matrix

        //カメラビュー変換はこれで終わり。
        GLES.setCMatrix(cMatrix);

        //cMatrixをセットしてから光源位置をセット
        GLES.setLightPosition(LightPos);

        int value = 0;
        synchronized(sync) { // 別スレッドでlineが書き換わるかもしれないので、synchronizedで同期を取る
            value = Integer.parseInt(line);
        }


        //ボール
        Matrix.setIdentityM(mMatrix, 0);
        Matrix.translateM(mMatrix, 0, value, 0f, 0f);
        Matrix.scaleM(mMatrix, 0, 0.3f, 0.3f, 0.3f);
        GLES.updateMatrix(mMatrix);//現在の変換行列をシェーダに指定
        //MySphereの描画本体
        // r, g, b, a, shininess(1以上の値 大きな値ほど鋭くなる)
        MySphere.draw(1.5f, 1.5f, 0f, 1f, 5.f);


        GLES.enableShading(); //シェーディング機能を使う設定に戻す

        GLES.enableTexture();


    }

}

contextを用いずとも、このコードを新しく作ったクラスに書きインスタンスを渡すことで実現可能でしょうか?

「contextの持ち回し」や「クラス間で共有」などと調べても目的にあったものを見つけ出すことができませんでした。

追記

    public void connect() {
        new AsyncTask<Void, String, String>() {
            @Override
            protected String doInBackground(Void... voids) {
                while (true) {

                    Socket socket = null;
                    BufferedReader reader = null;
                    try {
                        socket = new Socket("アドレス", 4000);

                        reader = new BufferedReader(
                                new InputStreamReader(socket.getInputStream()));

                        String temp = reader.readLine();
                        synchronized(sync) { 
                            line = temp;
                        }
                    } catch(Exception e) {
                        e.printStackTrace();
                    } finally {
                        if(reader != null) {
                            try {
                                reader.close();
                            } catch(Exception e) {}
                        }
                        if(socket != null) {
                            try {
                                socket.close();
                            } catch(Exception e) {}
                        }
                    }
                }
                return null;
            }
        }.execute();
    }

connect()修正したがreturn nullでエラーが出てしまう。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2017/12/13 10:43

    すいません!SurfaceViewのコードを書いてなかったらわからないですよね。GLSurfaceViewも別のクラスとして書いています。GLRendererはmasaya_ohashiさんがおっしゃる通りGLSurfaceviewにセットするためのものです。

    キャンセル

  • masaya_ohashi

    2017/12/13 10:47

    えーと、最後にもう一点、このSocket通信で得られる情報はGLRenderer#onDrawFrameで使う目的「のみ」ですか?それとも他のクラスにも情報を渡したいことがありますか?

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2017/12/13 10:49

    なん度もすいません!onDrawFrame以外では使うつもりはないです。

    キャンセル

回答 1

checkベストアンサー

+1

GLRendererでしか使わないのであれば、最初からGLRendererで処理してしまうのがいいでしょう。

動作検証とかはしてないのでこれで動くかどうかわかりませんが、参考にどうぞ。

MainActivity.java

public class MainActivity extends Activity {
    private MyGLSurfaceView glView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        connect();
        super.onCreate(savedInstanceState);
        glView=new MyGLSurfaceView(this);
        setContentView(glView);
    }
    @Override
    public void onResume() {
        //中略
    }
    @Override
    public void onPause() {
      //中略
    }
}

MyGLSurfaceView.java  

public class MyGLSurfaceView extends GLSurfaceView {  
    private final Context mContext;  
    public GLRenderer renderer;  
    private static final String TAG = "MyGLSurfaceView";

    public MyGLSurfaceView(Context context) {  
        super(context);  
        mContext=context;  
        setEGLContextClientVersion(2);  
        setEGLConfigChooser(8, 8, 8, 8, 16, 0);  
        renderer = new GLRenderer(context);  
        setRenderer(renderer);  
    }
}  

  

GLRenderer.java

public class GLRenderer implements GLSurfaceView.Renderer {

    private String line = "0"; // onDrawFrameでエラーを起こさないためにとりあえず0を入れとく
    private Object sync = new Object(); // スレッドセーフのための同期オブジェクト
    private boolean loop = true;

    @Override
    public GLRenderer() {
        // GLRenderer生成時に通信をスタートさせる
        connect();
    }

    public void connect() {
        new AsyncTask<Void, String, String>() {
            @Override
            protected String doInBackground(Void... voids) {
                while (loop) {

                    Socket socket = null;
                    BufferedReader reader = null;
                    try {
                        socket = new Socket("アドレス", 4000);

                        reader = new BufferedReader(
                                new InputStreamReader(socket.getInputStream()));

                        String temp = reader.readLine();
                        synchronized(sync) { // 別スレッドでlineを書き換えるので、synchronizedで同期を取る
                            line = temp;
                        }
                    } catch(Exception e) {
                        e.printStackTrace();
                    } finally {
                        if(reader != null) {
                            try {
                                reader.close();
                            } catch(Exception e) {}
                        }
                        if(socket != null) {
                            try {
                                socket.close();
                            } catch(Exception e) {}
                        }
                    }
                }
                return null;
            }
        }.execute();
    }
    @Override
    public void onSurfaceCreated(GL10 gl10,EGLConfig eglConfig) {
        //中略
    }
    @Override
    public void onSurfaceChanged(GL10 gl10,int w,int h) {
        //中略
    }
    //毎フレーム描画時に呼ばれる
    @Override
    public void onDrawFrame(GL10 glUnused) {
        //ここでlineをintに変換して使いたいです。
        int value = 0;
        synchronized(sync) { // 別スレッドでlineが書き換わるかもしれないので、synchronizedで同期を取る
            value = Integer.parseInt(line);
        }
        // Socket通信ループを終了させる条件
        if(value > 5) {
            loop = false;
        }

    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/13 12:43

    回答ありがとうございます。 GLRenderer()がOverrideできなかったのでonSurfaceCreatedの中にconnect();を書いてみたのですが強制終了してしまいました。OverrideしていないGLRenderer()の中に書いてもダメですよね?

    キャンセル

  • 2017/12/13 13:10

    あ、ごめんなさいよく考えたらコンストラクタに@Overrideなんていらないですね。消してみてください。

    キャンセル

  • 2017/12/13 13:10

    あと、それでも強制終了したらエラーメッセージを見せてください。

    キャンセル

  • 2017/12/13 15:10

    例えばdraw(x、y、z)でx,y,z座標上に描画できる関数があるとしたら、draw(value,0,0);は 
    synchronized(sync) {
    value = Integer.parseInt(line);
    }の中にないとダメでしょうか?

    キャンセル

  • 2017/12/13 15:13

    lineという変数を「使う瞬間」だけ同期が取れていればいいので、valueを使うだけなら外で大丈夫です。

    キャンセル

  • 2017/12/13 15:45

    少し長いですが、現在のGLRenderer.javaのコードを全て載せました。こちらのコードで実行してみると、valueが0のまま更新されていないので球体の位置が変化しませんでした。

    キャンセル

  • 2017/12/13 16:28

    MainActivityのonCreate、GLRendererのコンストラクタ、およびsetRotationSensorの計三箇所でソケット通信を始めてしまっているので、正しい情報が受け取れない状態にあるかもしれません。GLRendererコンストラクタのconnect以外は不要です。

    キャンセル

  • 2017/12/13 16:29

    あと、BufferedReaderからlineを受け取るところにlogを仕込んでみてください。そもそも通信が正しく周期的に行われていればログが逐次出力されるはずです。

    キャンセル

  • 2017/12/13 16:32

    あと、よく見たらconnectメソッドの中身も私が提示したものと異なって、whileがループされずにreturnするような形になっています。このような形に変更した理由はなんですか?

    キャンセル

  • 2017/12/13 16:32

    あ。私のコード、try catchがないからですね。修正します。

    キャンセル

  • 2017/12/13 16:37

    あと、できれば「回答を元に修正したコード」は「前のコードに上書き」するのではなく、「追記」という形で別々に質問文に残してください。でないと後からこの質問を読んだ人がわけがわからなくなります。

    キャンセル

  • 2017/12/13 16:46

    了解しました。 reader.close();とsocket.close();のところでtryとcatchがないというふうにエラーが出るのですがどう書けば良いでしょうか?

    キャンセル

  • 2017/12/13 17:03

    またしてもポカミスしてました。closeもIOExceptionが発生するのでtry catchで囲みます。お使いのJavaがJava8以降ならもっと簡単な書き方があるのですがね…

    キャンセル

  • 2017/12/13 17:06

    なん度もすいません。return null;のところでエラーが出て
    Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
    > Compilation failed; see the compiler error output for details.
    Error:(131, 17) エラー: この文に制御が移ることはありません
    と出ました。

    キャンセル

  • 2017/12/14 13:32

    確かにこのままだと永遠にwhileを抜けないですね…うーん、何かを条件にループを抜けなければいけないのですが、なにかソケット側から終了を検知するための信号を送る予定はありますか?

    キャンセル

  • 2017/12/14 14:28

    全く考えていませんでした、、、例えばvalueの値が5より大きくなった場合に終了するという条件でもいいのでしょうか?

    キャンセル

  • 2017/12/14 15:12

    いいですよ。とりあえずサンプルを書きますね。

    キャンセル

  • 2017/12/14 15:19

    loopというメンバ変数を用意して、ループの条件にしました。valueが5より大きくなったときにloopをfalseにして抜けるようになっています。

    キャンセル

  • 2017/12/14 16:06

    ありがとうございます。回答のように書いたのですがconnect();が起動していないみたいです。masaya_ohashiさんはpublic GLRenderer() {connect();}でけですが、私のコードは
    GLRenderer( Context context) {
       connect();
    mContext = context;
    }となっているのがいけないのでしょうか?

    キャンセル

  • 2017/12/14 16:08

    問題ないはずです。Log.iなどを使ってどこまで処理が来ているか確認しましょう。while(loop)の直後や、reader.readLine()の直前、直後などにログを仕込んでみてください。

    キャンセル

  • 2017/12/14 17:06

    すいません。プロジェクトを新しくしたので<uses-permission android:name="android.permission.INTERNET"/> をManifestに書いていませんでした。
    長い間本当にありがとうございました。

    キャンセル

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

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Java

    12849questions

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

  • Android Studio

    3374questions

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