2014-01-14 94 views
3

我想在我的android應用程序中製作一些水波,所以我用這個javascript代碼http://jsfiddle.net/esteewhy/5Ht3b/6/轉換成C代碼,就像這裏顯示的Live Wallpaper Water Ripple Effect(由esteewhy)。致命的異常

我有一個主要活動,點擊一個按鈕後調用水波紋活動。水波紋是偉大的工作,我的可變位,問題是,當我點擊了Android設備的「返回」按鈕,系統崩潰引發此錯誤:

FATAL EXCEPTION: Thread-2556 
java.lang.NullPointerException 
at com.wheelly.whater.WaterView.onDraw (line 149) 
at com.wheelly.whater.WaterView$GameThread.run (line 255) 

我想有一些問題的處理線程或活動本身。

這裏是水波紋的代碼:在GameThread檢查,如果線程的run方法

public class WaterView extends SurfaceView implements SurfaceHolder.Callback { 
    GameThread thread; 

    public static Bitmap icon; 

    //Measure frames per second. 
    long now; 
    int framesCount=0; 
    int framesCountAvg=0; 
    long framesTimer=0; 
    Paint fpsPaint=new Paint(); 

    //Frame speed 
    long timeNow; 
    long timePrev = 0; 
    long timePrevFrame = 0; 
    long timeDelta; 

    private int width = 480; 
    private int height = 800; 

    private short riprad = 6; 
    boolean flip; 
    private short[] ripplemap, last_map; 
    Bitmap ripple; 

    private static final String TAG = null; 

    private Rippler rippler; 

    public WaterView(Context context) { 
     super(context); 
     initialize(); 
    } 

    void initialize() { 
     //CB 
     icon = BitmapFactory.decodeResource(getResources(), R.drawable.sand100); 
     icon = convertToMutable(icon); 
     //-- 
     rippler = new NativeRippler(); 
     reinitgGlobals(); 
     fpsPaint.setTextSize(30); 

     //Set thread 
     getHolder().addCallback(this); 

     setFocusable(true); 
    } 

    void reinitgGlobals() { 
     int size = width * (height + 2) * 2; 
     ripplemap = new short[size]; 
     last_map = new short[size]; 
     Bitmap texture = createBackground(width, height); // this creates a MUTABLE bitmap 
     ripple = texture; 
     _td = new int[width * height]; 
     texture.getPixels(_td, 0, width, 0, 0, width, height); 
     _rd = new int[width * height]; 
    } 

    void randomizer() { 
     final Random rnd = new Random(); 
     final Handler disHAndler = new Handler(); 
     final Runnable disturbWater = new Runnable() { 
      @Override 
      public void run() { 
       disturb(rnd.nextInt(width), rnd.nextInt(height)); 
       disHAndler.postDelayed(this, 7000); 
      } 
     }; 
     disHAndler.post(disturbWater); 
    } 

    private static Bitmap createBackground(int width, int height) { 
     Canvas cb = new Canvas (icon); 
     cb.save(); 
     cb.restore(); 
     return icon; 
    } 


    private Bitmap convertToMutable(Bitmap bitmap) { 
     try { 
      File file = new File("/mnt/sdcard/sample/temp.txt"); 
      file.getParentFile().mkdirs(); 
      RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); 

      int width_mutable = bitmap.getWidth(); 
      int height_mutable = bitmap.getHeight(); 

      FileChannel channel = randomAccessFile.getChannel(); 
      MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, width_mutable*height_mutable*4); 
      bitmap.copyPixelsToBuffer(map); 
      bitmap.recycle(); 

      bitmap = Bitmap.createBitmap(width_mutable, height_mutable, Config.ARGB_8888); 
      map.position(0); 
      bitmap.copyPixelsFromBuffer(map); 

      channel.close(); 
      randomAccessFile.close(); 

     } catch (FileNotFoundException e) { 
      Log.i(TAG, "::onActivityResult:" + ""+Log.getStackTraceString(e)); 
     } catch (IOException e) { 
      Log.i(TAG, "::onActivityResult:" + ""+Log.getStackTraceString(e)); 
     } 
     return bitmap; 
    } 

    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
     super.onSizeChanged(w, h, oldw, oldh); 
     width = w; 
     height = h; 
     reinitgGlobals(); 
    } 

    @Override 
    protected void onDraw(android.graphics.Canvas canvas) { 
     super.onDraw(canvas); 
     newframe(); 
     canvas.drawBitmap(ripple, 0, 0, null); 

     //Measure frame rate (unit: frames per second). 
     now=System.currentTimeMillis(); 
     canvas.drawText(framesCountAvg+" fps", 40, 70, fpsPaint); 
     framesCount++; 
     if(now-framesTimer>1000) { 
       framesTimer=now; 
       framesCountAvg=framesCount; 
       framesCount=0; 
     } 
    } 

    /** 
    * Disturb water at specified point 
    */ 
    private void disturb(int dx, int dy) { 
     rippler.disturb(dx, dy, width, height, riprad, ripplemap, flip); 
    } 

    int[] _td; 
    int[] _rd; 

    /** 
    * Generates new ripples 
    */ 
    private void newframe() { 
     System.arraycopy(_td, 0, _rd, 0, width * height); 
     flip = !flip; 
     rippler.transformRipples(height, width, ripplemap, last_map, _td, _rd, flip); 
     ripple.setPixels(_rd, 0, width, 0, 0, width, height); 
    } 


    @Override 
    public synchronized boolean onTouchEvent(MotionEvent event) { 
      disturb((int)event.getX(), (int)event.getY()); 
      return true; 

    } 

    @Override 
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { 
    } 

    @Override 
    public void surfaceCreated(SurfaceHolder arg0) { 
     thread = new GameThread(getHolder(), this); 
     thread.setRunning(true); 
     thread.start(); 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder arg0) { 
     boolean retry = true; 
     thread.setRunning(false); 
     while (retry) { 
      try { 
       thread.join(); 
       retry = false; 
      } catch (InterruptedException e) { 

      } 
     } 
    } 

    class GameThread extends Thread { 
     private SurfaceHolder surfaceHolder; 
     private WaterView gameView; 
     private boolean run = false; 

     public GameThread(SurfaceHolder surfaceHolder, WaterView gameView) { 
      this.surfaceHolder = surfaceHolder; 
      this.gameView = gameView; 
     } 

     public void setRunning(boolean run) { 
      this.run = run; 
     } 

     public SurfaceHolder getSurfaceHolder() { 
      return surfaceHolder; 
     } 

     @Override 
     public void run() { 
      Canvas c; 
      while (run) { 
       c = null; 

       //limit frame rate to max 60fps 
       timeNow = System.currentTimeMillis(); 
       timeDelta = timeNow - timePrevFrame; 
       if (timeDelta < 16) { 
        try { 
         Thread.sleep(16 - timeDelta); 
        } 
        catch(InterruptedException e) { 
        } 
       } 
       timePrevFrame = System.currentTimeMillis(); 

       try { 
        c = surfaceHolder.lockCanvas(null); 
        synchronized (surfaceHolder) { 
         //call methods to draw and process next fame 
         gameView.onDraw(c); 
        } 
       } finally { 
        if (c != null) { 
         surfaceHolder.unlockCanvasAndPost(c); 
        } 
       } 
      } 
     } 
    } 
} 
+0

哪條線是149? – Nfear

+0

嗨, 這一行這裏: canvas.drawBitmap(ripple,0,0,null); – txarlybarrera

回答

1

你應該關閉你的工作線程的方法Activity.onStop

@Override 
    protected void onStop() { 
     thread.interrupt(); 
     super.onStop(); 
    } 

在調用gameView.onDraw(c)之前中斷。像這樣:

if(isInterrupted()) { 
     break; 
    } 
    gameView.onDraw(c); 

順便說一句,大概如果更換gameView.onDraw(c)與gameView.invalidate()它會更好;

+0

您好Yury,非常感謝您的幫助。我嘗試了你的建議,但同樣的錯誤仍然出現。我將該線程通過處理程序傳遞給活動類,並關閉該活動的onStop方法中的線程。 我也用invalidate()替換了onDraw方法,但它並沒有幫助。 – txarlybarrera

+0

我不知道下面的提示是否會幫助,但誰知道 - 嘗試將方法onSizeChanged中的所有代碼移動到surfaceChanged。 –

+0

它沒有工作,但無論如何感謝。 – txarlybarrera

1

不要直接調用onDraw有一個觀點,而是叫gameView.invalidate()

synchronized (surfaceHolder) { 
    //call methods to draw and process next fame 
    gameView.invalidate(); 
} 

如果它不能正常工作,請嘗試使用調試器斷點,看看哪些變量爲空正是

1

我發現解決方案:

我不得不中斷活動的方法中的線程,而不是在onStop方法中進行。現在它工作正常。

非常感謝大家幫助我解決這個問題。