I am working on adding in-app billing and working from this official documentation
And I am on the section Binding to IInAppBillingService
Here is my code:
public class CommunityActivity extends BaseActivity implements ServiceConnection
{
ArrayAdapter<ChatMessage> adapter;
Dialog dialog;
ArrayList<ChatMessage> chat = new ArrayList <ChatMessage>( );
IInAppBillingService mService;
ServiceConnection mServiceConn = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
#Override
public void onServiceConnected(ComponentName name,
IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
FlurryAgent.onStartSession(this, "8CA5LTZ5M73EG8R35SXG");
setContentView(R.layout.community);
bindService(new
Intent("com.android.vending.billing.InAppBillingService.BIND"),
mServiceConn, Context.BIND_AUTO_CREATE);
But I get compile errors saying I have to implement the onServiceConnected and onServiceDisconnected methods. But I thought I already added them in a way that the example suggested.
Where did I go wrong here? Thanks!
The error is because you have declared your class as follows
public class CommunityActivity extends BaseActivity implements ServiceConnection
now compiler expects that u have these two functions onServiceConnected and on ServiceDisconnected implemented in CommunityActivity. but it cannot find them in this class.
remove this implements ServiceConnection and code should compile successfully.
Related
I have question about binding service. I am having parent activity and several fragments, i am binding and unbinding service with activity,now can i get access to that service in fragment? I need to use ServiceConnection in Fragments.
Yes, you could access services of parent activity inside your fragments by something like this :
getActivity().getMyService()
===========in you activity=================
callbackFragmentServiceConnection callbackfragment;
public interface callbackFragmentServiceConnection{
public void servicefun(MusicPlayService musicPlayService);
}
public void registerClientFragment(Fragment fragment){
this.callbackfragment = (callbackFragmentServiceConnection)fragment;
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
mBound = true;
callbackfragment.servicefun(musicPlayService);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
=================in your fragment=============
public class FragmentLibraryTrack extends Fragment implements
MainActivity.callbackFragmentServiceConnection {
MainActivity mainActivity;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mainActivity= (MainActivity) context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mainActivity.registerClientFragment(this);
}
#Override
public void servicefun(MusicPlayService musicPlayService) {
Log.e("reached sucessfully","yes");
}
}
In the reference application, RegionBootstrap is initialised in a custom application class on it's onCreate method and of course, the application class is called before any activity is called.
Is there a way to initialise RegionBootstrap inside an activity? I already tried making a static variable of RegionBootstrap so i can call it in a different activity, but unfortunately, it doesn't work.
BeaconApplication.regionBootstrap = new RegionBootstrap((BootstrapNotifier) this.getApplication(), downloadedBeacons);
The Regions I needed to be initialised will come from a server, so initialisation of RegionBootstrap must not come from the application class.
* EDIT *
public class LoginActivity extends ActionBarActivity {
…
/*** short version ***/
#Override
protected void onCreate(Bundle savedInstanceState) {
/*** after successful login ***/
BeaconApplication.beacons = downloadBeaconsFromServer();
}
}
public class BeaconActivity extends ActionBarActivity {
…
#Override
protected void onCreate(Bundle savedInstanceState) {
…
startService(new Intent(this, BeaconService.class));
}
}
This is where I implemented BeaconConsumer
public class BeaconService extends Service implements BeaconConsumer {
private BeaconManager beaconManager;
private BeaconNotifier beaconNotifier;
private RegionBootstrap regionBootstrap;
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setBackgroundBetweenScanPeriod(1001);
beaconManager.setBackgroundScanPeriod(101);
beaconManager.setForegroundScanPeriod(101);
beaconManager.setForegroundBetweenScanPeriod(1001);
beaconNotifier = new BeaconNotifier(this);
beaconManager.bind(this);
}
#Override
public void onBeaconServiceConnect() {
beaconManager.setMonitorNotifier(beaconNotifier);
monitorBeacons();
regionBootstrap = new RegionBootstrap(beaconNotifier, BeaconApplication.beacons);
}
private void monitorBeacons() {
for (Region beacon : BeaconApplication.beacons) {
try {
Log.i(TAG, "Monitoring beacon " + beacon.getUniqueId());
beaconManager.startMonitoringBeaconsInRegion(beacon);
} catch (RemoteException e) {
Log.e(TAG, "Monitoring beacon failed");
e.printStackTrace();
}
}
}
}
Implementation of BeaconNotifier
public class BeaconNotifier implements BootstrapNotifier {
private Context context;
public BeaconNotifier(Context context) {
this.context = context;
}
#Override
didEnter.. etc
#Override
public Context getApplicationContext() {
return context;
}
}
You can use:
BeaconManager.setMonitorNotifier(MonitorNotifier);
BeaconManager.startMonitoringBeaconsInRegion(Region);
But do not forget, in order to use BeaconManager methods, you have to wait until BeaconService is connected. Be aware, with this methods, you need to create your own service if you want to monitor beacons even if app is killed.
Btw, I remember, once I have also faced a problem with RegionBootstrap. I used a trick to handle that problem. Can you test following code?
...
BeaconManager.bind(yourConsumer);
...
//wait until BeaconConsumer.onBeaconServiceConnect() is called
//write following code inside of onBeaconServiceConnect
RegionBootstrap dummy = new RegionBootstrap(mBootstrapNotifier, new Region("dummy", null, null, null));
dummy.disable();
//after this point you can create your own RegionBootstrap
There is a key point in here, you need to create your own BootstrapNotifier. If you are doing this in an activity, you can do this:
public class YourActivity extends Activity implements BootstrapNotifier {
...
BootstrapNotifier mBootstrapNotifier = this;
...
Or in an Application class:
public class YourApp extends Application implements BootstrapNotifier {
...
BootstrapNotifier mBootstrapNotifier = this;
...
In my case, I have created an adapter and that adapter requires Contextin its constructor and I have used that adapter as BootstrapNotifier:
public class AltBeaconAdapter implements BootstrapNotifier {
private Context mContext;
...
public AltBeaconAdapter(Context context) {
mContext = context;
...
}
#Override
public Context getApplicationContext() {
return mContext;
}
...
}
Also, you have to implement MonitorNotifier methods since BootstrapNotifier is a sub class of MonitorNotifier.
Yes, this trick is weird and it shows there is an error in the library with initializing RegionBootstrap but I have service so I switched to first method that I proposed to you. If this trick works for you too, let me know so that I can create an issue on the library's GitHub page.
I'm trying to access sqlite DB (that is filled on diffrent part of the package) on AIDL stub implementation but - there is no context there. how can I get the context?
there are 2 projects (applications) - A,B.
Project A contains keeps records on sqlite DB. and contains aidl service.
Project B needs to ask project A (diffrent package, there can be many projects like B) if a record exists. the only way for project A to answer project B from the stub is to check the DB is to have a Context (the "?????" in the code below) - how can I get the project A's context from the stub?
The AIDL's implementation:
public class IRecordServiceImpl extends IRecordService.Stub{
#Override
public boolean RecordExists(String recordKey)
throws RemoteException {
boolean returnValue = false;
RecordDataSource rds = new RecordDataSource(??????);
rds.Open();
returnValue = rds.isRecordExists(recordKey);
rds.Close();
return returnValue;
}
}
The Service code:
public class IRecordService extends Service {
private IRecordServiceImpl service;
#Override
public void onCreate() {
super.onCreate();
this.service = new IRecordServiceImpl();
}
#Override
public IBinder onBind(Intent intent) {
return this.service;
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Thanks!
Problem solved - you can pass the Service's Context via the constructor and keep it in IRecordServiceImpl as private field
I have a service that I'm trying to unit test using ServiceTestCase. In my setUp(), I'm creating the IBinder, but I get a NullPointerException when creating the intent. I'm using the application's context and setting it to the test case, but the package name seems to be null. Any ideas as to why it's doing this and what the solution might be?
ServiceTestCase Code:
public class MyActivityTest extends ServiceTestCase<ImageDownloadTaskService> {
ImageDownloadTaskService service;
/**
* Constructor
*/
public MyActivityTest() {
super(ImageDownloadTaskService.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
setApplication(new MyApplication());
getApplication().onCreate();
setContext(getApplication());
Intent intent = new Intent(getContext(), ImageDownloadTaskService.class);
IBinder binder = bindService(intent);
service = ((ImageDownloadTaskService.LocalBinder) binder).getService();
}
public void testService(){
assertTrue(service.returnTrue());
}
}
Service code snippet:
public boolean returnTrue(){
return true;
}
public class LocalBinder extends Binder {
ImageDownloadTaskService getService() {
return ImageDownloadTaskService.this;
}
}
private final IBinder binder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return binder;
}
Error:
java.lang.NullPointerException
at android.content.ContextWrapper.getPackageName(ContextWrapper.java:127)
at android.content.ComponentName.<init>(ComponentName.java:75)
at android.content.Intent.<init>(Intent.java:3004)
at com.example.untitled2.MyActivityTest.setUp(MyActivityTest.java:43)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:537)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1551)
Try using getSystemContext() instead of getContext(). Docs say:
It returns the real system context that is saved by setUp(). Use it to create mock or other types of context objects for the service under test.
Hope this helps.
I'm having a problem writing a service, that should work with multiple activities.
I wrote a simple service and a mediator class the makes the bind and can return a service object. this is the simple service class:
public class ServerConnectionService extends Service{
private static final String TAG = "ServerConnectionService";
private final Binder binder=new LocalBinder();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy(){
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class LocalBinder extends Binder {
ServerConnectionService getService() {
return ServerConnectionService.this;
}
}
}
this is the mediator class:
public class ServiceConnectionBinder{
private ServerConnectionService m_SrvConnection=null;
private ServiceConnection m_OnService;
private boolean m_IsBound;
private Activity m_Client;
public ServiceConnectionBinder(Activity i_Activity)
{
m_IsBound = false;
this.m_Client = i_Activity;
this.m_OnService=new ServiceConnection() {
public void onServiceConnected(ComponentName className,IBinder rawBinder) {
m_SrvConnection=((ServerConnectionService.LocalBinder)rawBinder).getService();
}
public void onServiceDisconnected(ComponentName className) {
m_SrvConnection=null;
}
};
doBindService();
Log.d("ServiceConnectionBinder", "finished Ctor");
}
private void doBindService() {
if(!m_IsBound)
{
m_Client.bindService(new Intent(m_Client, ServerConnectionService.class), m_OnService, Context.BIND_AUTO_CREATE);
m_IsBound = true;
}
if(m_SrvConnection == null)
{
Log.d("ServiceConnectionBinder",".doBindService cannot bind " + ServerConnectionService.class.toString() + " to " + this.toString());
}
}
public void doUnbindService() {
if (m_IsBound) {
// Detach our existing connection.
m_Client.unbindService(m_OnService);
m_IsBound = false;
}
}
public ServerConnectionService getServerConnectionService()
{
if(m_IsBound)
{
Log.d("ServiceConnectionBinder", "getServerConnectionService m_IsBound = " + m_IsBound);
}
return m_SrvConnection;
}
}
The client Activity has the following data members:
private ServiceConnectionBinder m_SrvcConnectionBinder=null;
private ServerConnectionService m_SrvConnection=null;
And in onCreate() the following code:
m_SrvcConnectionBinder = new ServiceConnectionBinder(this);
m_SrvConnection = m_SrvcConnectionBinder.getServerConnectionService();
problem is that after the onCreate(), the m_SrvConnection is always null.
If you have any other ways to implement this you are more than welcome to share..
problem is that after the onCreate(), the m_SrvConnection is always null.
Of course. The binding request will not even begin until the main application thread gets control again (i.e., you return control to the OS).
You cannot use m_SrvConnection until onServiceConnected() is called.
Resurrecting the old post as I had the similar question, but there is no clear answer here.
One of the ways to address this is like this:
protected void onCreate(Bundle savedInstanceState){
//... some stuff #1...
new AsyncTask<Void, Void, Integer>(){
protected void onPreExecute() { }
protected Integer doInBackground(Void... params) {
while(m_SrvConnection==null);
return new Integer(1);
}
protected void onPostExecute(Integer result) {
// service is up, m_SrvConnection is set
// what you wanted to do with the service in onCreate() goes here
}
}.execute();
//...some stuff #2...
}
Note that "some stuff #1" will run right when onCreate() is called, "some stuff #2" will be executed almost right after that, but what you put in onPostExecute() will be run much later.
The reason for doing it this way and not just putting the code into onServiceConnected() is that the ServiceConnectionBinder can now be put outside of the Activity (in some singleton, or Application for example) and be used by multiple activities without the need for each of them to bind to the service.
Note, it may not be obvious, but things in onPostExecute() may (will) actually be run after all other standard callbacks (like onResume() etc.).