问题
First of all I've tried searching for this ans was unsuccessful. If my question is out there already answered could someone please point me to it? Thank you very much for either helping me here by looking at this, or even by skimming this and pointing me in the right direction. I really do appreciate it!
My dilemma: I have an activity, and in that activity there is listview. The listview has multiple items inside it that most need to call an AlertDialog. The AlertDialog calls a service that says, "Hey, you need to update some data." The Service listens and does the update successfully.
The problem that comes into play is that my activity doesn't acknowledge the service. What I'm wondering about is that I'm don't fully understand how a Service operates, and if you can have the same service spun up / running more than once.
Note, my example ties somewhat to the idea on The Android Dev Reference for Service.
The Example:
public class MyActivity extends Activity implements IMainActivity
{
ListView _list;
private RefreshConnector _serviceConnector;
private boolean _isBound;
public MyActivity () {}
public fillList()
{
//this won't trigger within the service
}
private void doBindService()
{
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
getApplicationContext().bindService(new Intent(this, UpdateScheduleService.class), _serviceConnector, BIND_AUTO_CREATE);
_isBound= true;
}
private void doUnbindService()
{
if (_isScheduleBound)
{
// Detach our existing connection.
getApplicationContext().unbindService(_serviceConnector);
_isBound= false;
}
}
@Override
protected void onDestroy()
{
super.onDestroy();
doUnbindService();
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
_isBound= false;
_list = (ListView) findViewById(R.id.TheList);
_list.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id)
{
if (view != null)
{
CheckBox selectedFlag = (CheckBox) view.findViewById(R.id.selectedItem);
selectedFlag.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
doBindService();
Bundle extras = new Bundle();
extras.putBoolean(BundleLocations.BUNDLE_ENABLED, ((CheckBox) view).isChecked());
extras.putLong(BundleLocations.BUNDLE_SCHEDULE_ID, 123); //123 is an example of an id being passed
extras.putString(BundleLocations.ACTION, BundleLocations.ACTION_SELECTED);
Intent updateSelection = new Intent("ChangeItems");
updateSelection.putExtras(extras);
view.getContext().startService(updateSelection);
}
});
TextView description = (TextView) view.findViewById(R.id.description);
description.setText(s.getDescription());
description.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
doBindService();
ChangeDescriptionDialog dia = new ChangeDescriptionDialog(view.getContext());
dia.setTitle(view.getContext().getResources().getString(R.string.DESCRIPTION_TITLE));
dia.setAction(BundleLocations.ACTION_DESCRIPTION);
dia.setDescription("something new"); //simplified for example...
dia.create();
dia.show();
}
});
}
}
};
}
RefreshConnector :
public class RefreshConnector implements ServiceConnection
{
private UpdateService service;
public IMainActivity getActivity()
{
return activity;
}
public void setActivity(IMainActivity value)
{
this.activity = value;
}
public UpdateScheduleService getService()
{
return service;
}
private IMainActivity activity;
public void onServiceConnected(ComponentName componentName, IBinder iBinder)
{
service = ((UpdateService.UpdateBinder)iBinder).getService();
if(activity != null)
activity.fillList();
}
public void onServiceDisconnected(ComponentName componentName)
{
service = null;
}
}
The UpdateService
public class UpdateService extends Service
{
final public IBinder binder = new UpdateBinder();
@Override
public IBinder onBind(Intent intent)
{
return binder;
}
public class UpdateBinderextends Binder
{
public UpdateService getService()
{
return UpdateService .this;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
if (intent == null)
{
stopSelf();
return START_STICKY;
}
if(action.equals(BundleLocations.ACTION_SELECTED))
{
long id = intent.getExtras().getLong(BundleLocations.BUNDLE_ID);
boolean enabled = intent.getExtras().getBoolean(BundleLocations.BUNDLE_ENABLED);
if(id < 0 )
{
return START_STICKY;
}
String item = intent.getExtras().getString(BundleLocations.BUNDLE_ITEM);
if (item == null || action.equals("")) return START_STICKY;
//do some work with saving the description, which it does
return START_STICKY;
}
return START_STICKY;
}
@Override
public void onDestroy()
{
super.onDestroy();
}
}
DescriptionDialog truncated (constructor), Also, this is extended from the AlertDialog.Builder class. I also have a class that is common in all dialogs where basically I store the _context. So in the case here, the context is saved in the super. The _context is protected ...
public ChangeDescriptionDialog(Context context)
{
super(context);
DialogInterface.OnClickListener onClickListenerPositive = new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
//dispatch change
Intent ChangeItems = new Intent("ChangeItems");
Bundle extras = new Bundle();
extras.putParcelable(BundleLocations.BUNDLE_ITEM, _description);
extras.putString(BundleLocations.ACTION, _action);
ChangeItems.putExtras(extras);
//
// my question is partly here
// I start this service...
//
// How would my activity see it... right now it doesn't seem that way even though I do the binding before this call
//
_context.startService(ChangeItems);
}
};
this.setPositiveButton(context.getResources().getString(R.string.DIALOG_POS), onClickListenerPositive);
}
Again, notice the binding that takes place before the popup occurs. 2nd, notice me starting the service in the binding. What am I doing wrong or just not getting?
Thank you all again, Kelly
回答1:
There is a much easier way to do what you want to do that does not require bound services.
First, you should probably extend IntentService instead of Service. This will ensure that your service does not run on the UI thread. You would start the service via an intent the same way you are currently.
Second, in your service implementation, it is much easier to send a broadcast message to indicate that you are done than to try using a BoundService. So in your service you would do something like:
Intent intent = new Intent(); // specify the intent filter appropriately here
sendBroadcast(intent);
Then, in your activity you would want to register a BroadcastReciever that would be notified of these changes. See the BroadcastReceiver doc for more details.
来源:https://stackoverflow.com/questions/7779401/starting-a-service-in-an-alertdialog-and-have-an-outside-activity-bound-to-it