可能有两个问题,一个是关于Handler,另一个是关于声音池。
这是错误日志:

09-09 06:36:24.743: W/dalvikvm(541): threadid=1: thread exiting with uncaught exception (group=0x409c01f8)
09-09 06:36:24.801: E/AndroidRuntime(541): FATAL EXCEPTION: main
09-09 06:36:24.801: E/AndroidRuntime(541): java.lang.NullPointerException
09-09 06:36:24.801: E/AndroidRuntime(541):  at com.example.helloandroid.WelcomeView.playSound(WelcomeView.java:78)
09-09 06:36:24.801: E/AndroidRuntime(541):  at com.example.helloandroid.TestHelloAndroidActivity$1.handleMessage(TestHelloAndroidActivity.java:67)
09-09 06:36:24.801: E/AndroidRuntime(541):  at android.os.Handler.dispatchMessage(Handler.java:99)
09-09 06:36:24.801: E/AndroidRuntime(541):  at android.os.Looper.loop(Looper.java:137)
09-09 06:36:24.801: E/AndroidRuntime(541):  at android.app.ActivityThread.main(ActivityThread.java:4424)
09-09 06:36:24.801: E/AndroidRuntime(541):  at java.lang.reflect.Method.invokeNative(Native Method)
09-09 06:36:24.801: E/AndroidRuntime(541):  at java.lang.reflect.Method.invoke(Method.java:511)
09-09 06:36:24.801: E/AndroidRuntime(541):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
09-09 06:36:24.801: E/AndroidRuntime(541):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
09-09 06:36:24.801: E/AndroidRuntime(541):  at dalvik.system.NativeStart.main(Native Method)

谁能帮忙!非常感谢。
这是我的代码,请忽略注释中的中文字符。非常感谢。 :P

1.“TestAndroidActivity”代码:
package com.example.helloandroid;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.os.Looper;
import android.os.Message;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Window;
import android.view.WindowManager;

public class TestHelloAndroidActivity extends Activity {
/** Called when the activity is first created. */ <br/>
View CurrentView;
WelcomeView wv;
ProgressView pv;
GameView gv;
boolean wantSound=true;         //是否开启声音,默认不开
Handler myHandler = new Handler(){                  //创建自定义的Handler
    public void handleMessage(Message msg) {            //重写处理消息的方法
        switch(msg.what){                           //判断Message对象的类型
        case 0:                                 //切换到开始游戏前的进度条界面
            pv = new ProgressView(TestHelloAndroidActivity.this, 4);    //target为0,进度条走完后去Gameview
            setContentView(pv);                     //切换屏幕到ProgressView
            CurrentView = pv;                       //记录当前View
            wv.soundPool.release();                 //释放SoundPool
            wv.soundPool = null;                        //声明SoundPool对象为null
            wv = null;                              //声明WelcomeView对象为null
            new Thread(){                           //创建并启动一个新线程
                public void run(){
                    Looper.prepare();
                    BitmapManager.loadGamePublic(getResources());   //加载游戏界面图片资源
                    updateProgress(40);                         //更新进度条
                    gv = new GameView(null);            //创建GameView对象
                    updateProgress(100);                        //更新进度条
                }
            }.start();
            break;
        case 4:                                 //开始游戏
            setContentView(gv);                     //切换屏幕到GameView
            CurrentView = gv;                       //记录当前View
            pv = null;                              //声明pv指向的ProgressView的
            break;
        /*case 1:                                   //显示帮助
            hv = new HelpView(RunActivity.this);            //创建HelpView对象
            setContentView(hv);                     //切换屏幕到HelpView
            currentView = hv;                       //记录当前View
            wv.resetMenu();                     //重置菜单按钮
            break; */
        case 2:                                 //退出游戏
            wv.stopSound(1);                        //停止声音的播放
            wv.soundPool.release();                 //释放WelcomeView的SoundPool对象
            android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(0);                         //退出程序
            break;
        case 3:                                 //显示欢迎界面
            setContentView(wv);                     //设置当前屏幕为WelcomeView对象
            CurrentView = wv;                       //记录当前View
            if(wantSound){                          //如有需要,播放声音
                wv.playSound(1, -1);
            }
            pv = null;                              //将pv指向的ProgressView声明为垃圾
            break;
        }
    }
};
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //设置全屏
    getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    BitmapManager.loadSystemPublic(getResources());
    pv = new ProgressView(this, 3);                 //创建一个ProgressView对象,目标为3,即走满后去WelcomeView
    setContentView(pv);
    CurrentView = pv;
    new Thread(){
        public void run(){
            Looper.prepare();
            BitmapManager.loadWelcomePublic(getResources());    //加载欢迎界面的图片资源
            updateProgress(60);
            wv = new WelcomeView(TestHelloAndroidActivity.this);//初始化WelcomeView
            updateProgress(100);
        }
    }.start();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if(event.getAction() == MotionEvent.ACTION_UP){
        int x = (int)event.getX();          //获取屏幕点击处的X坐标
        int y = (int)event.getY();          //获取屏幕点击处的Y坐标
        if(CurrentView == wv){              //如果当前View为WelcomeView
            return wv.myTouchEvent(x, y);   //调用WelcomeView的相关事件处理方法
        }
        /*else if(CurrentView == gv){           //如果当前View为GameView
            return gv.myTouchEvent(x, y);   //调用GameView的相关事件处理方法
        } */
    }
    return true;
}

//方法:更新进度条 <br/>
public void updateProgress(int progress){
    if(pv != null){
        pv.setProgress(progress);
    }
}
}

2. WelcomeView:
package com.example.helloandroid;
import java.util.HashMap;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.media.AudioManager;
import android.media.SoundPool;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class WelcomeView extends SurfaceView implements SurfaceHolder.Callback {
TestHelloAndroidActivity father;
WelcomeDrawThread wdt;
int status = -1; //记录当前状态,0:背景渐显,1:美女移入,2:显示菜单,3:待命,4:有按钮点下
int selectedIndex=-1;//选择的菜单选项,如0为开始游戏/1为帮助/2退出
int mm_x = 129; //mm图片宽度
int mm_y = 289; //mm图片高度
int mmX; //终点X坐标0
int mmY; //终点Y左边191
int btnIndex = 0; //按钮帧索引
int btnSpan = 10; //按钮间隔
int btnHight = 25; //按钮高度
int alpha = 0;
Rect rectMenuStart = new Rect(105,334,317,359);//开始按钮矩形框
Rect rectMenuHelp = new Rect(105,369,317,394);//帮助按钮矩形框
Rect rectMenuQuit = new Rect(105,404,317,429);//退出按钮矩形框
Rect rectSoundMenu = new Rect(140,440,172,472);//声音按钮
SoundPool soundPool;        //SoundPool对象引用
HashMap<Integer,Integer> SoundMap;  //存放声音资源的Map

public WelcomeView(TestHelloAndroidActivity father) {
    super(father);
    this.father = father;
    getHolder().addCallback(this);
    wdt = new WelcomeDrawThread(this, getHolder());
}

public void doDraw(Canvas canvas){
    Paint paint = new Paint();  //创建画笔
    paint.setAlpha(alpha);
    BitmapManager.drawWelcomePublic(0, canvas, 0, 0,paint);//画背景

    switch(status){
    case 1://状态:美女渐入
        BitmapManager.drawWelcomePublic(1, canvas, mmX, mmY, paint);

    case 4://状态:有按钮点下
    case 3://状态:待命状态,等待按钮按下
        BitmapManager.drawWelcomePublic((father.wantSound?6:5), canvas, 140, 440, paint);//画声音菜单,5表示开启那帧,6表示关闭那帧

    case 2://状态:显示菜单按钮, 光画框还没写字呢09.09
        paint.setAlpha(alpha);      //设置画笔透明度
        for(int i=0; i<3; i++){
        BitmapManager.drawWelcomePublic((i==selectedIndex?btnIndex+2:2), canvas, rectMenuStart.left, rectMenuStart.top+i*(btnHight + btnSpan), paint);
        }
        break;
    }
}

//方法:初始化声音
    public void initSound(TestHelloAndroidActivity father){

        soundPool = new SoundPool(1,AudioManager.STREAM_MUSIC,100);
        int id = soundPool.load(father, R.raw.welcom_background, 1);
        SoundMap.put(1, id);    //加载背景音乐
    }
    //方法:播放声音
    public void playSound(int sound,int loop){
        AudioManager am = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
        float streamVolumeCurrent = am.getStreamVolume(AudioManager.STREAM_MUSIC);
        float streamVolumeMax = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        float volume = streamVolumeCurrent / streamVolumeMax;
        soundPool.play(SoundMap.get(sound), volume, volume, 1, loop, 1);
    }
    //方法:停止声音
    public void stopSound(int sound){
        soundPool.stop(SoundMap.get(sound));
    }

    //方法:处理用户点击屏幕事件
    public boolean myTouchEvent(int x,int y){
        if(rectMenuStart.contains(x, y)){//点下开始按钮
            selectedIndex = 0;//设置按下的索引
            status = 4;//设置状态为4,即按下列按钮
        }
        else if(rectMenuHelp.contains(x, y)){//点下帮助按钮
            selectedIndex = 1;//设置按下的索引
            status = 4;//设置状态为4,即按下列按钮
        }
        else if(rectMenuQuit.contains(x, y)){//点下退出按钮
            selectedIndex = 2;//设置按下的索引
            status = 4;//设置状态为4,即按下列按钮
        }
        else if(rectSoundMenu.contains(x, y)){//点下了声音菜单按钮
            if(father.wantSound){//按下之前是有声音的
                stopSound(1);//停止声音的播放
            }
            else{//按下之前没声音
                playSound(1, -1);
            }
            father.wantSound = !father.wantSound;//置反
        }


        return true;
    }


public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    // TODO Auto-generated method stub

}

public void surfaceCreated(SurfaceHolder holder) {
    // TODO Auto-generated method stub

}

public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub

}
}

最佳答案

您不会在 Activity 中的WelcomeView中调用initSound,因此执行soundPoolnull仍然是playSound

07-24 12:30