ServiceConnection.onServiceConnected()绑定到开始服务之后,从来没有所谓的 [英] ServiceConnection.onServiceConnected() never called after binding to started service
问题描述
在游戏应用我有以下情形:
- 从主游戏
活动
,播放器开始,在与时间长短不一后台运行多个游戏任务。 - 玩家应该能够查看在一个单独的
查看
的运行游戏的任务的进度。
要做到这一点,我创建了两个活动
和一个服务
,定义如下:
-
服务ProgressService
处理几个进度
S上并行线程同时运行。 -
活动WorkScreen2
创建一个游戏任务,启动服务
与startService ()
在传递任务参数捆绑
。 -
活动ProgressScreen
绑定到服务
来获取和显示进度
S的正在运行的任务。 -
在单独运行这两项活动
李>TabHost
取值一个TabActivity
。
我遇到的问题是, ServiceConnection.onServiceConnected()
方法不会被调用。我得到一个显示java.lang.NullPointerException
,因为我尝试调用服务
对象应在指定的方法此方法。见下面code。
我用 getApplicationContext()。bindService()
绑定活动
到服务
,因为 则tabspec
无法绑定到服务
。这个方法返回真
。因此,绑定成功
下面是服务
:
公共类ProgressService扩展服务实现GameConstants {
公共静态最后弦乐BROADCAST_PROGRESS =com.mycompany.android.mygame.progressbroadcast;
私有静态最后长的更新周期= 500;
私人的IBinder mBinder;
私人名单,其中,进度> mProgressBarList;
私人列表<字符串> mStaffNameList;
私人final类ServiceHandler扩展处理程序{
公共ServiceHandler(活套活套){
超(活套);
}
@覆盖
公共无效的handleMessage(信息MSG){
进度进度=新进度(ProgressService.this);
mProgressBarList.add(进度);
束束= msg.getData();
字符串staffName = bundle.getString(WorkScreen2.STAFF_NAME);
mStaffNameList.add(staffName);
INT taskDurationMillis = bundle.getInt(WorkScreen2.TASK_DURATION)* 1000;
progressBar.setMax(taskDurationMillis / 1000);
长startTimeMillis = SystemClock.uptimeMillis();
长elapsedTimeMillis = SystemClock.uptimeMillis()
- startTimeMillis;
意向意图=新的意图();
intent.setAction(BROADCAST_PROGRESS);
而(elapsedTimeMillis< taskDurationMillis){
尝试 {
视频下载(更新周期);
}赶上(InterruptedException异常E){
e.printStackTrace();
}
elapsedTimeMillis = SystemClock.uptimeMillis()
- startTimeMillis;
INT elapsedTimeSeconds =(int)的elapsedTimeMillis / 1000;
progressBar.setProgress(elapsedTimeSeconds);
sendBroadcast(意向);
}
progressBar.setVisibility(View.GONE);
mProgressBarList.remove(进度);
mStaffNameList.remove(staffName);
sendBroadcast(意向);
如果(mProgressBarList.isEmpty()){
stopSelf(msg.arg1);
}
}
}
@覆盖
公共无效的onCreate(){
super.onCreate();
mBinder =新ProgressServiceBinder();
mProgressBarList =集合
.synchronizedList(新的ArrayList&其中;进度>());
mStaffNameList = Collections.synchronizedList(新的ArrayList&其中;字符串>());
}
/ *
*创建每场比赛的任务一个线程在传递的参数
*< code>的意图< / code取代;
* /
@覆盖
公众诠释onStartCommand(意向意图,诠释标志,诠释startId){
Toast.makeText(这一点,启动服务,Toast.LENGTH_LONG).show();
HandlerThread线程=新HandlerThread(ServiceStartArguments
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
处理器serviceHandler =新ServiceHandler(thread.getLooper());
消息味精= serviceHandler.obtainMessage();
msg.arg1 = startId;
msg.setData(intent.getExtras());
serviceHandler.sendMessage(MSG);
返回START_STICKY;
}
@覆盖
公众的IBinder onBind(意向意图){
返回mBinder;
}
公共类ProgressServiceBinder扩展粘合剂{
ProgressService的getService(){
返回ProgressService.this;
}
}
公开名单<进度> getProgressBarList(){
返回mProgressBarList;
}
公开名单<字符串> getStaffNameList(){
返回mStaffNameList;
}
@覆盖
公共无效的onDestroy(){
Toast.makeText(这一点,做服务,Toast.LENGTH_SHORT).show();
}
}
这是活动
绑定到它:
公共类ProgressScreen扩展ListActivity {
私人最终字符串变量=ProgressScreen;
私人ProgressScreenAdapter mAdapter;
私人ProgressService mProgressService;
私人名单,其中,进度> mProgressBarList;
私人列表<字符串> mStaffNameList;
@覆盖
公共无效的onCreate(束捆){
Log.i(TAG,ProgressScreen的OnCreate);
super.onCreate(包);
的setContentView(R.layout.progress_screen_layout);
IntentFilter的过滤器=新的IntentFilter();
filter.addAction(ProgressService.BROADCAST_PROGRESS);
registerReceiver(接收机,过滤器);
doBindService();
mAdapter =新ProgressScreenAdapter(这一点,mStaffNameList,mProgressBarList);
setListAdapter(mAdapter); //返回true
/ *
*这是我得到的NullPointerException异常
* mProgressService为null这里
* /
mProgressBarList = mProgressService.getProgressBarList();
mStaffNameList = mProgressService.getStaffNameList();
}
@覆盖
保护无效onResume(){
super.onResume();
IntentFilter的过滤器=新的IntentFilter();
filter.addAction(ProgressService.BROADCAST_PROGRESS);
registerReceiver(接收机,过滤器);
}
@覆盖
保护无效的onPause(){
super.onPause();
unregisterReceiver(接收机);
}
布尔doBindService(){
。返回getApplicationContext()bindService(新意图(这一点,ProgressService.class),mConnection,Context.BIND_AUTO_CREATE);
}
无效doUnbindService(){
。getApplicationContext()unbindService(mConnection);
}
ServiceConnection mConnection =新ServiceConnection(){
公共无效onServiceConnected(组件名的className,粘合剂的IBinder){
mProgressService =((ProgressService.ProgressServiceBinder)粘合剂).getService();
Toast.makeText(ProgressScreen.this,连接到ProgressService,Toast.LENGTH_SHORT).show();
}
公共无效onServiceDisconnected(组件名名){
mProgressService = NULL;
}
};
私人BroadcastReceiver的接收器=新的BroadcastReceiver(){
@覆盖
公共无效的onReceive(上下文的背景下,意图意图){
mAdapter.notifyDataSetChanged();
}
};
}
而服务
从主活动开始
如下:
意向意图=新的意图(WorkScreen2.this,ProgressService.class);
intent.putExtra(TASK_DURATION,task.getDuration());
intent.putExtra(STAFF_NAME,staff.getName());
startService(意向);
在的AndroidManifest.xml
包含
<服务
机器人:名称=。ProgressService
机器人:标签=@字符串/ progress_service>
< /服务>
ServiceConnection的onServiceConnected()叫,但没有人可以保证,这将是一个名为之前的onCreate继续执行。因此,这里发生的事情 - 你successfuly绑定到该服务(这就是为什么onBind返回true),但是你不能的完全连接的 - onServiceConnected()尚未被调用,所以当地的mProgressService对象尚未initalized,所以你得到的NullPointerException异常。
解决方法:
将以下两行:
mProgressBarList = mProgressService.getProgressBarList();
mStaffNameList = mProgressService.getStaffNameList();
从的onCreate()来onServiceConnected()函数(使用服务对象的在它是在onServiceConnected初始化())。
In a game application I have the following scenario:
- From the main game
Activity
, the player starts several game tasks that run in the background with varying duration. - The player should be able to view the progress of the running game tasks in a separate
View
.
To do this, I created two Activity
s and a Service
, defined as follows:
Service ProgressService
handles severalProgressBar
s running simultaneously on parallel threads.Activity WorkScreen2
creates a game task, starts theService
withstartService()
with task parameters passed in aBundle
.Activity ProgressScreen
binds to theService
to get and display theProgressBar
s of the running tasks.Both activities run under separate
TabHost
s of oneTabActivity
.
The problem I'm having is that the ServiceConnection.onServiceConnected()
method is never called. I get a Java.lang.NullPointerException
because I try to call a method of the Service
object that should be assigned in this method. See code below.
I use getApplicationContext().bindService()
to bind the Activity
to the Service
because TabSpec
cannot bind to Services
. This method returns true
. Therefore, binding is successful.
Here is the Service
:
public class ProgressService extends Service implements GameConstants {
public static final String BROADCAST_PROGRESS = "com.mycompany.android.mygame.progressbroadcast";
private static final long UPDATE_INTERVAL = 500;
private IBinder mBinder;
private List<ProgressBar> mProgressBarList;
private List<String> mStaffNameList;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
ProgressBar progressBar = new ProgressBar(ProgressService.this);
mProgressBarList.add(progressBar);
Bundle bundle = msg.getData();
String staffName = bundle.getString(WorkScreen2.STAFF_NAME);
mStaffNameList.add(staffName);
int taskDurationMillis = bundle.getInt(WorkScreen2.TASK_DURATION) * 1000;
progressBar.setMax(taskDurationMillis / 1000);
long startTimeMillis = SystemClock.uptimeMillis();
long elapsedTimeMillis = SystemClock.uptimeMillis()
- startTimeMillis;
Intent intent = new Intent();
intent.setAction(BROADCAST_PROGRESS);
while (elapsedTimeMillis < taskDurationMillis) {
try {
Thread.sleep(UPDATE_INTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
elapsedTimeMillis = SystemClock.uptimeMillis()
- startTimeMillis;
int elapsedTimeSeconds = (int) elapsedTimeMillis / 1000;
progressBar.setProgress(elapsedTimeSeconds);
sendBroadcast(intent);
}
progressBar.setVisibility(View.GONE);
mProgressBarList.remove(progressBar);
mStaffNameList.remove(staffName);
sendBroadcast(intent);
if (mProgressBarList.isEmpty()) {
stopSelf(msg.arg1);
}
}
}
@Override
public void onCreate() {
super.onCreate();
mBinder = new ProgressServiceBinder();
mProgressBarList = Collections
.synchronizedList(new ArrayList<ProgressBar>());
mStaffNameList = Collections.synchronizedList(new ArrayList<String>());
}
/*
* Creates a thread for each game task with parameters passed in
* <code>intent</code>
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "starting service", Toast.LENGTH_LONG).show();
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
Handler serviceHandler = new ServiceHandler(thread.getLooper());
Message msg = serviceHandler.obtainMessage();
msg.arg1 = startId;
msg.setData(intent.getExtras());
serviceHandler.sendMessage(msg);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class ProgressServiceBinder extends Binder {
ProgressService getService() {
return ProgressService.this;
}
}
public List<ProgressBar> getProgressBarList() {
return mProgressBarList;
}
public List<String> getStaffNameList() {
return mStaffNameList;
}
@Override
public void onDestroy() {
Toast.makeText(this, "Service done", Toast.LENGTH_SHORT).show();
}
}
And this is the Activity
that binds to it:
public class ProgressScreen extends ListActivity {
private final String TAG = "ProgressScreen";
private ProgressScreenAdapter mAdapter;
private ProgressService mProgressService;
private List<ProgressBar> mProgressBarList;
private List<String> mStaffNameList;
@Override
public void onCreate(Bundle bundle) {
Log.i(TAG, "ProgressScreen oncreate");
super.onCreate(bundle);
setContentView(R.layout.progress_screen_layout);
IntentFilter filter = new IntentFilter();
filter.addAction(ProgressService.BROADCAST_PROGRESS);
registerReceiver(receiver, filter);
doBindService();
mAdapter = new ProgressScreenAdapter(this, mStaffNameList, mProgressBarList);
setListAdapter(mAdapter); // Returns true
/*
* This is where I get the NullPointerException
* mProgressService is null here
*/
mProgressBarList = mProgressService.getProgressBarList();
mStaffNameList = mProgressService.getStaffNameList();
}
@Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(ProgressService.BROADCAST_PROGRESS);
registerReceiver(receiver, filter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
boolean doBindService() {
return getApplicationContext().bindService(new Intent(this, ProgressService.class), mConnection, Context.BIND_AUTO_CREATE);
}
void doUnbindService() {
getApplicationContext().unbindService(mConnection);
}
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
mProgressService = ((ProgressService.ProgressServiceBinder) binder).getService();
Toast.makeText(ProgressScreen.this, "Connected to ProgressService", Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName name) {
mProgressService = null;
}
};
private BroadcastReceiver receiver = new BroadcastReceiver () {
@Override
public void onReceive(Context context, Intent intent) {
mAdapter.notifyDataSetChanged();
}
};
}
And the Service
is started from the main Activity
as follows:
Intent intent = new Intent(WorkScreen2.this, ProgressService.class);
intent.putExtra(TASK_DURATION, task.getDuration());
intent.putExtra(STAFF_NAME, staff.getName());
startService(intent);
The AndroidManifest.xml
contains
<service
android:name=".ProgressService"
android:label="@string/progress_service">
</service>
ServiceConnection's onServiceConnected() is called, but nobody guarantees that it will be called before onCreate continues execution. So, what happens here - you successfuly bind to the service (that's why onBind returns true), but you're not fully connected - onServiceConnected() has not yet been called, so your local mProgressService object is not yet initalized, and therefore you get the NullPointerException.
Solution:
Move these two lines:
mProgressBarList = mProgressService.getProgressBarList();
mStaffNameList = mProgressService.getStaffNameList();
from onCreate() to onServiceConnected() function (use the service object after it is initialized in onServiceConnected()).
这篇关于ServiceConnection.onServiceConnected()绑定到开始服务之后,从来没有所谓的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!