ServiceConnection.onServiceConnected() ne s'est jamais appelé après la liaison de service démarré

Dans une application de jeu, j'ai le scénario suivant:

  • À partir de l'écran de jeu principal Activity, le joueur commence le jeu de plusieurs tâches qui s'exécutent en arrière-plan avec des durées variables.
  • Le joueur doit être en mesure de voir l'état d'avancement de l'exécution de tâches de jeu dans un autre View.

Pour ce faire, j'ai créé deux Activitys et un Service, définis comme suit:

  • Service ProgressService gère plusieurs ProgressBars en cours d'exécution simultanément sur les threads parallèles.

  • Activity WorkScreen2 crée un jeu de tâches, commence la Service avec startService() avec les paramètres de la tâche passé dans un Bundle.

  • Activity ProgressScreen se lie à la Service d'obtenir et d'afficher le ProgressBars) de l'exécution des tâches.

  • À la fois à des activités exécutées en vertu de séparer TabHosts d'un TabActivity.


Le problème, je vais avoir, c'est que le ServiceConnection.onServiceConnected() méthode n'est jamais appelé. Je reçois un Java.lang.NullPointerException parce que j'essaie d'appeler une méthode de la Service objet qui doit être attribué à cette méthode. Voir le code ci-dessous.

- Je utiliser getApplicationContext().bindService() de lier la Activity à la Service parce que TabSpec ne peut pas se lier à Services. Cette méthode retourne true. Par conséquent, la liaison est réussie.


Ici est la 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();
}
}

Et c'est le Activity qui se lie à elle:

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();
}
};
}

Et la Service est démarré à partir de la principale Activity comme suit:

Intent intent = new Intent(WorkScreen2.this, ProgressService.class);
intent.putExtra(TASK_DURATION, task.getDuration());
intent.putExtra(STAFF_NAME, staff.getName());
startService(intent);

La AndroidManifest.xml contient

<service
android:name=".ProgressService"
android:label="@string/progress_service">
</service>

OriginalL'auteur Wesam | 2012-02-12