ANDROID SERVICE TUTORIAL
ANDROID SERVICE TUTORIAL
Version 2.3
Copyright © 2011, 2012 Lars Vogel
02.04.2012
Revision History | ||
---|---|---|
Revision 0.1 | 07.03.2011 | Lars Vogel |
created | ||
Revision 0.2 - 2.3 | 08.03.2011 - 02.04.2012 | Lars Vogel |
bug fixed and enhancements |
Developing own services and using system services in Android
This tutorial
describes how to create and consume Android services. It is based
on Eclipse 3.6, Java 1.6 and Android 4.0 (Ice Cream Sandwich).
Table
of Contents
A
Service
is a component which runs in the background, without interacting
with the user. Every developer can create new
Services
in his application.
Services
support true multitasking for Android, as they can run in
their own process. If you use threads in
Activities
their are still connected to the life-cycle of
Activities
and the Android system may decide to terminate them at any point
in point.
The Android platform provides
pre-defined
Services
, usually exposed
via a specific Manager class. Access to these services can be gained via
the method
getSystemService()
.
You can declare your own
Service
to perform long running operations without user interaction or to
supply functionality to other applications.
A
Service
needs to be declared in the
AndroidManifest.xml
via a
<service android:name="yourclasss">
and the implementing
</service>
class must extend theService
class or one of its subclasses.
A
Service
will not automatically run in its own thread. Without the process
attribute, they run the main thread of their hosting process. Therefore
you should run performance intensive tasks in the background.
You can also specify that
your
Service
runs in a separate process via theandroid:process=":process_description"
attribute.
This way the service gets
its own process and has its own memory. Any long running operation in theService
,
e.g. a garbage collection, will not affect the user interface of your
Activity
The colon prefix before
the name tells Android that the
Service
is private to its declaring application. If the colon is not used
the
Service
would be a global process and can be used by other components.
<service
android:name="WordService"
android:process=":my_process"
android:icon="@drawable/icon"
android:label="@string/service_name"
>
</service>
Running a service in its
own process will not block the application in case the service performs
long running operations in its main thread. But as the services runs in
its own process you need to use some interprocess communication (IPC) to
communicate to your service from other parts.
While the base class for
creating a
Service
is the
Service
class you can also implementIntentService
.
The
IntentService
is used to perform a certain task in the background. Once done, the
instance ofIntentService
terminate itself automatically. Examples for its usage would be to
download a certain resources from the Internet.
The
IntentService
class offers the
onHandleIntent()
method which will be asynchronously called by the Android system.
An
Activity
can start a
Service
via the
startService()
method and stop the service via thestopService()
method. If the
Activity
want to interact with the
Service
it can use the
bindService()
method of
the Service.
This requires an
ServiceConnection
object which allows to connect to theService
and which return a
IBinder
object. This
IBinder
object can be used by the activity to communicate with the
Service.
Once a
Service
is started the
onCreate()
method is called. Afterwards the
onStartCommand()
method
is called with the Intent data provided by the activity.
startService()
also allows you to provide a flag which determines the lifecycle
behavior of the services.
Service.START_STICKY
is used for services which are explicit started or stopped. Services
started with
Service.START_NOT_STICKY
will end automatically after the
onStartCommand()
method
is done. A
Service
is started within the main thread of the application therefore all
long running tasks should be performed in the background.
There are several way for
an Activity
to communicate with an Service and vice versa.
If the
Service
is started in the same process as the
Activity
, the
Activity
can directly bind to the service a call of the
bindService()
method. This method has the
ServiceConnection
parameter. The
onServiceConnected()
method is called on this object once the
Service
is available. TheService
return on its
onBind()
method an object of type
IBinder
which can be used to call to the service.
See
Local Service Example for
an example.
To bind to a
Service
which runs in a different process you need to use Inter Process Communication
(IPC) as the data needs to be send between different processes. For this
you need to create a AIDL file which looks similar to an Java interface
but ends with the
.aidl
file extension and is only allowed to extend other AIDL files.
If the Android Development
Tools find such a file in your source folder, it will create the necessary
stub classes for IPC communication for your. Still using this approach is
relatively advanced and will not be covered in this tutorial.
If the service should
be communicating back to the
Activity
it can receive an object of type
Messenger
via the
Intent
data it receives from the
Activity
. If the
Messenger
in bound to a
Handler
in theActivity
the
Service
can send objects of type
Message
to the
Activity.
A
Messenger
is parcable, which means it can be passed to another process and
you can use this object to send
Messages
to the
Handler
in the
Activity.
Messenger
provides also the method
getBinder()
which allows to pass a
Messenger
to theActivity. The
Activity
can therefore send
Messages
to the
Service.
To start
Services
automatically after the Android system starts you can register
aBroadcastReceiver
to the Android
android.intent.action.BOOT_COMPLETED
system event. This requires the
android.permission.RECEIVE_BOOT_COMPLETED
permission.
The following AndroidManifest.xml
registers a receiver for the
BOOT_COMPLETED
event.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.ownservice.local"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name" >
<activity
android:name=".ServiceConsumerActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="MyScheduleReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="MyStartServiceReceiver" >
</receiver>
</application>
</manifest>
In the
onReceive()
method the corresponding
BroadcastReceiver
would then start the service.
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, WordService.class);
context.startService(service);
}
}
If you application is
installed on the SD card, then it is not available after theandroid.intent.action.BOOT_COMPLETED
event. Register yourself in this case for theandroid.intent.action.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
event.
Also note that as of Android
3.0 the user needs to have started the application at least once before
your application can receive
android.intent.action.BOOT_COMPLETED
events.
As with
Activities
the Android system may terminate the process of a service at any
time to save resources. For this reason you cannot simple use a
TimerTask
in the service to ensure that it is executed on a regular basis.
The following would be
incorrect, as Android may terminate your
Service
.
public void onCreate() {
super.onCreate();
pollForUpdates();
}
// WRONG, don't do this
private void pollForUpdates() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (list.size() >= 6) {
list.remove(0);
}
list.add(fixedList[index++]);
if (index >= fixedList.length) {
index = 0;
}
}
}, 0, UPDATE_INTERVAL);
Log.i(getClass().getSimpleName(), "Timer started.");
}
For correct scheduling
of the
Service
use the
AlarmManager
class.
A PendingIntent is a token
that you give to another application (e.g. Notification Manager, Alarm Manager
or other 3rd party applications), which allows this other application to use
the permissions of your application to execute a predefined piece of code.
To perform a broadcast via
a pending intent so get a PendingIntent viaPendingIntent.getBroadcast()
.
To perform an activity via an pending intent you receive the activity via
PendingIntent.getActivity()
.
The following will demonstrate
how to use the
IntentService
class to download a file from the Internet. Once done the
IntentService
will use an instance of the
Messenger
class to inform the
Activity
which started the
service about the location of the downloaded file.
Create a new project called
"de.vogella.android.intentservice.download" with a
Activity
calledMainActivity.
Create a service "DownloadService"
by creating the following class and the entry inAndroidManifest.xml
.
Also add the permission to write to external storage and to access the Internet
to the file.
package de.vogella.android.intentservice.download;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
public class DownloadService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public DownloadService() {
super("DownloadService");
}
// Will be called asynchronously be Android
@Override
protected void onHandleIntent(Intent intent) {
Uri data = intent.getData();
String urlPath = intent.getStringExtra("urlpath");
String fileName = data.getLastPathSegment();
File output = new File(Environment.getExternalStorageDirectory(),
fileName);
if (output.exists()) {
output.delete();
}
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
stream = url.openConnection().getInputStream();
InputStreamReader reader = new InputStreamReader(stream);
fos = new FileOutputStream(output.getPath());
int next = -1;
while ((next = reader.read()) != -1) {
fos.write(next);
}
// Sucessful finished
result = Activity.RESULT_OK;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Bundle extras = intent.getExtras();
if (extras != null) {
Messenger messenger = (Messenger) extras.get("MESSENGER");
Message msg = Message.obtain();
msg.arg1 = result;
msg.obj = output.getAbsolutePath();
try {
messenger.send(msg);
} catch (android.os.RemoteException e1) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.intentservice.download"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="DownloadService" >
</service>
</application>
</manifest>
Change the
main.xml
layout to the following.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Button" />
</LinearLayout>
Change
MainActivity
to the following.
package de.vogella.android.intentservice.download;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
private Handler handler = new Handler() {
public void handleMessage(Message message) {
Object path = message.obj;
if (message.arg1 == RESULT_OK && path != null) {
Toast.makeText(MainActivity.this,
"Downloaded" + path.toString(), Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(MainActivity.this, "Download failed.",
Toast.LENGTH_LONG).show();
}
};
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClick(View view) {
Intent intent = new Intent(this, DownloadService.class);
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(handler);
intent.putExtra("MESSENGER", messenger);
intent.setData(Uri.parse("http://www.vogella.com/index.html"));
intent.putExtra("urlpath", "http://www.vogella.com/index.html");
startService(intent);
}
}
If you run your example and
press the button, the download should be performed by the
Service
and once done the
Activity
should show a Toast with the file name.
The following chapter will
demonstrate how to create and consume a service from an activity. The service
will be started at boot and periodically fetch data. The service will used by
an
activity
which bind itself to the service. The activity will allow to request
the latest data from the service.
Create a new project called
de.vogella.android.ownservice.local
with an
Activity
called
MainActivity.
Create the
LocalWordService
class.
package de.vogella.android.ownservice.local;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class LocalWordService extends Service {
private final IBinder mBinder = new MyBinder();
private ArrayList<String> list = new ArrayList<String>();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Random random = new Random();
if (random.nextBoolean()) {
list.add("Linux");
}
if (random.nextBoolean()) {
list.add("Android");
}
if (random.nextBoolean()) {
list.add("iPhone");
}
if (random.nextBoolean()) {
list.add("Windows7");
}
if (list.size() >= 20) {
list.remove(0);
}
return Service.START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyBinder extends Binder {
LocalWordService getService() {
return LocalWordService.this;
}
}
public List<String> getWordList() {
return list;
}
}
Create the following two classes,
which will be registered as
BroadcastReceivers
.
package de.vogella.android.ownservice.local;
import java.util.Calendar;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyScheduleReceiver extends BroadcastReceiver {
// Restart service every 30 seconds
private static final long REPEAT_TIME = 1000 * 30;
@Override
public void onReceive(Context context, Intent intent) {
AlarmManager service = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, MyStartServiceReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, i,
PendingIntent.FLAG_CANCEL_CURRENT);
Calendar cal = Calendar.getInstance();
// Start 30 seconds after boot completed
cal.add(Calendar.SECOND, 30);
//
// Fetch every 30 seconds
// InexactRepeating allows Android to optimize the energy consumption
service.setInexactRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), REPEAT_TIME, pending);
// service.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
// REPEAT_TIME, pending);
}
}
package de.vogella.android.ownservice.local;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyStartServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, LocalWordService.class);
context.startService(service);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.ownservice.local"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".LocalWordService"
android:icon="@drawable/icon"
android:label="@string/service_name" >
</service>
<receiver android:name="MyScheduleReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name="MyStartServiceReceiver" >
</receiver>
</application>
</manifest>
Change the
main.xml
layout to the following.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showServiceData"
android:text="Button" >
</Button>
<ListView
android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
Change your
Activity
to the following.
package de.vogella.android.ownservice.local;
import java.util.ArrayList;
import java.util.List;
import android.app.ListActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast;
public class MainActivity extends ListActivity {
private LocalWordService s;
/** Called when the activity is first created. */
@Override
public
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.main); wordList
=
new ArrayList<String>(); adapter =
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
wordList); setListAdapter(adapter); doBindService(); }
private ServiceConnection mConnection =
new ServiceConnection() {
public
void onServiceConnected(ComponentName className, IBinder binder) { s
= ((LocalWordService.MyBinder) binder).getService(); Toast.makeText(MainActivity.this,
"Connected", Toast.LENGTH_SHORT).show();
}
public
void onServiceDisconnected(ComponentName className) { s = null; } };
private ArrayAdapter<String> adapter;
private List<String> wordList;
void doBindService() { bindService(new
Intent(this,
LocalWordService.class),
mConnection, Context.BIND_AUTO_CREATE); }
public
void showServiceData(View view) {
if (s != null) { Toast.makeText(this,
"Number of elements" + s.getWordList().size(),
Toast.LENGTH_SHORT).show(); wordList.clear(); wordList.addAll(s.getWordList());
adapter.notifyDataSetChanged(); } } }
The following chapter will
demonstrate how to communicate between an
Activity
and an
Service
using the
Messenger
and
Handler
class.
Create a new project called
"de.vogella.android.ownservice.messenger" with an
Activity
calledMainActivity.
Creating the following
AndroidManifest.xml
.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.vogella.android.ownservice.messenger"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="DownloadServiceMessenger" >
</service>
</application>
</manifest>
Create the following class
package de.vogella.android.ownservice.messenger;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.StrictMode;
import android.util.Log;
public class DownloadServiceMessenger extends Service {
public static final String FILENAME = "fileName";
public static final String URLPATH = "urlPath";
public static final String RESULTPATH = "urlPath";
private int result = Activity.RESULT_CANCELED;
// Used to receive messages from the Activity
final Messenger inMessenger = new Messenger(new IncomingHandler());
// Use to send message to the Activity
private Messenger outMessenger;
public DownloadServiceMessenger() {
super();
// Don't do this
// Network Stuff will run in the main thread
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
}
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Log.e("MESSAGE", "Got message");
Bundle data = msg.getData();
String urlPath = data.getString(DownloadServiceMessenger.URLPATH);
String fileName = data.getString(DownloadServiceMessenger.FILENAME);
String outputPath = download(urlPath, fileName);
Message backMsg = Message.obtain();
backMsg.arg1 = result;
Bundle bundle = new Bundle();
bundle.putString(RESULTPATH, outputPath);
backMsg.setData(bundle);
try {
outMessenger.send(backMsg);
} catch (android.os.RemoteException e1) {
Log.w(getClass().getName(), "Exception sending message", e1);
}
}
}
private String download(String urlPath, String fileName) {
File output = new File(Environment.getExternalStorageDirectory(),
fileName);
if (output.exists()) {
output.delete();
}
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
stream = url.openConnection().getInputStream();
InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
fos = new FileOutputStream(output.getPath());
int next = -1;
while ((next = reader.read()) != -1) {
fos.write(next);
}
// Sucessful finished
result = Activity.RESULT_OK;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return output.getAbsolutePath();
}
@Override
public IBinder onBind(Intent intent) {
Bundle extras = intent.getExtras();
// Get messager from the Activity
if (extras != null) {
outMessenger = (Messenger) extras.get("MESSENGER");
}
// Return our messenger to the Activity to get commands
return inMessenger.getBinder();
}
}
Change the
main.xml
layout to the following.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="Button" />
</LinearLayout>
Change
MainActivity
to the following.
package de.vogella.android.ownservice.messenger;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
Messenger messenger = null;
private Handler handler = new Handler() {
public void handleMessage(Message message) {
Bundle data = message.getData();
if (message.arg1 == RESULT_OK && data != null) {
String text = data
.getString(DownloadServiceMessenger.RESULTPATH);
Toast.makeText(MainActivity.this, text, Toast.LENGTH_LONG)
.show();
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
private ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
messenger = new Messenger(binder);
}
public void onServiceDisconnected(ComponentName className) {
messenger = null;
}
};
protected void onResume() {
super.onResume();
Toast.makeText(this, "OnResume called", Toast.LENGTH_SHORT).show();
Intent intent = null;
intent = new Intent(this, DownloadServiceMessenger.class);
// Create a new Messenger for the communication back
// From the Service to the Activity
Messenger messenger = new Messenger(handler);
intent.putExtra("MESSENGER", messenger);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onPause() {
super.onPause();
unbindService(conn);
}
public void onClick(View view) {
Message msg = Message.obtain();
try {
Bundle bundle = new Bundle();
bundle.putString(DownloadServiceMessenger.FILENAME, "index.html");
bundle.putString(DownloadServiceMessenger.URLPATH,
"http://www.vogella.com/index.html");
msg.setData(bundle);
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Before posting questions,
please see the
vogella FAQ. If you have questions or find an error in this article please
use the
www.vogella.com Google Group. I have created a short list
how to create good questions
which might also help you.
Android ListView and ListActivity
Android Location API and Google Maps
Android Background processing with Threads and Asynchronous Task
Remote Messenger Service from Google
vogella Training Android
and Eclipse Training from the vogella team
Android Tutorial Introduction
to Android Programming
GWT Tutorial Program in Java
and compile to JavaScript and HTML
Eclipse RCP Tutorial Create
native applications in Java
JUnit Tutorial Test your
application
Git Tutorial Put everything
you have under distributed version control system
آخر اخبارنا
اهم الفاعليات لهذا الشهر
شهادات العملاء
من بين عدة انظمة للمحاسبة وقع اختيارنا على آفاق للمحاسبة لانه مناسب لطبيعة نشاطنا وانتشار فروعنا في مناطق مختلفة
آفاق للحسابات العامة نشكركم على هذا المنتج الرائع والي مزيد من التقدم والرقي لهذا المنتج الرائع
نقاط البيع واصدار الفواتير عبر نظام آفاق بالفعل هو الافضل مع تجربتنا لاكثر من نظام محاسبي كان آفاق الافضل من بينها
الشبكات الإجتماعية
الوسوم
تغريدات تويتر
-
web3jba @web3jba 4h
"برنامج محاسبة: برنامج محاسبة الى كل الشركات التى تقوم بمشاريع ذات تكاليف كثيرة لديك الان… https://t.co/Y9aiYAxLTN"
عرض التغريدة -
alkhateeb_groub @alkhateeb_groub 4h
"شاركنا باسم افضل برنامج محاسبة تعمل عليه ؟؟ مجموعة الخطيب للمحاسبة والتدقيق والتحكيم المالي والاستشارات الضريبية"
عرض التغريدة -
edara_arabia @edara_arabia 4h
"مجانا : برنامج #محاسبة متكامل هذا البرنامج يمكنك من تسجيل الدخل والمصروفات وعمل #ميزانية الشهرية والسنوية... https://t.co/hiWH94zgk3"
عرض التغريدة -
egydrem @egydrem 4h
"#إيجي_موب : برنامج حسابات رائع قد تدفع الكثير من المال فى برنامج معقد لن يفيدك فى شئ وقد تدفع القليل فى برنامج... http://t.co/mcFDTffZ7R"
عرض التغريدة