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 Activity
s et un Service
, définis comme suit:
-
Service ProgressService
gère plusieursProgressBar
s en cours d'exécution simultanément sur les threads parallèles. -
Activity WorkScreen2
crée un jeu de tâches, commence laService
avecstartService()
avec les paramètres de la tâche passé dans unBundle
. -
Activity ProgressScreen
se lie à laService
d'obtenir et d'afficher leProgressBar
s) de l'exécution des tâches. -
À la fois à des activités exécutées en vertu de séparer
TabHost
s d'unTabActivity
.
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
Vous devez vous connecter pour publier un commentaire.
ServiceConnection de onServiceConnected() est appelé, mais personne ne peut garantir qu'il sera appelé avant onCreate continue l'exécution. Donc, ce qui se passe ici - vous réussi à lier le service (c'est pourquoi onBind renvoie true (vrai), mais vous n'êtes pas entièrement connecté - onServiceConnected() n'a pas encore été appelé, alors votre local mProgressService objet n'est pas encore initalized, et, par conséquent, vous obtenez la NullPointerException.
Solution:
Déplacer ces deux lignes:
de onCreate() de onServiceConnected() fonction (utilisation de l'objet de service après il est initialisé dans onServiceConnected()).
Seconde. J'ai été dicking autour de cette toute la nuit et ce, enfin, de relever de l'évidence. Merci!
OriginalL'auteur Milan Krstic
Vérifier AndroidManifest.xml de la vôtre et ajouter le service que vous avez essayé de lier.
Service
élément 'AndroidManifest.xml" pour leService
je suis en train de créer une liaison. La liaison est réussie, depuisbindService()
retournetrue
.Je ne pouvais pas vous remercier plus M. Oldtimer : )
OriginalL'auteur oldtimer
Vous devez retourner votre Classeur intérieur de la classe de
OriginalL'auteur Chathuranga Rathnayake