-1

ユーザーが画面に触れている間にImageViewを移動しようとしています。私はもともとonTouchEventメソッドからwhileループを試しましたが、これは私が必要としたいくつかのバックグラウンドプロセスを停止しました。私は現在、自分のゲームを制御するスレッドを持っています。このスレッドは、MotionViewイベントによって決まる 'movementSpeed'という浮動小数点数に基づいてImageViewの位置を更新する呼び出しを伴います。問題は、ImageViewの初期化にあると思いますが、私にとってはうまくいかないような他の質問から多くの解決策を試しました。 スレッドからメソッドを呼び出していて、UIスレッドでメソッドを実行しようとしたが、それでも機能しなかったため、これが問題になるかどうかを検討しました。しかし、タッチイベントメソッドからupdateCharPosを呼び出すと、その位置が更新されることがわかりました。これは、前述の他のタスクを実行する上での難しさを引き起こします。ImageView nullPointerException

活動のJava:

package fozard.backuptestapp; 


public class Play extends AppCompatActivity { 

private GameThread thread; 
private float charX=0; 
ImageView character; 


@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_play); 
    character = (ImageView) findViewById(R.id.character); 
} 

@Override 
protected void onStart(){ 
    super.onStart(); 
    thread=new GameThread(); 
    thread.setRunning(true); 
    thread.start(); 
} 

public boolean onTouchEvent(MotionEvent event){ 
    switch (event.getAction()){ 
     case MotionEvent.ACTION_DOWN: 
      thread.setMovementSpeed(5); 
      thread.setMoving(true); 
      break; 
     case MotionEvent.ACTION_UP: 
      thread.setMoving(false); 
    } 
    return true; 
} 

public void updateCharPos(float movementSpeed){ 
    Log.d("Updating", "Should be able to update"); 
    charX = character.getX(); 
    System.out.print(charX); 
} 
} 

スレッドコード:

public class GameThread extends Thread { 

public static final int maxFps=30; 
private double averageFps; 
private boolean isRunning; 
private int score=0; 
private Play play = new Play(); 
private boolean isMoving; 
private float movementSpeed=0; 


public void setMovementSpeed(float movementSpeed){ 
    this.movementSpeed = movementSpeed; 
} 

public void setMoving(Boolean isMoving){ 
    this.isMoving = isMoving; 
} 

public void setRunning(Boolean isRunning){ 
    this.isRunning = isRunning; 
} 


@Override 
public void run(){ 
    long startTime; 
    long timeMillis; 
    long waitTime; 
    int frameCount=0; 
    long totalTime=0; 
    long targetTime= 1000/maxFps; 

    while (isRunning){ 
     startTime = System.nanoTime(); 

     timeMillis = (System.nanoTime()-startTime)/1000000; 
     waitTime = targetTime-timeMillis; 
     try{ 
      if (waitTime>0){ 
       currentThread().sleep(waitTime); 
      } 
     }catch (Exception e){ 

     } 
     totalTime += System.nanoTime() - startTime; 
     frameCount++; 
     score=score+1; 
     if (isMoving){ 
       try{ 
        update(); 
       }catch (Exception e){ 
        e.fillInStackTrace(); 
       } 
     } 

     if (frameCount==maxFps){ 
      averageFps=1000/((totalTime/frameCount)/1000000); 
      frameCount=0; 
      totalTime=0; 
      System.out.println(averageFps); 
     } 
    } 
} 

public void update(){ 
    play.runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      play.updateCharPos(movementSpeed); 
     } 
    }); 

    } 
} 

と私のスタックトレース:

11-23 19:46:51.715 27465-27504/fozard.backuptestapp I/System.out: 30.0 
11-23 19:46:52.710 27465-27504/fozard.backuptestapp I/System.out: 30.0 
11-23 19:46:53.705 27465-27504/fozard.backuptestapp I/System.out: 30.0 
11-23 19:46:54.105 27465-27465/fozard.backuptestapp D/Updating: Should be able to update 
11-23 19:46:54.105 27465-27465/fozard.backuptestapp D/AndroidRuntime: Shutting down VM 
11-23 19:46:54.105 27465-27465/fozard.backuptestapp W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41d29700) 
11-23 19:46:54.125 27465-27465/fozard.backuptestapp E/AndroidRuntime: FATAL EXCEPTION: main 
                     java.lang.NullPointerException 
                     at android.app.Activity.findViewById(Activity.java:1914) 
                     at fozard.backuptestapp.Play.updateCharPos(Play.java:55) 
                     at fozard.backuptestapp.GameThread$1.run(GameThread.java:88) 
                     at android.os.Handler.handleCallback(Handler.java:730) 
                     at android.os.Handler.dispatchMessage(Handler.java:92) 
                     at android.os.Looper.loop(Looper.java:176) 
                     at android.app.ActivityThread.main(ActivityThread.java:5419) 
                     at java.lang.reflect.Method.invokeNative(Native Method) 
                     at java.lang.reflect.Method.invoke(Method.java:525) 
                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046) 
                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862) 
                     at dalvik.system.NativeStart.main(Native Method) 
11-23 19:46:54.840 27465-27504/fozard.backuptestapp I/System.out: 30.0 
11-23 19:46:55.835 27465-27504/fozard.backuptestapp I/System.out: 30.0 

任意の助けをいただければ幸いです!

のXml:

ImageView 
    android:layout_width="100dp" 
    android:layout_height="100dp" 
    android:layout_alignParentBottom="true" 
    android:layout_centerHorizontal="true" 
    android:src="@drawable/character" 
    android:id="@+id/character" 
    android:scaleType="fitCenter" 
    android:clickable="false" 
    android:longClickable="false"/
+0

ため

character = (ImageView) findViewById(R.id.character); 

を置き換えることができますあなたはR.id.characterはImageViewのを指していますか? activity_playレイアウトを投稿できますか? – mWhitley

+0

@mWhitley。私activity_playレイアウトから:これは正しいと思いますか?また、onTouchEventメソッドからupdateCharPos()メソッドを呼び出すと、位置が更新されますが、他のタスク(上記)に問題が発生します – BFozard

+0

@BFozardレイアウトコード(xml)を投稿できますか? – HenriqueMS

答えて

0

EDIT:

私は気づいていなかったが、あなたは手動で私はおよそ

private Play play = new Play(); 

Activity年代を話していた奇妙な行動を説明Activityを拡張するクラスをインスタンス化している@ njzk2はコメントに書いたようにサブクラスを直接インスタンス化するべきではありません。右はhereです。

あなたができる活動の中からこれをやっている場合は、次の

Intent intent = new Intent(this, NAME_OF_NEW_ACTIVITY.class); 
    startActivity(intent); 

あなたの実際のコールフローは次のようになります:

Play (Activity) -> new GameThread() -> new Play() (Activity) -> new GameThread() 

それはあなたが右の欲しいものはおそらくありませんか?あなたが別のスレッドから活動を開始している場合は、新しい活動

Intent myIntent = new Intent(mContext, Play.class); 

mContext.startActivity(myIntent); 

あなたが直接NPEを得ているという事実を起動することができるように

はまた、あなたは、コンテキストを持っている必要がありますfindViewById()を呼び出すと、あなたはまだ完全に作成されたアクティビティが奇妙であるとは思わないかもしれません。さらに、デバッグのために

あなたは

LayoutInflater mInflater; 
    mInflater = LayoutInflater.from(this); 

    //breakpoint here, check if you have the mInflater 
    View layoutView = mInflater.inflate(R.layout.activity_play, null); 

    //breakpoint here, check if you have the layoutView 
    ImageView character = (ImageView) layoutView.findViewById(R.id.character); 

    //if you get here you should be in the clear 
    setContentView(layoutView); 
+0

ありがとうございました!あなたと@ njzk2は、アクティビティの新しいインスタンスを作成することによってそれが起こっていることを正しく示していました。私は活動の中で 'public static Play play'を使用して終了し、 'play = this;' onCreate()内で。これにより、 'Play.play.updateCharPos(movementSpeed);によってスレッドから既存のアクティビティインスタンスを参照することができました。今は完璧に動作します!助けてくれてありがとう! – BFozard

+0

@BFozardちょっとしたアイデアに注意してください。アクティビティへの静的な参照を保持することによって、ガベージコレクションが行われずにメモリがリークする可能性が高くなります。私はAndroidのパターンに従って活動を使用することをお勧めします。私は喜びを助けることができてうれしいです;) – HenriqueMS

0

R.id.characterが実際に有効なビューを参照すると仮定すると、あなたは必要なUIコンポーネントが実際に存在していることを保証するために、どちらかonStart()またはonResume()関数にバックグラウンドスレッドの初期化thread=new GameThread();を移動することができます。

Androidライフサイクルの詳細については、this SO postを参照してください。

+0

提案のおかげで@ブー。 R.id.characterが有効なビューを参照していて、次のような修正を試みたことを確認しました: '@Override' protected void onStart(){ super.onStart(); スレッド=新しいGameThread(); thread.setRunning(true); thread.start(); }、問題は引き続き発生します。変わった部分は、タッチイベントからupdateCharPosを呼び出すと(これが他のプロセスを停止させた元の問題を引き起こしますが) – BFozard