2013-02-25 93 views
1

我一直在閱讀觀察者模式,以保持我的UI是最新的,但我仍然無法讓它工作,據我瞭解,觀察者是我的用戶界面,它看着我的寵物如果有任何變量運行update();在這一刻它什麼都不做,甚至沒有Log.d.Observer實現問題

觀察員/ MainActivity

package com.grim.droidchi; 

import java.util.Observable; 
import java.util.Observer; 

import android.app.Activity; 
import android.app.AlarmManager; 
import android.app.PendingIntent; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.Menu; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.webkit.WebSettings.LayoutAlgorithm; 
import android.webkit.WebView; 
import android.widget.Button; 
import android.widget.TextView; 
import android.widget.Toast; 

public class MainActivity extends Activity implements Observer, OnClickListener { 
    private static final String TAG = "VPET"; 
    private static final String APP_PREFS = "VPET"; 
    private static final int REQUEST_CODE = 1; 

    TextView happiness_display, health_display, hunger_display, level_display; 
    Button PunchPet, UpdateHunger; 
    public static Pet pet = new Renamon(); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     WebView myWebView = (WebView) findViewById(R.id.pet_display); 
     myWebView.loadUrl("file:///android_asset/renamon.gif"); 
     myWebView.setInitialScale(10000); 
     myWebView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); 


     PunchPet = (Button) findViewById(R.id.PunchPet); 
     UpdateHunger = (Button) findViewById(R.id.UpdateHunger); 
     final TextView hunger_display = (TextView) findViewById(R.id.hunger_display); 
     TextView happiness_display = (TextView) findViewById(R.id.happiness_display); 
     TextView level_display = (TextView) findViewById(R.id.level_display); 
     TextView health_display = (TextView) findViewById(R.id.health_display); 

     hunger_display.setText(Integer.toString(pet.getHunger())); 
     health_display.setText(Integer.toString(pet.getHP())); 
     level_display.setText(Integer.toString(pet.getLVL())); 
     happiness_display.setText(Integer.toString(pet.getHappy())); 


     Intent intent = new Intent(this, Gameloop.class); 
     PendingIntent pendingIntent = PendingIntent.getBroadcast(
       getBaseContext(), REQUEST_CODE, intent, 0); 

     AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); 
     alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 
       System.currentTimeMillis() + (5 * 1000), 1800000, pendingIntent); 
     // 1800000 ms = 30 mins 

     pet.feed(); 
     pet.addObserver(this); 
     pet.notifyObservers(pet); 


    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.activity_main, menu); 
     return true; 
    } 

    @Override 
    protected void onPause() { 


     super.onPause(); 
    } 

    @Override 
    public void update(Observable o, Object data) { 
     Toast.makeText(getApplicationContext(), "soemthing has changed", Toast.LENGTH_LONG).show(); 
    } 

    @Override 
    public void onClick(View v) { 
     if (v == PunchPet) { 
      pet.setLVL(50); 
      pet.notifyObservers(pet); 
      Log.d(TAG, "PUNCHPET" + pet.getHP()); 

    }else { 

    } 



    } 

} 

可觀察/寵物

package com.grim.droidchi; 

import java.util.Observable; 


import android.util.Log; 

public class Pet extends Observable implements PetInterface { 

    private static final String TAG = "VPET"; 
    private int Health = 100; 

    private int Happiness = 10; 
    private int Level = 1; 
    private int Hunger = 0; 
    private int Exp = 0; 
    private String Name; 
    private Boolean isAlive = true; 
    private Boolean isSick = false; 

    public void setisAlive(boolean answer) { 
     this.isAlive = answer; 
    } 

    public void setisSick(boolean answer) { 
     this.isAlive = answer; 
    } 

    public void setHP(int hp) { 
     this.Health = hp; 
     notifyObservers(hp); 
    } 

    public void setLVL(int lvl) { 
     this.Level = lvl; 
     notifyObservers(lvl); 
    } 

    public void setXP(int xp) { 
     this.Exp = xp; 
     notifyObservers(xp); 
    } 

    public void setHunger(int hunger) { 
     this.Hunger = hunger; 
     notifyObservers(hunger); 
    } 

    public void setHappy(int happy) { 
     this.Happiness = happy; 
     notifyObservers(happy); 
    } 

    public int getHP() { 

     return Health; 
    } 

    public int getLVL() { 

     return Level; 
    } 

    public int getXP() { 

     return Exp; 
    } 

    public int getHunger() { 

     return Hunger; 
    } 

    public int getHappy() { 

     return Happiness; 
    } 

    public boolean isAlive() { 
     return isAlive; 

    } 

    public boolean isSick() { 
     return isSick; 

    } 

    @Override 
    public void sleep() { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void clean() { 
     // TODO Auto-generated method stub 

    } 

    @Override 
    public void feed() { 
     Log.d(TAG, "FEEDING FROM INTERFACE THING"); 

    } 

    @Override 
    public void passtime() { 

    } 

} 

是的,我問過這也但如你所知,它有兩個答案(這雖然他們也許是對的不要幫助我),不會再接受現在它會下降太多的名單,如果我可以刪除它,我會

Logcat

02-25 22:51:50.381: E/AndroidRuntime(12026): FATAL EXCEPTION: main 
02-25 22:51:50.381: E/AndroidRuntime(12026): java.lang.NullPointerException 
02-25 22:51:50.381: E/AndroidRuntime(12026): at com.grim.droidchi.MainActivity.update(MainActivity.java:93) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at java.util.Observable.notifyObservers(Observable.java:138) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at com.grim.droidchi.Pet.setHP(Pet.java:33) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at com.grim.droidchi.MainActivity$1.onClick(MainActivity.java:47) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at android.view.View.performClick(View.java:4202) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at android.view.View$PerformClick.run(View.java:17340) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at android.os.Handler.handleCallback(Handler.java:725) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at android.os.Handler.dispatchMessage(Handler.java:92) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at android.os.Looper.loop(Looper.java:137) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at android.app.ActivityThread.main(ActivityThread.java:5191) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at java.lang.reflect.Method.invokeNative(Native Method) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at java.lang.reflect.Method.invoke(Method.java:511) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562) 
02-25 22:51:50.381: E/AndroidRuntime(12026): at dalvik.system.NativeStart.main(Native Method) 
+0

您正在使用例如。 'notifyObservers(飢餓)'。這種方法在哪裏? – 2013-02-25 21:03:49

+0

爲什麼你重寫所有的'Observable'方法並試圖自己跟蹤'Observers'? – 2013-02-25 21:08:59

+0

對不起,我不明白你的意思?我必須有一個可變的方法嗎?我認爲這個想法是,如果有什麼改變(無所謂)Observable讓Observer知道,然後Observer可以運行更新,只是用新值「刷新」textview? – Pheonix2105 2013-02-25 21:09:32

回答

2

當您從Observable繼承時,您的類將繼承其所有功能。除非您添加自己的功能,否則您不需要重寫其方法或保留自己的一套Observers。如Bailey S所述,在調用方法中,在致電notifyOservers()之前,請致電setChanged()

嘗試從Observable類中刪除所有已覆蓋的方法。此外,每次撥打notifyObservers(object)後,請致電clearChanged()

+0

我在收到您的建議後再次進行了編輯,幾乎所有我讀過或看過的其他東西都說我必須自己實現這些方法,但它仍然不起作用,但開始變得更有意義,現在更新方法不會被調用。在我的日誌。 – Pheonix2105 2013-02-25 21:56:07

+0

爲了澄清我還沒有真正想到這一點(幫助仍然很好,但不會責怪你,如果你跑了),但我已經接受你的答案,因爲你是最有幫助和最不敵意的,我真的很感激。 – Pheonix2105 2013-02-25 21:57:11

+0

它可能與您的'PunchPet'視圖和'onClick'方法有關,因爲Observer-Observable設置正確。 – 2013-02-25 22:06:33

2

問題是您已覆蓋notifyObservers(),但不是notifyObservers(java.lang.Object)。你打電話給後者,但你沒有定義它。

@Override 
    public void notifyObservers(Object o) { 
     observers.notify(o); 
     super.notifyObservers(o); 
    } 

此外,您內部可能會更改值,但Observer不知道。在你的「寵物」(Observable)上致電setChanged()來解決這個問題。

+0

目前還不清楚爲什麼他會覆蓋它或其中的任何一個,實際上。我甚至沒有想到要看/注意它。 – 2013-02-25 21:07:29

1

問題是notifyObservers()方法什麼也不做,除非先前調用setChanged()。這並不直觀,因爲它似乎應該總是通知觀察者,但事實並非如此。不需要使用clearChagned()方法,因爲notifyObervers()也會清除已更改的標誌。使用這樣的代碼中getter和setter方法:

public void setHP(int hp) { 
    this.Health = hp; 
    setChanged(); 
    notifyObservers(hp); 
} 

此外,不要覆蓋Observable的方法,你只需要實施在接口`觀測方法。

您的update()方法需要做些什麼。這是一些非常簡單的示例代碼。其中,Observable對象和數據被忽略,因爲你已經知道它是什麼對象,並且我們只是更新所有的字段。

@Override 
public void update(Observable o, Object data) { 
    Toast.makeText(getApplicationContext(), "soemthing has changed",Toast.LENGTH_LONG).show(); 

    //Update the GUI fields with values from the local pet object. 
    hunger_display.setText(Integer.toString(pet.getHunger())); 
    health_display.setText(Integer.toString(pet.getHP())); 
    level_display.setText(Integer.toString(pet.getLVL())); 
    happiness_display.setText(Integer.toString(pet.getHappy())); 

} 

onCreate()需要正確初始化實例變量。

onCreate() { 
    ... 

    hunger_display = (TextView) findViewById(R.id.hunger_display); 
    happiness_display = (TextView) findViewById(R.id.happiness_display); 
    level_display = (TextView) findViewById(R.id.level_display); 
    health_display = (TextView) findViewById(R.id.health_display); 

    ... 
} 

換句話說,你需要刪除TextView聲明,因爲他們正在創造新的變量,而不是設置你真的想設置的。

+0

嗨貝利謝謝你回答,甚至在我接受了真正的感謝之後。我再次更改了代碼,包括setChanged();到setter(我應該也做getters?似乎不應該,因爲他們只是檢索一個值,而不是改變它?)我用了一個匿名類的按鈕,它現在的作品,但價值arn't不更新?例如,我把pet.setLVL(50);進入按鈕的onclick它告訴我更新方法正在運行,但值不會改變? – Pheonix2105 2013-02-25 22:24:26

+0

沒有理由在獲取方法中通知觀察者,事實上,當經常調用getter時,這會對性能產生可怕的影響。 'update()'方法中沒有更新,因爲除了打印到終端之外,您還沒有在其中放置任何內容。你需要在'update()'中做一些事情。 Observer/Observable非常簡單,不會爲你做任何「魔術」。我將在我的答案中添加一個'update()'樣例。 – 2013-02-25 22:38:59

+0

有「\t hunger_display.setText(Integer.toString(pet.getHunger()));」在我的更新中,但它導致應用程序崩潰,所以我刪除它。精確地拋出一個空指針異常。 – Pheonix2105 2013-02-25 22:43:13