Android App Continue Running in Background Xamarin Android
Introduction To Android Services
Android provides platform support to execute with and without a user interface. An Android service is defined as an application component that is generally used to perform long tasks in the background without needing user input.
Services could be used for a variety of purposes:
- Handle network transactions
- Play audio/music in background
- Perform non-user input requiring I/O operations like backup
- Periodic downloads of certain types of data
Basics of Android Services
The service isn't a separate process, nor a thread. It runs in the same process as the application. A service provides the following features of interest:
- Something that the application can communicate to the Android system what it wants to execute in the background without telling user what it is doing
- A mechanism for an application to expose certain functionality to other applications
A service needs to declare itself in the application manifest file (AndroidManifest.xml) as a <service>.
<manifest ... > ... <application ... > <service android_name=".MyService" /> ... </application> </manifest>
Services can be started in one of two ways: by using Context.startService() or Context.bindService().
Good programming practices dictate to use an explicit intent when starting or binding a service. One must also not declare intent filters for a service.
How to Create a Service in Android
There are two ways to create a service. If the service is simple, you can create a subclass of IntentService and only implement the onHandleIntent() method.
To create a service in a custom manner, one needs to create a subclass of Service and override some methods (methods that handle key aspects of service lifecycle).
- onStartCommand(): This method is called when another component requests the service to be started by calling startService().
- onBind(): This method is called when another component wants to bind to the service by calling bindService().
- onCreate(): This method is called when the service is first created. This method is meant for "housekeeping." The Android platform calls this method before it calls onStartCommand() or onBind().
- onDestroy(): This method is called when the service is no longer used and is to be destroyed. All cleanup code should reside in this method.
Note that when Android system runs low on resources, background services can be destroyed to free up resources, so make sure to implement the above method properly.
Hands On with Android Services
Let us now create a simple service—"started service"—that will be started by another component by calling startService().
Fire up Android Studio and start a new Android Studio Project.
Figure 1: Starting Android Studio
Provide ServiceDemo as the Application Name and click Next.
Figure 2: Naming the application
On the next screen, leave the default values and click Next.
Figure 3: Leaving the defaults in place
On the "Add an activity to Mobile" page, choose "Blank Activity". This creates an application with a single activity.
Figure 4: Starting a blank activity
We are then prompted to customize the activity. We will leave the default values unchanged.
Figure 5: Again, leaving the default values in place
Click Finish to creating the project files.
Next, we create a custom Service. Right-click the /src/java/ folder on the Project Explorer and select New-> Service->Service.
Figure 6: Creating a custom Service
Leave the default values unchanged and click Finish to create the Service class.
Figure 7: Once again, leaving the default values in place
The default code generated is as follows:
package com.example.vipul.servicedemo; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel // to the service. throw new UnsupportedOperationException ("Not yet implemented"); } }
We will now implement the other callbacks. We will also add logging to understand the order of the calls.
package com.example.vipul.servicedemo; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. Log.w("MyService", "onBind callback called"); throw new UnsupportedOperationException("Not yet implemented"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.w("MyService", "onStartCommand callback called"); return super.onStartCommand(intent, flags, startId); } @Override public void onCreate() { super.onCreate(); Log.w("MyService", "onCreate callback called"); } @Override public void onDestroy() { super.onDestroy(); Log.w("MyService", "onDestroy callback called"); } }
Next, we will create a Intent service. Right-click the /src tab and select New -> Service -> IntentService
Figure 8: Selecting a New Service
Leave the suggested name for the service unchanged and click Finish to create the class.
Figure 9: Leaving the suggested service name unchanged
You will see that the default code that is generated by Android Studio has the following content:
package com.example.vipul.servicedemo; import android.app.IntentService; import android.content.Intent; import android.content.Context; import android.util.Log; /** * An {@link IntentService} subclass for handling asynchronous * task requests in a service on a separate handler thread. * <p/> * TODO: Customize class - update intent actions, extra * parameters and static helper methods. */ public class MyIntentService extends IntentService { // TODO: Rename actions, choose action names that describe tasks that // this IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS private static final String ACTION_FOO = "com.example.vipul.servicedemo.action.FOO"; private static final String ACTION_BAZ = "com.example.vipul.servicedemo.action.BAZ"; // TODO: Rename parameters private static final String EXTRA_PARAM1 = "com.example.vipul.servicedemo.extra.PARAM1"; private static final String EXTRA_PARAM2 = "com.example.vipul.servicedemo.extra.PARAM2"; /** * Starts this service to perform action Foo with the given parameters. If * the service is already performing a task this action will be queued. * * @see IntentService */ // TODO: Customize helper method public static void startActionFoo(Context context, String param1, String param2) { Intent intent = new Intent(context, MyIntentService.class); intent.setAction( ACTION_FOO ); intent.putExtra( EXTRA_PARAM1 , param1); intent.putExtra( EXTRA_PARAM2 , param2); context.startService(intent); } /** * Starts this service to perform action Baz with the given parameters. If * the service is already performing a task this action will be queued. * * @see IntentService */ // TODO: Customize helper method public static void startActionBaz(Context context, String param1, String param2) { Intent intent = new Intent(context, MyIntentService.class); intent.setAction( ACTION_BAZ ); intent.putExtra( EXTRA_PARAM1 , param1); intent.putExtra( EXTRA_PARAM2 , param2); context.startService(intent); } public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { final String action = intent.getAction(); if ( ACTION_FOO .equals(action)) { final String param1 = intent.getStringExtra( EXTRA_PARAM1 ); final String param2 = intent.getStringExtra( EXTRA_PARAM2 ); handleActionFoo(param1, param2); } else if ( ACTION_BAZ .equals(action)) { final String param1 = intent.getStringExtra( EXTRA_PARAM1 ); final String param2 = intent.getStringExtra( EXTRA_PARAM2 ); handleActionBaz(param1, param2); } } } /** * Handle action Foo in the provided background thread with the * provided parameters. */ private void handleActionFoo(String param1, String param2) { // TODO: Handle action Foo throw new UnsupportedOperationException("Not yet implemented"); } /** * Handle action Baz in the provided background thread with the * provided parameters. */ private void handleActionBaz(String param1, String param2) { // TODO: Handle action Baz throw new UnsupportedOperationException("Not yet implemented"); } }
We will implement the other callbacks for the service.
package com.example.vipul.servicedemo; import android.app.IntentService; import android.content.Intent; import android.content.Context; import android.util.Log; /** * An {@link IntentService} subclass for handling asynchronous * task requests in a service on a separate handler thread. * <p/> * TODO: Customize class - update intent actions, extra parameters * and static helper methods. */ public classMyIntentService extends IntentService { // TODO: Rename actions, choose action names that describe tasks // that this IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS private static final String ACTION_FOO = "com.example.vipul.servicedemo.action.FOO"; private static final String ACTION_BAZ = "com.example.vipul.servicedemo.action.BAZ"; // TODO: Rename parameters private static final String EXTRA_PARAM1 = "com.example.vipul.servicedemo.extra.PARAM1"; private static final String EXTRA_PARAM2 = "com.example.vipul.servicedemo.extra.PARAM2"; /** * Starts this service to perform action Foo with the given parameters. If * the service is already performing a task this action will be queued. * * @see IntentService */ // TODO: Customize helper method public static void startActionFoo(Context context, String param1, String param2) { Intent intent = new Intent(context, MyIntentService.class); intent.setAction( ACTION_FOO ); intent.putExtra( EXTRA_PARAM1 , param1); intent.putExtra( EXTRA_PARAM2 , param2); context.startService(intent); } /** * Starts this service to perform action Baz with the given parameters. If * the service is already performing a task this action will be queued. * * @see IntentService */ // TODO: Customize helper method public static void startActionBaz(Context context, String param1, String param2) { Intent intent = new Intent(context, MyIntentService.class); intent.setAction( ACTION_BAZ ); intent.putExtra( EXTRA_PARAM1 , param1); intent.putExtra( EXTRA_PARAM2 , param2); context.startService(intent); } public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { final String action = intent.getAction(); if ( ACTION_FOO .equals(action)) { final String param1 = intent.getStringExtra( EXTRA_PARAM1 ); final String param2 = intent.getStringExtra( EXTRA_PARAM2 ); handleActionFoo(param1, param2); } else if ( ACTION_BAZ .equals(action)) { final String param1 = intent.getStringExtra( EXTRA_PARAM1 ); final String param2 = intent.getStringExtra( EXTRA_PARAM2 ); handleActionBaz(param1, param2); } } } /** * Handle action Foo in the provided background thread with the provided * parameters. */ private void handleActionFoo(String param1, String param2) { // TODO: Handle action Foo throw new UnsupportedOperationException("Not yet implemented"); } /** * Handle action Baz in the provided background thread with the provided * parameters. */ private void handleActionBaz(String param1, String param2) { // TODO: Handle action Baz throw new UnsupportedOperationException("Not yet implemented"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.w("MyIntentService", "onStartCommand callback called"); return super.onStartCommand(intent, flags, startId); } @Override public void onStart(Intent intent, int startId) { Log.w("MyIntentService", "onStart callback called"); super.onStart(intent, startId); } @Override public void onDestroy() { Log.w("MyIntentService", "onDestroy callback called"); super.onDestroy(); } }
Finally, we will add a couple of buttons on MainActivity. When the user clicks the buttons, we will invoke the services we have created above.
<RelativeLayout xmlns_android= "http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android_text="@string/hello_world" android_layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textView" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Service" android:id="@+id/buttonStartService" android:layout_below="@+id/textView" android:layout_toRightOf="@+id/textView" android:layout_toEndOf="@+id/textView" android:layout_marginTop="62dp" <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Intent Service" android:id="@+id/buttonStartIntentService" android:layout_centerVertical="true" android:layout_alignLeft="@+id/buttonStartService" android:layout_alignStart="@+id/buttonStartService" </RelativeLayout>
We will now implement the click event handlers for the buttons:
// MainActivity.java package com.example.vipul.servicedemo; import android.app.Service; import android.content.Intent; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; public class MainActivity extends ActionBarActivity { @Override protected voidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout. activity_main ); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar // if it is present. getMenuInflater().inflate(R.menu. menu_main , menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. intid = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id. action_settings ) { return true; } return super.onOptionsItemSelected(item); } public void onButtonServiceClick(View view) { Intent myServiceIntent = new Intent(this, MyService.class); startService(myServiceIntent); } public void onButtonIntentServiceClick(View view){ Intent myIntentServiceIntent = new Intent(this, MyIntentService.class); startService(myIntentServiceIntent); } }
Finally, we will wire up the event handlers with the event.
// Activity_main.xml <RelativeLayout xmlns_android= "http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android_text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textView" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Service" android:id="@+id/buttonStartService" android:layout_below="@+id/textView" android:layout_toRightOf="@+id/textView" android:layout_toEndOf="@+id/textView" android:layout_marginTop="62dp" android:onClick="onButtonServiceClick" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Intent Service" android:id="@+id/buttonStartIntentService" android:layout_centerVertical="true" android:layout_alignLeft="@+id/buttonStartService" android:layout_alignStart="@+id/buttonStartService" android:onClick="onButtonIntentServiceClick" /> </RelativeLayout>
Our application is now complete. When we run the application and click the buttons, we will see the screen as shown in Figure 10.
Figure 10: The screen displaying two buttons
However, when we observe the logcat view with the warning filter, the content in Figure 11 appears:
Figure 11: The logical view
You will observe the following order of callbacks being invoked.
11-22 16:50:40.823 1690-1709/com.example.vipul.servicedemo W/EGL_emulation : eglSurfaceAttrib not implemented 11-22 16:50:40.823 1690-1709/com.example.vipul.servicedemo W/OpenGLRenderer : Failed to set EGL_SWAP_BEHAVIOR on surface 0xb4b48380, error=EGL_SUCCESS 11-22 16:51:08.180 1690-1690/com.example.vipul.servicedemo W/MyService : onCreate callback called 11-22 16:51:08.183 1690-1690/com.example.vipul.servicedemo W/MyService : onStartCommand callback called 11-22 16:51:17.123 1690-1690/com.example.vipul.servicedemo W/MyIntentService : onStartCommand callback called 11-22 16:51:17.124 1690-1690/com.example.vipul.servicedemo W/MyIntentService : onStart callback called 11-22 16:51:17.182 1690-1690/com.example.vipul.servicedemo W/MyIntentService : onDestroy callback called 11-22 16:53:19.340 1690-1697/com.example.vipul.servicedemo W/art : Suspending all threads took: 5.497ms 11-22 16:54:37.475 1690-1697/com.example.vipul.servicedemo W/art : Suspending all threads took: 5.694ms 11-22 16:57:33.791 1690-1697/com.example.vipul.servicedemo W/art : Suspending all threads took: 7.551ms 11-22 16:58:58.447 1690-1697/com.example.vipul.servicedemo W/art : Suspending all threads took: 5.555ms
This shows the event order in which service callbacks are called.
You can see that the IntentService destroy callback was destroyed in my case because I stopped app debugging.
Summary
In this article, we learned the basics about Android services and how to create a custom service and a intent service. I hope you have found this information useful. You can download the sample code from the link at the bottom of this article.
About the Author
Vipul Patel is a technology geek based in Seattle. He can be reached at [email protected] You can visit his LinkedIn profile at https://www.linkedin.com/pub/vipul-patel/6/675/508.
Source: https://www.developer.com/languages/xml/executing-long-running-background-tasks-in-android-apps-without-an-interface-using-services/
0 Response to "Android App Continue Running in Background Xamarin Android"
Postar um comentário