0

我是 Scala 和 Android 开发的新手,所以我相信错误可能无处不在。实际上,这段代码或多或少是数独应用程序 Java 教程的 Scala 翻译。我得到的错误是常见的:

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

请在下面找到我的代码:

安卓清单:

     <?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)
}
 }

游戏.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));
    }


}

如果你能帮助我,那就太好了!提前致谢 !

4

1 回答 1

0

正如我实际看到的那样,您创建视图并在其构造函数中引用 Activity 的实例(this)。

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

那时它还没有初始化。所以它不能用作视图的上下文。

尝试在 onCreate 方法中实例化您的视图。

于 2013-10-10T21:22:01.963 回答