I have some programm, where I want to save the instance of service and use it in another activities. But service doesn't create.
Just see the code, please.
MainActivity.java:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainService.get(this);
}
}
MainService.java:
public class MainService extends Service {
public static Object sWait = new Object();
public static MainService instance;
#Override
public IBinder onBind(Intent intent) {
return null;
}
public static MainService get(Context mContext) {
if (instance == null) {
Intent intent = new Intent(mContext, MainService.class);
mContext.startService(intent);
}
while (true) {
if (instance != null) {
Log.v("myLogs", "all is good!");
break;
}
synchronized (sWait) {
try {
sWait.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return instance;
}
#Override
public void onCreate() {
Log.v("myLogs", "created!");
instance = this;
synchronized (sWait) {
sWait.notify();
}
}
}
When I don't use while in MainService.get(), service creates. I added this service to manifest file. I don't know where is there error. I need your help.
That's just not the way you should use Service in Android.
What you probably need is to use bindService() call from your Activity.
See more about bound service here http://developer.android.com/guide/components/bound-services.html
If you need the service to be the same instance each time you bind to it, call startService once when your application start.
Example code:
public class LocalBinder<T> extends Binder {
private WeakReference<T> mService;
public LocalBinder(T service) {
mService = new WeakReference<T>(service);
}
public T getService() {
return mService.get();
}
}
public class MyService extends Service {
private final LocalBinder<MyService> binder;
public MyService() {
binder = new LocalBinder<MyService>(this);
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
}
public class MyActivity extends Activity implements ServiceConnection {
#Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, MyService.class), this, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(this);
}
#SuppressWarnings("unchecked")
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService serv = ((LocalBinder<MyService>) service).getService();
// serv is your service instance now
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}
To start your service use (call this from your activity!):
Intent serviceIntent = new Intent(this, MainService.class);
startService(serviceIntent);
see docs: https://developer.android.com/training/run-background-service/send-request.html
That is definitely not the way you are supposed to use services in android.
I would suggest you revisit the offical android docs.
To get a quick introduction visit this tutorial here.
Related
I am trying to constantly update the UI based on a long-running service output.
Basically, I want to display and append a list of users one by one after they get processed by the bound service.
MainActivityViewModel
public class MainActivityViewModel extends ViewModel {
private MutableLiveData<User> user = new MutableLiveData<>();
private MutableLiveData<MyService.MyBinder> mBinder = new MutableLiveData<>();
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder iBinder) {
MyService.MyBinder binder = (MyService.MyBinder) iBinder;
mBinder.postValue(binder);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBinder.postValue(null);
}
};
public ServiceConnection getServiceConnection(){
return serviceConnection;
}
public LiveData<User> getUser(){
return user;
}
public LiveData<MyService.MyBinder> getBinder(){
return mBinder;
}
}
My Service
public class MyService extends Service {
private final IBinder mBinder = new MyBinder();
private Handler mHandler;
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void starFetchingUsers(User obj){
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
/**********************************************************/
Here i will be sending POST method one by one for 100 times and will get
a response as a user object which needs to be a liveData. So once this object
is changed after next post method, i want it to get displayed or appended on UI.
How to bind this dynamic user object variable to the MutableLiveData user created in MainActivityViewModel class? so this get auto updated in UI.
/**********************************************************/
}
});
thread.start();
}
public class MyBinder extends Binder{
MyService getService(){
return MyService.this;
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
stopSelf();
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Please let me know what I am missing in both classes.
I want to have background music playing while the user is playing a game. The music starts when the user starts the application, pauses when they leave it, and it resumes when they go back to the application.
I tried using this method, I edited it a bit:
public class MainActivity extends Activity {
private boolean bounded;
private BackgroundSoundService backgroundSoundService;
ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceDisconnected( ComponentName name ) {
bounded = false;
backgroundSoundService = null;
}
#Override
public void onServiceConnected( ComponentName name, IBinder service ) {
bounded = true;
BackgroundSoundService.LocalBinder localBinder = (BackgroundSoundService.LocalBinder) service;
backgroundSoundService = localBinder.getServiceInstance();
}
};
#Override
public void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
// (code that's not necessary)
backgroundSoundService.start(); // this is where the error is thrown
}
#Override
public void onPause() {
super.onPause();
backgroundSoundService.pause();
}
#Override
public void onResume() {
super.onResume();
backgroundSoundService.resume();
}
#Override
public void onStop() {
super.onStop();
backgroundSoundService.pause();
}
#Override
public void onStart() {
super.onStart();
Intent intent = new Intent(this, BackgroundSoundService.class);
bindService(intent, connection, BIND_AUTO_CREATE);
backgroundSoundService.start();
}
#Override
public void onDestroy() {
super.onDestroy();
backgroundSoundService.destroy();
}
}
I use an activity to play, pause and resume background music. I'll leave out the unecessary methods/lines for this question here:
public class BackgroundSoundService extends Service {
private static final String TAG = null;
public IBinder binder = new LocalBinder();
public IBinder onBind( Intent arg0 ) {
return binder;
}
public IBinder onUnBind( Intent arg0 ) {
return null;
}
public class LocalBinder extends Binder {
public BackgroundSoundService getServiceInstance() {
return BackgroundSoundService.this;
}
}
}
However, when I run the application I get a NullPointerException in the MainActivity class (in the onCreate method, I commented it in the code).
The variable doesn't seem to be initialized yet, but I do need to start the music when the user opens the application.
I also tried removing the backgroundSoundService.start(); from the onCreate method, so the music would start when onStart is called. However, when I do that, I get the same error.
So, how can I initialize backgroundSoundService before it is used to call its methods?
first of all remove this backgroundSoundService.start() from onCreate and add it inside onServiceConnected() method
u need to check null before doing any backgroundSoundService related stuffs like below
#Override
public void onPause() {
super.onPause();
if(backgroundSoundService != null){
backgroundSoundService.pause();
}
}
add this kind of null check in all appearance of backgroundSoundService
In my application I want to establish a TCP connection with a service and bind this service to every activity where it is needed. It gets started in my Login activity and everything is working like it should. Here is the code:
private TCPService mService;
private boolean mBound = false;
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, TCPService.class);
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
TCPService.LocalBinder binder = (TCPService.LocalBinder)service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
Now I want to bind the service in another activity by using almost the same code just without startService(intent); But the mBound is never set to true and I can't access the service functions like it is intented.
Here is the implementation of the service:
public class TCPService extends Service {
private final IBinder myBinder = new LocalBinder();
public class LocalBinder extends Binder {
public TCPService getService() {
return TCPService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return myBinder;
}
}
What am I missing out? Is there anything I should check that may cause this behaviour?
Thanks in advance
I'm developing an app, which gets data from web and writes it back to web. For that I was using AsyncTask, but those requests weren't optimized, so I had to authenticate user, on every request. Now I want to use Service for holding the connection to backend and to do requests without needing to authenticate the user on every requests.
I'm having trouble to send this service object to subactivity without creating an new instance and nulling all the values I need from the service. So how to do it without osing values ?
Here is my service:
public class LasteMVService extends Service {
private ArrayList<WorkSheet> workSheetArrayList;
private SpreadSheet selectedSpeadSheet;
private static String LOG_TAG = "LasteMVService";
private IBinder mBinder = new MyBinder();
#Override
public void onCreate() {
super.onCreate();
new Thread(new Task()).start();
Log.v(LOG_TAG, "in onCreate");
}
#Override
public IBinder onBind(Intent intent) {
Log.v(LOG_TAG, "in onBind");
return mBinder;
}
#Override
public void onRebind(Intent intent) {
Log.v(LOG_TAG, "in onRebind");
super.onRebind(intent);
}
public SpreadSheet getSelectedSpeadSheet() {
return selectedSpeadSheet;
}
public ArrayList<WorkSheet> getWorkSheetArrayList() {
return workSheetArrayList;
}
#Override
public void onDestroy() {
Log.v(LOG_TAG, "in onDestroy");
super.onDestroy();
}
public class MyBinder extends Binder {
public LasteMVService getService() {
return LasteMVService.this;
}
}
class Task implements Runnable {
#Override
public void run() {
synchronized (this){
AndroidAuthenticator androidAuthenticator = new AndroidAuthenticator(getApplicationContext());
SpreadSheetFactory spf = SpreadSheetFactory.getInstance(androidAuthenticator);
ArrayList<SpreadSheet> sheets = spf.getSpreadSheet("Stardiprotokoll", true);
if (sheets != null) {
final SpreadSheet spreadSheet = sheets.get(0);
selectedSpeadSheet = spreadSheet;
ArrayList<WorkSheet> workSheet = spreadSheet.getAllWorkSheets();
workSheetArrayList = workSheet;
}
}
}
}
}
And here is where I bind it with BaseActivity:
public class BaseActivity extends AppCompatActivity {
protected LasteMVService lasteMVService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lasteMVService = ((LasteMVApplication) getApplicationContext()).getLasteMVService();
if(lasteMVService == null){
((LasteMVApplication) getApplicationContext()).initApp();
lasteMVService = ((LasteMVApplication) getApplicationContext()).getLasteMVService();
Util.restartApp(this, true);
}
}
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(BaseActivity.this,LasteMVService.class);
startService(intent);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
}
protected ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
LasteMVService.MyBinder myBinder = (LasteMVService.MyBinder) service;
lasteMVService = myBinder.getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
};
My question is how to get the same instance of the service in some of the subactivities of BaseActivity?
Okay so you need a service object, Scratch getting the object's reference from base activity rather create a singleton class that is globally accessible throughout your application..
The source code to help you is below
public class Common extends Application {
private Service mService; //Service Object from your class that extends service.
private Context mContext;
public Service getService(){
return mService;
}
public void setService(Service service){
mService = service;
}
#Override
public void onCreate() {
super.onCreate();
//Gets the context associated with the whole application
mContext = getApplicationContext();
}
}
public class Service extends Service{
private Common mApp;
private Context mContext;
//Instantiate the Common Object from the singleton class within on create.
#Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
mApp = (Common) getApplicationContext();
mApp.setService(this);
}
}
//Now to use it in your base Activity
public class BaseActivity extends AppCompatActivity{
private Common mApp;
private Service mService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApp = (Common) mContext.getApplicationContext();
//To use the service you would simply use:
mService = mApp.getService()./*Some public method defined in your service*/;
}
}
How to pass handler from an activity to service? I am trying to update the activity UI on the state of Bluetooth connection by using Handler as shown below from service class.
mHandler.obtainMessage(MenuActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
In the activity, I implemented this:
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if (true)
Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch(msg.arg1){
case BluetoothService.STATE_CONNECTED:
showToast("Connected to " + mConnectedDeviceName, Toast.LENGTH_SHORT);
break;
I tried to use a constructor to pass the handler from the activity to service like this:
public BluetoothService(Handler handler, BluetoothAdapter mBluetoothAdapter) {
mAdapter = mBluetoothAdapter;
mState = STATE_NONE;
mHandler = handler;
}
But there was an error which shows Unable to instantiate service and found that the service needs to have a public no-args constructor. But after removing the constructor, the handler did not get passed into the service.
How to solve this problem?
You have to bind to the service from activity and establish a ServiceConnection and then get the instance of service and set your handler.
Here is the activity and service class which i use for one of my media player application.....
public class MainActivity extends Activity
{
private CustomService mService = null;
private boolean mIsBound;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
startService(new Intent(this.getBaseContext(), CustomService.class));
doBindService();
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder)
{
mService = ((CustomService.LocalBinder)iBinder).getInstance();
mService.setHandler(yourHandler);
}
#Override
public void onServiceDisconnected(ComponentName componentName)
{
mService = null;
}
};
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).
bindService(new Intent(this,
CustomService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private void doUnbindService()
{
if (mIsBound)
{
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy()
{
super.onDestroy();
doUnbindService();
}
}
CustomService Code ....
public class CustomService extends Service
{
private final IBinder mIBinder = new LocalBinder();
private Handler mHandler = null;
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flag, int startId)
{
return START_STICKY;
}
#Override
public void onDestroy()
{
if(mHandler != null)
{
mHandler = null;
}
}
#Override
public IBinder onBind(Intent intent)
{
return mIBinder;
}
public class LocalBinder extends Binder
{
public CustomService getInstance()
{
return CustomService.this;
}
}
public void setHandler(Handler handler)
{
mHandler = handler;
}
}