2017-11-16 40 views
0

私はアンドロイドとスレッド一般的に新しいです。私は現在、UIとは別のスレッド上でレンダリングとロジックが発生するゲームを作っています。 私の問題は、ワーカースレッドから投稿を使用してUIを更新するように見えることです。投稿スレッドを使用して投稿

これは私のmainActivityです:

private GameScene gameScene; 
private Handler uiHandler; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    super.onCreate(savedInstanceState); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); 
    setContentView(R.layout.game); 
    uiHandler = new Handler(Looper.getMainLooper()); 

    gameScene = new GameScene(getApplicationContext(), uiHandler); 
    LinearLayout gameHolder = (LinearLayout)findViewById(R.id.game_view); 
    gameHolder.addView(gameScene); 
    gameScene.resume(); 
} 

これは、実行可能な実装するクラスです:

public abstract class Scene extends SurfaceView implements Runnable { 

    Handler uiHandler; 
    Thread thread = null; 
    public Scene(Context context, Handler uiHandler) { 
     super(context); 
     this.uiHandler = uiHandler; 
    } 

    @Override 
    public void run() { 
     uiHandler.post(() -> { 
      TextView textView = findViewById(R.id.fps_counter); 
      textView.setText("hello"); 
     }); 
    } 

    public void resume() { 
     thread = new Thread(this); 
     thread.start(); 
    } 

のxml:ポストの内側

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <LinearLayout 
     android:id="@+id/game_view" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:orientation="horizontal" 
     android:visibility="visible"> 

     <TextView 
      android:id="@+id/fps_counter" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:layout_weight="1" 
      android:text="0" 
      android:textColor="@color/colorAccent" 
      android:textSize="24sp" /> 
    </LinearLayout> 

</FrameLayout> 

コードがUIスレッド上で実行する必要があります右?しかし、私はテキストを設定しようとすると、nullオブジェクト参照を取得しています。はい、id fps_counterのテキストが存在します。

+0

public abstract class Scene extends SurfaceView implements Runnable { Handler uiHandler; Thread thread = null; TextView textView; public Scene(Context context, Handler uiHandler, TextView textView) { super(context); this.uiHandler = uiHandler; this.textView = textView; } @Override public void run() { uiHandler.post(() -> { textView.setText("hello"); }); } public void resume() { thread = new Thread(this); thread.start(); } 

は、その後のTextViewの3番目のパラメータでGameSceneを作成します。 – Fustigador

+0

あなたのレイアウトxmlを投稿してください。 – TpoM6oH

+0

どこで呼びますか? @Fustigador – Tagor

答えて

1

SurfaceViewの中にfindViewByIdを呼び出すと、SurfaceView内に特定のIDを持つビューが効果的に探しています。

あなたのビューはR.id.fps_counterですが、IDはアクティビティ内にあるので、アクティビティ内で探す必要があります。

GameSceneクラスを作成してコンストラクタで提供する前に見つけてください。

https://developer.android.com/reference/android/view/View.html#findViewById(int)https://developer.android.com/reference/android/app/Activity.html#findViewById(int)

は後で答えにペティによってコードを使用してくださいを参照してください。

もう1つの解決方法は、あなたのGameSceneにアクティビティを渡すことになり、ハンドラなしで実行できます。

private GameScene gameScene; 
private TextView fpsCounter; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    super.onCreate(savedInstanceState); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); 
    setContentView(R.layout.game); 

    fpsCounter = findViewById(R.id.fps_counter); 
    gameScene = new GameScene(this); 
    LinearLayout gameHolder = (LinearLayout)findViewById(R.id.game_view); 
    gameHolder.addView(gameScene); 
    gameScene.resume(); 
} 

public void setFps(String fps) { 
    fpsCounter.setText(fps); 
} 

public abstract class Scene extends SurfaceView implements Runnable { 

    Thread thread; 
    Activity activity; 

    public Scene(Activity activity) { 
     super(activity); 
     this.activity = activity; 
    } 

    @Override 
    public void run() { 
     activity.runOnUiThread(() -> { 
      activity.setFps("Hello"); 
     }); 
    } 

    public void resume() { 
     thread = new Thread(this); 
     thread.start(); 
    } 

Gamesceneがfps_counter用のTextViewを含んでいないのでさらに良いhere

2

ように、initメソッド内のフレームワークとセット活性が期待コンストラクタを使用するであろう抽象的なシーンとクラス拡張を変更して、テキストビューへの参照を渡すことができます。 UIスレッド上でコードを実行するためにrunOnUiThreadを試してみてください

TextView textView = findViewById(R.id.fps_counter); 
// no need to use getApplicationContext(), you may use this (a reference to "mainActivity") 
gameScene = new GameScene(this, uiHandler, textView); 
+0

ありがとうございます。しかし、私は1つの質問がある、それはまた、ハンドラを使用せずに動作します。私が読んだことから、ハンドラを使用してUIと通信する必要があります。代わりに関与する変数への単純な参照を使用して通信するとどうなりますか? – Tagor

+0

本当に面白いコールバックは常にUIスレッドから呼び出されるはずですから、uiハンドラは本当に必要ありません。何らかの理由でバックグラウンドスレッドから呼び出すと、ゴールデンルールの1つが破損しているため、アプリがクラッシュします(常にUIスレッドからビューをタッチします)。あなたは今働いてうれしいです。 – petey

+0

ありがとう、しかし、私はまだかなり理解していない、シーンのrunメソッドの目的は、そこのすべてがUIスレッドとは異なるスレッドで実行されるということです。実行時にuiHandlerを使用しないでtextView.setText()を呼び出すと、それでもUIスレッドで実行されますか?私は今混乱している@petey – Tagor

関連する問題