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*/;
}
}
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.
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
Hello I am passing handler message from test Service to test activity. Is there any way i can return object from TestActivity to Testservice class. Or is there any easier way to do this.
public class TestService {
public Handler testResultsHandler;
private BooleanstoreTestResults(String message) {
if (testResultsHandler != null)
{
Message message = testResultsHandler.obtainMessage();
message.obj = "refresh";
testResultsHandler.sendMessage(message);
}
}
}
public class TestActivity extends Activity {
private TestService testService = new TestService(this);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
formView = (View) findViewById(R.id.form);
messageTextView = (TextView) findViewById(R.id.status_message);
testService.testResultsHandler = new TestResultResponse();
}
private class TestResultResponse extends Handler {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg != null && msg.obj != null && this != null) {
if (msg.obj.toString().equals("refresh")) {
refresh(); // return value back to testservice in here
}
}
}
}
}
You need to use ServiceConnection to store Service handler in Activity.
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
// onServiceDisconnected is only called in extreme situations (crashed / killed).
mBound = false;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mConnectorSender = new Messenger(service);
mBound = true;
}
};
and bind service like this:
mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
Here is a good tutorial from Vogella.
Also it is better to send small messages in msg.arg1 and msg.arg2 params. You can create constant for refresh action and assign it to msg.arg1. It would be better, than sending the Object.
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.
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;
}
}