我面临以下问题:
public class StatCounterService extends Service {
private TimerTask updateTask_ref = new TimerTask() {
//Get the element by Id as common practice in Android
TextView hungerValue_ref = (TextView)layout.findViewById(R.id.hungerValue);
@Override
public void run() {
//Every X Seconds, the Tamagotchi loses Hunger Points
int hunger = (int) (getHunger()-1);
//Updating Model (DataBase)
updateHunger(hunger);
//Now I want to update the TextView, but this hungerValue is Null
hungerValue_ref.setText(new Long(getHunger()).toString());
}
};
}
我认为问题是,我在服务中查找View的ID,也在嵌套的Class(timertask)中查找。服务正在运行,我只是在“hungerValue”上得到一个nullpointer。任何想法我怎么能解决这个问题? 非常感谢! 丹尼尔
编辑:我现在尝试从活动中更新Timer中的视图,这是想法:
public class MainWindowActivity extends Activity {
Timer timer_ref;
TextView hungerValue_ref;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Change the View I want to change initally (getting Value from Database)
updateHungerView();
//Start Timer
timer_ref = new Timer("StatCounterTimer");
timer_ref.schedule(updateTask_ref, 1000L, 10000L);
}
//The Timer from within I want to change the View every X seconds
private TimerTask updateTask_ref = new TimerTask() {
@Override
public void run() {
//Line Throws Exception, see Method below
updateHungerView();
}
};
/**
* Important Part
*/
public void updateHungerView() {
hungerValue_ref = (TextView) findViewById(R.id.hungerValue);
hungerValue_ref.setText(new Long(getHunger()).toString());
}
当我尝试从我的活动中更改视图时,我明白了:
09-30 11:54:48.967: ERROR/AndroidRuntime(30476): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
答案 0 :(得分:2)
您正尝试从服务内部处理布局的组件部分,但您只能使用相关活动内部的布局。该服务在执行其代码时不知道活动是否在顶部 - 活动实例可能甚至还不存在。
允许服务使显示更新的最佳方法是从服务广播一个Intent:
Intent intent = new Intent();
intent.setAction("my.intent.action.name");
sendBroadcast(intent);
然后,在Activity中,创建一个BroadcastReceiver实例来处理意图。
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("my.intent.action.name")) {
// do something with the UI here
}
}
};
您还需要在onResume()方法中注册广播接收器:
IntentFilter filter = new IntentFilter("my.intent.action.name");
registerReceiver(receiver, filter);
在onPause()方法中取消注册:
unregisterReceiver(receiver);
您不能为BroadcastReceiver实例使用静态内部类,因为它无法执行以下操作:
MyActivity.this.getContext()
或
MyActivity.this.findViewById(R.id.my_ui_component)
希望有所帮助!
答案 1 :(得分:1)
考虑使用AsyncTask而不是Service。由于您无法在后台更新UI http://developer.android.com/reference/android/os/AsyncTask.html
答案 2 :(得分:1)
我认为这是android的常见问题。 findViewById是相对于布局的,如果我记得很清楚,必须在setContentView之后调用。这可以帮到你:
http://www.anddev.org/solved_why_does_findviewbyid_return_null-t557.html
答案 3 :(得分:1)
对我而言,您似乎正在尝试查找并更新可能无法显示/膨胀的TextView(例如,它的持有活动已被销毁/停止/暂停)。
我猜你想要使用某项服务,因为它可以继续运行,即使你的应用程序被推到后台或被杀死。我认为,在您的情况下,您的设计可能会更改。
而不是让服务正在运行 - 只要您的应用暂停(在可见活动的onPause()
- 方法中),就会保存时间戳。然后,当用户恢复应用程序(将调用onResume
- 方法)时,您将计算先前保存的时间戳与当前时间之间的时间,并根据此值减少hp值。然后从保留活动更新TextView。
您还可以考虑使用AsyncTask - 如果hpvalue仅在应用程序处于活动状态时需要更新。