2013-10-10 58 views
0

我在Scala和Android開發中很新,所以我認爲這個錯誤可能無處不在。實際上,這個代碼或多或少是一個Sudoku應用程序的Java教程的Scala翻譯。我得到的錯誤是常見:Scala for Android應用程序:無法實例化activityinfo組件

10-10 17:41:26.743: E/AndroidRuntime(17091): FATAL EXCEPTION: main 
10-10 17:41:26.743: E/AndroidRuntime(17091): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.sudokuscala/com.example.sudokuscala.Game}: java.lang.NullPointerException 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2106) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.app.ActivityThread.access$600(ActivityThread.java:141) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.os.Handler.dispatchMessage(Handler.java:99) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.os.Looper.loop(Looper.java:137) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.app.ActivityThread.main(ActivityThread.java:5041) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at java.lang.reflect.Method.invokeNative(Native Method) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at java.lang.reflect.Method.invoke(Method.java:511) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at dalvik.system.NativeStart.main(Native Method) 
10-10 17:41:26.743: E/AndroidRuntime(17091): Caused by: java.lang.NullPointerException 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.content.ContextWrapper.getResources(ContextWrapper.java:89) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.view.ContextThemeWrapper.getResources(ContextThemeWrapper.java:78) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.view.View.<init>(View.java:3226) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at com.example.sudokuscala.PuzzleView.<init>(PuzzleView.scala:15) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at com.example.sudokuscala.Game.<init>(Game.scala:21) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at java.lang.Class.newInstanceImpl(Native Method) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at java.lang.Class.newInstance(Class.java:1319) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.app.Instrumentation.newActivity(Instrumentation.java:1054) 
10-10 17:41:26.743: E/AndroidRuntime(17091): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2097) 
10-10 17:41:26.743: E/AndroidRuntime(17091): ... 11 more 

請在下面找到我的代碼:

Android清單:

 <?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
package="com.example.sudokuscala" 
android:versionCode="1" 
android:versionName="1.0" > 

<uses-sdk 
    android:minSdkVersion="11" 
    android:targetSdkVersion="18" /> 

<application 
    android:allowBackup="true" 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme" > 
    <activity 
     android:name="com.example.sudokuscala.SudokuScala" 
     android:label="@string/app_name" > 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 
    <activity 
     android:name="com.example.sudokuscala.About" 
     android:label="@string/about_label" 
     android:theme="@android:style/Theme.Dialog" > 
    </activity> 
    <activity 
     android:name="com.example.sudokuscala.Game" 
     android:label="@string/game_title" > 
    </activity> 
    <activity 
     android:name="com.example.sudokuscala.PuzzleView"> 
    </activity> 
</application> 

SudokuScala.scala(MainActivity)

package com.example.sudokuscala 

    import com.example.sudokuscala.R.layout 

    import android.app.Activity 
import android.os.Bundle 
import android.view.View 
import android.view.View.OnClickListener 
import android.content.Intent 
import android.app.AlertDialog 
import android.content.DialogInterface 
import android.util.Log 

class SudokuScala extends Activity { 

override def onCreate(savedState : Bundle) : Unit = { 
    super.onCreate(savedState) 
    setContentView(R.layout.main) 

//Set up click listeners for all the buttons 
val newButton = findViewById(R.id.new_button) 
newButton.setOnClickListener(new View.OnClickListener() { 

    def onClick(view : View) = { 
     openNewGameDialog 
    } 
    }) 

val aboutButton = findViewById(R.id.about_button) 
aboutButton.setOnClickListener(new OnClickListener() { 

    def onClick(view : View) = { 
     startActivity(new Intent(SudokuScala.this, classOf[About])) 
    } 
}) 

val exitButton = findViewById(R.id.exit_button) 
exitButton.setOnClickListener(new OnClickListener() { 

    def onClick(view : View) = { 
     finish() 
    } 
}) 
} 

val TAG : String = "Sudoku" 

//Open the window for difficulty choices 
def openNewGameDialog() { 
    new AlertDialog.Builder(this) 
    .setTitle(R.string.new_game_title) 
    .setItems(R.array.difficulty, 
      new DialogInterface.OnClickListener() { 
       def onClick(dialoginterface : DialogInterface , i : Int) { 
        startGame(i) 
     } 
    }) 
    .show() 
} 

// Start game with the chosen difficulty 
def startGame(i : Int) { 
    Log.d(TAG, "clicked on " + i); 
    val intent = new Intent(this, classOf[Game]) 
    intent.putExtra("org.example.sudoku.difficulty",i) 
    startActivity(intent) 
} 
} 

Game.scala

package com.example.sudokuscala 

import android.app.Activity; 
import android.app.Dialog; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Gravity; 
import android.widget.Toast; 

class Game extends Activity { 

val TAG : String ="Sudoku" 

val KEY_DIFFICULTY : String ="org.example.sudoku.difficulty" 
val DIFFICULTY_EASY : Int = 0 
val DIFFICULTY_MEDIUM : Int = 1 
val DIFFICULTY_HARD : Int = 2 

var puzzle = Array.fill(81)(0) 

var puzzleView = new PuzzleView(this) 

override def onCreate(savedState : Bundle) { 
    super.onCreate(savedState) 
    Log.d(TAG, "onCreate") 

    def diff : Int = getIntent.getIntExtra(KEY_DIFFICULTY, DIFFICULTY_EASY) 
    puzzle = getPuzzle(diff) 
    calculateUsedTiles 

    puzzleView = new PuzzleView(this) 
    setContentView(puzzleView) 
    puzzleView.requestFocus() 
} 

def showKeypadOrError(x : Int, y : Int) : Unit = { 
    var tiles = getUsedTiles(x, y) 
    if (tiles.length == 9) { 
     var toast = Toast.makeText(this, R.string.no_moves_label, Toast.LENGTH_SHORT); 
     toast.setGravity(Gravity.CENTER, 0, 0) 
     toast.show(); } 
    else { 
     Log.d(TAG, "showKeypad: used=" + toPuzzleString(tiles)) 
     var v = new Keypad(this, tiles, puzzleView); 
     v.show(); 
} } 

def setTileIfValid(x : Int, y : Int, value : Int) : Boolean = { 
    var tiles = getUsedTiles(x, y) 
    if (value != 0) { 
     for (tile <- tiles) { 
      if (tile == value) 
      return false; 
     } } 
    setTile(x, y, value) 
    calculateUsedTiles() 
    true 
} 

val x0 = 0 
val y0 = 0 
val z0 = 0 
var used = Array.fill(x0, y0, z0)(0) 

def getUsedTiles(x : Int, y : Int) : Array[Int] = { 
    used(x)(y); 
} 

def calculateUsedTiles() { 
    for (x <- 0 to 8) { 
     for (y <- 0 to 8) { 
      used(x)(y) = calculateUsedTiles(x, y); 
      // Log.d(TAG, "used[" + x + "][" + y + "] = " 
      // + toPuzzleString(used[x][y])); 
     }}} 

//Pour chaque tile (case), cette fonction donne la liste (Array[Int]) 
//des chiffres interdits a cette case 
def calculateUsedTiles(x : Int, y : Int) : Array[Int] = { 
    var c = Array.fill[Int](9)(0) 
    var t = 0 

// horizontal 
    for (i <- 0 to 8) { 
     if (i == y) {} 
     else t = getTile(x, i) 
      if(t!= 0) 
      c(t - 1)=t 
    } 

// vertical 
    for (i <- 0 to 8) { 
     if (i == x) {} 
     else t = getTile(i, y) 
      if (t != 0) 
       c(t - 1) = t 
    } 

// same cell block 
    var startx = (x/3) * 3 
    var starty = (y/3) * 3 
    for (i <- startx to startx + 2) { 
     for (j <- starty to starty + 2) { 
      if (i == x && j == y) {} 
      else t = getTile(i, j) 
       if(t!= 0) 
        c(t - 1)=t 
     } 
    } 

// compress 
var nused = 0 
for (t <- c) { 
    if (t != 0) 
     nused = nused + 1 
} 

var c1 = Array.fill(nused)(0) 
nused = 0 
for (t <- c){ 
    if (t != 0) 
     {c1(nused) = t 
     nused = nused + 1} 
} 
c1 
} 

val easyPuzzle = new String(
     "360000000004230800000004200" + 
     "070460003820000014500013020" + 
     "001900000007048300000000045") 
val mediumPuzzle = new String(
     "650000070000506000014000005" + 
     "007009000002314700000700800" + 
     "500000630000201000030000097") 
val hardPuzzle = new String( 
     "009000000080605020501078000" + 
     "000000700706040102004000000" + 
     "000720903090301080000000600") 

def getPuzzle(diff : Int) : Array[Int] = { 
    var puz = new String 
    // TODO: Continue last game 
    if (diff == 2) 
     puz = hardPuzzle 
    else if (diff == 1) 
     puz = mediumPuzzle 
    else if (diff == 0) 
     puz = easyPuzzle 
    return fromPuzzleString(puz) } 

def toPuzzleString(puz : Array[Int]) : String = { 
    var buf = new StringBuilder() 
    for (element <- puz) { 
     buf.append(element) 
    } 
    buf.toString() } 

def fromPuzzleString(string : String) : Array[Int] = { 
    var puz = Array.fill[Int](81)(0) 
    for (i <- 0 to 80) { 
     puz(i) = string.charAt(i) - '0'; 
     } 
    return puz; 
} 

def getTile(x : Int, y : Int) : Int = { 
    puzzle(y * 9 + x) 
} 

def setTile(x : Int, y : Int, value : Int) : Unit = { 
    puzzle(y * 9 + x) = value 
} 

def getTileString(x : Int, y : Int) : String ={ 
    var v = getTile(x, y) 
    if (v == 0) 
     "" 
    else 
     String.valueOf(v); 
    } 

} 

PuzzleView.scala

package com.example.sudokuscala 

import android.content.Context 
import android.graphics.Canvas 
import android.graphics.Paint 
import android.graphics.Paint.FontMetrics 
import android.graphics.Paint.Style 
import android.graphics.Rect 
import android.util.Log 
import android.view.KeyEvent 
import android.view.MotionEvent 
import android.view.View 
import android.view.animation.AnimationUtils 

class PuzzleView(context : Context) extends View(context) { 

val TAG ="Sudoku" 
var game = new Game 

this.game = context.asInstanceOf[Game] 
setFocusable(true) 
setFocusableInTouchMode(true) 


var width : Float = 0 //width of one tile 
var height : Float = 0//height of one tile 
var selX : Float = 0//X index of selection 
var selY : Float = 0//Y index of selection 
var selRect = new Rect() 

override def onSizeChanged(w : Int, h : Int , oldw : Int, oldh : Int) : Unit = { 
    width = w /9 
    height = h/ 9 
    getRect(selX.toInt,selY.toInt, selRect) 
    Log.d(TAG, "onSizeChanged : width " + width +", height " + height) 
    super.onSizeChanged(w, h, oldw, oldh) 
} 

def getRect(x : Int, y : Int, rect : Rect) : Unit = { 
    rect.set((x*width).toInt, (y*height).toInt, (x*width+width).toInt, (y*height+height).toInt); 
} 

override def onDraw(canvas : Canvas) : Unit ={ 
    //Draw the background 
    val background = new Paint() 
    background.setColor(getResources().getColor(R.color.puzzle_background)) 
    canvas.drawRect(0, 0, getWidth(), getHeight(), background) 

    //Draw the board 
    //Define colors for the grid lines 
    val dark = new Paint() 
    dark.setColor(getResources().getColor(R.color.puzzle_dark)) 

    val hilite = new Paint() 
    hilite.setColor(getResources().getColor(R.color.puzzle_hilite)) 

    val light = new Paint() 
    light.setColor(getResources().getColor(R.color.puzzle_light)) 

    //Draw the minor grid lines 
    for (i <- 0 to 8){ 
     canvas.drawLine(0, i*height, getWidth(), i * height, light) 
     canvas.drawLine(0, i*height + 1, getWidth(), i * height + 1, hilite) 
     canvas.drawLine(i*width, 0, i*width, getHeight(), light) 
     canvas.drawLine(i*width + 1, 0, i*width + 1, getHeight(), hilite) 
    } 

    //Draw the major grid lines 
      for (i <- 0 to 8){ 
       if (i%3 != 0) {} 
       else { 
       canvas.drawLine(0, i*height, getWidth(), i * height, dark) 
       canvas.drawLine(0, i*height + 1, getWidth(), i * height + 1, dark) 
       canvas.drawLine(0, i*height - 1, getWidth(), i * height - 1, dark) 
       canvas.drawLine(i*width, 0, i*width, getHeight(), dark) 
       canvas.drawLine(i*width + 1, 0, i*width + 1, getHeight(), dark) 
       canvas.drawLine(i*width - 1, 0, i*width - 1, getHeight(), dark) 
       } 
      } 

    // Define color and style for numbers 
    val foreground = new Paint(Paint.ANTI_ALIAS_FLAG) 
    foreground.setColor(getResources().getColor(R.color.puzzle_foreground)) 
    foreground.setStyle(Style.FILL) 
    foreground.setTextSize(height * 0.75f) 
    foreground.setTextScaleX(width/height)  
    foreground.setTextAlign(Paint.Align.CENTER)    

    // Draw the number in the center of the tile 
    val fm = foreground.getFontMetrics() 
    // Centering in X: use alignment (and X at midpoint) 
    var x = width/2 
    // Centering in Y: measure ascent/descent first 
    var y = height/2 - (fm.ascent + fm.descent)/2 

    for (i <- 0 to 8) { 
     for (j <- 0 to 8) { 
      canvas.drawText(this.game.getTileString(i, j), i * width + x, j * height + y, foreground) 
      } 
     } 

    //Draw the selection 
    Log.d(TAG, "selRect=" + selRect) 
    val selected = new Paint() 
    selected.setColor(getResources().getColor(R.color.puzzle_selected)) 
    canvas.drawRect(selRect, selected) 

    // Draw the hints... 
    // Pick a hint color based on #moves left 
    /*val hint = new Paint(); 
    val c = Array(getResources().getColor(R.color.puzzle_hint_0), getResources().getColor(R.color.puzzle_hint_1), getResources().getColor(R.color.puzzle_hint_2)) 
    val r = new Rect(); 
    for (i <- 0 to 8) { 
     for (j <- 0 to 8) { 
      val movesleft = 9 - game.getUsedTiles(i, j).length 
      if (movesleft < c.length) { 
      getRect(i, j, r) 
      hint.setColor(c(movesleft)) 
      canvas.drawRect(r, hint) 
      } 
     } 
    }*/ 


} 
    override def onKeyDown(keyCode : Int, event : KeyEvent) : Boolean ={ 
     Log.d(TAG, "onKeyDown=" + keyCode +", events =" + event) 
     keyCode match { 
     /*case KeyEvent.KEYCODE_DPAD_UP => 
      select(selX, selY-1) 
     case KeyEvent.KEYCODE_DPAD_DOWN => 
      select(selX, selY+1) 
     case KeyEvent.KEYCODE_DPAD_LEFT => 
      select(selX-1, selY) 
     case KeyEvent.KEYCODE_DPAD_RIGHT => 
      select(selX+1, selY)*/ 
     case KeyEvent.KEYCODE_0 => 
     case KeyEvent.KEYCODE_SPACE => setSelectedTile(0) 
     case KeyEvent.KEYCODE_1 => setSelectedTile(1) 
     case KeyEvent.KEYCODE_2 => setSelectedTile(2) 
     case KeyEvent.KEYCODE_3 => setSelectedTile(3) 
     case KeyEvent.KEYCODE_4 => setSelectedTile(4) 
     case KeyEvent.KEYCODE_5 => setSelectedTile(5) 
     case KeyEvent.KEYCODE_6 => setSelectedTile(6) 
     case KeyEvent.KEYCODE_7 => setSelectedTile(7) 
     case KeyEvent.KEYCODE_8 => setSelectedTile(8) 
     case KeyEvent.KEYCODE_9 => setSelectedTile(9) 
     //case KeyEvent.KEYCODE_ENTER => 
     //case KeyEvent.KEYCODE_DPAD_CENTER => game.showKeypadOrError(selX, selY) 
     //default => return super.onKeyDown(keyCode,event); 
     } 
     return true; 
    } 

    def select(x: Int, y : Int) : Unit = { 
     invalidate(selRect) 
     selX = Math.min(Math.max(x,0),8) 
     selY = Math.min(Math.max(y,0),8) 
     getRect(selX.toInt, selY.toInt, selRect) 
     invalidate(selRect) 
    } 


    override def onTouchEvent(event : MotionEvent) : Boolean = { 
     if (event.getAction() != MotionEvent.ACTION_DOWN) 
      return super.onTouchEvent(event) 

     select((event.getX()/width).toInt, (event.getY()/height).toInt) 
     game.showKeypadOrError(selX.toInt, selY.toInt) 
     Log.d(TAG, "onTouchEvent : x " + selX + ", y " + selY) 
     return true; 
    } 

    def setSelectedTile(tile : Int) : Unit ={ 
     if (game.setTileIfValid(selX.toInt, selY.toInt, tile)) { 
      invalidate() //may change hints 
     } else 
      //Number is not valid for this tile 
      Log.d(TAG, "setSelectedTile: invalid: " + tile); 
      startAnimation(AnimationUtils.loadAnimation(game,R.anim.shake)); 
    } 


} 

如果你能幫助我,那將是偉大的!提前致謝 !

+0

嗯,堆棧跟蹤中有什麼不清楚?你在這裏有一個NPE異常:'(Game.scala:21) - >(PuzzleView.scala:15)'。調試它。 –

回答

0

正如我看到的那樣,你創建視圖並將它的實例(this)引用到它的constaructor中。

Game.scala: 21: var puzzleView = new PuzzleView(this) 

在這一點上它沒有被初始化。所以它不能被用作視圖的上下文。

嘗試在onCreate方法中實例化您的視圖。

+0

非常感謝,它現在正在工作......其實,我已經在onCreate和showKeypadOrError方法中實例化了它,因爲方法的變量是私有的。 – Marat

相關問題