Android-Service | 字数总计: 2.4k | 阅读时长: 14分钟 | 阅读量: |
定义布局文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 <?xml version="1.0" encoding="utf-8" ?> <LinearLayout 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:orientation ="vertical" android:padding ="20dp" tools:context =".MainActivity" > <Button android:id ="@+id/btn_start" android:layout_width ="match_parent" android:layout_height ="0dp" android:layout_weight ="1" android:text ="StartService" android:textAllCaps ="false" android:textSize ="30sp" android:enabled ="true" /> <Button android:id ="@+id/btn_stop" android:layout_width ="match_parent" android:layout_height ="0dp" android:layout_weight ="1" android:text ="StopService" android:textAllCaps ="false" android:textSize ="30sp" android:enabled ="false" /> <Button android:id ="@+id/btn_bind" android:layout_width ="match_parent" android:layout_height ="0dp" android:layout_weight ="1" android:text ="BindService" android:textAllCaps ="false" android:textSize ="30sp" /> <Button android:id ="@+id/btn_operate" android:layout_width ="match_parent" android:layout_height ="0dp" android:layout_weight ="1" android:text ="OperateService" android:textAllCaps ="false" android:textSize ="30sp" /> <Button android:id ="@+id/btn_unbind" android:layout_width ="match_parent" android:layout_height ="0dp" android:layout_weight ="1" android:text ="UnBindService" android:textAllCaps ="false" android:textSize ="30sp" /> <Button android:id ="@+id/btn_intent" android:layout_width ="match_parent" android:layout_height ="0dp" android:layout_weight ="1" android:text ="IntentService" android:textAllCaps ="false" android:textSize ="30sp" /> <Button android:id ="@+id/btn_foreground" android:layout_width ="match_parent" android:layout_height ="0dp" android:layout_weight ="1" android:text ="ForegroundService" android:textAllCaps ="false" android:textSize ="30sp" /> </LinearLayout >
新建Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.example.servicetest;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class MyService extends Service { private static final String TAG = MyService.class.getSimpleName(); public MyService () { } @Override public IBinder onBind (Intent intent) { throw new UnsupportedOperationException ("Not yet implemented" ); } @Override public void onCreate () { Log.d(TAG, "onCreate: ThreadId" +Thread.currentThread().getId()); super .onCreate(); } @Override public int onStartCommand (Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: StartId" +startId); Log.d(TAG, "onStartCommand: ThreadId" +Thread.currentThread().getId()); return super .onStartCommand(intent, flags, startId); } @Override public void onDestroy () { Log.d(TAG, "onDestroy: ThreadId" +Thread.currentThread().getId()); super .onDestroy(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package com.example.servicetest;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private Button mBtnStart, mBtnStop; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate: ThreadId" +Thread.currentThread().getId()); initView(); initClick(); } private void initClick () { mBtnStart.setOnClickListener((View view)->{ mBtnStart.setEnabled(false ); mBtnStop.setEnabled(true ); Intent intent = new Intent (this , MyService.class);; startService(intent); }); mBtnStop.setOnClickListener((View view)->{ mBtnStop.setEnabled(false ); mBtnStart.setEnabled(true ); Intent intent = new Intent (this , MyService.class);; stopService(intent); }); } private void initView () { mBtnStart = findViewById(R.id.btn_start); mBtnStop = findViewById(R.id.btn_stop); } }
通过如下按钮操作
点击三次StartService
点击一次Stop
点击一次Stop
点击一次StartService
输出结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 D/MainActivity: onCreate: ThreadId2 D/MyService: onCreate: ThreadId2 D/MyService: onStartCommand: StartId1 D/MyService: onStartCommand: ThreadId2 D/MyService: onStartCommand: StartId2 D/MyService: onStartCommand: ThreadId2 D/MyService: onStartCommand: StartId3 D/MyService: onStartCommand: ThreadId2 D/MyService: onDestroy: ThreadId2 D/MyService: onCreate: ThreadId2 D/MyService: onStartCommand: StartId1 D/MyService: onStartCommand: ThreadId2
分析
ThreadId相同,故在同一程序中的本地Service与Activity在同一UI线程中执行
第一次启动Service时,会调用onCreate()方法,然后调用onStartCommand()方法
允许多次启动Service,startId将会累加
调用stopService后将回调onDestroy()方法
再次启动又从startId=1开始
绑定Service
MyService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package com.example.servicetest;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;public class MyService extends Service { private static final String TAG = MyService.class.getSimpleName(); public class MyBinder extends Binder { public MyService getService () { return MyService.this ; } } private MyBinder myBinder = new MyBinder (); public MyService () { } @Override public IBinder onBind (Intent intent) { Log.d(TAG, "onBind: bind" ); return myBinder; } @Override public void onCreate () { Log.d(TAG, "onCreate: ThreadId" +Thread.currentThread().getId()); super .onCreate(); } public String doSomeOperation (String str) { Log.i(TAG,"doSomeOperation: bind" ); return str+"value" ; } @Override public int onStartCommand (Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: StartId" +startId); Log.d(TAG, "onStartCommand: ThreadId" +Thread.currentThread().getId()); return super .onStartCommand(intent, flags, startId); } @Override public void onDestroy () { Log.d(TAG, "onDestroy: ThreadId" +Thread.currentThread().getId()); super .onDestroy(); } }
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package com.example.servicetest;import androidx.appcompat.app.AppCompatActivity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private Button mBtnStart, mBtnStop; private Button mBtnBind, mBtnOperate, mBtnUnBind; private Intent intent; private MyService.MyBinder myBinder; private MyService myService; private ServiceConnection conn; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); intent = new Intent (this , MyService.class); Log.d(TAG, "onCreate: ThreadId" +Thread.currentThread().getId()); conn = new ServiceConnection () { @Override public void onServiceConnected (ComponentName name, IBinder binder) { Log.d(TAG, "ServiceConnected" ); myBinder = (MyService.MyBinder) binder; myService = myBinder.getService(); } @Override public void onServiceDisconnected (ComponentName name) { Log.d(TAG, "ServiceDisconnected" ); myBinder = null ; myService = null ; } }; initView(); initClick(); } private void initClick () { mBtnStart.setOnClickListener((View view)->{ startService(intent); }); mBtnStop.setOnClickListener((View view)->{ stopService(intent); }); mBtnBind.setOnClickListener((View view)->{ bindService(intent, conn, BIND_AUTO_CREATE); }); mBtnOperate.setOnClickListener((View view)->{ if (myService != null ) { String ret = myService.doSomeOperation("abc" ); Toast.makeText(this , ret, Toast.LENGTH_SHORT).show(); } }); mBtnUnBind.setOnClickListener((View view)->{ if (myBinder != null ){ unbindService(conn); } }); } private void initView () { mBtnStart = findViewById(R.id.btn_start); mBtnStop = findViewById(R.id.btn_stop); mBtnBind = findViewById(R.id.btn_bind); mBtnOperate = findViewById(R.id.btn_operate); mBtnUnBind = findViewById(R.id.btn_unbind); } }
IntentService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package com.example.servicetest;import android.app.IntentService;import android.content.Intent;import android.util.Log;import androidx.annotation.Nullable;public class MyIntentService extends IntentService { private static final String TAG = MyIntentService.class.getSimpleName(); public MyIntentService () { super (TAG); } public MyIntentService (String name) { super (name); } @Override public void onCreate () { super .onCreate(); Log.d(TAG, "onCreate" ); } @Override public int onStartCommand (@Nullable Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand startId=" +startId); return super .onStartCommand(intent, flags, startId); } @Override public void onStart (@Nullable Intent intent, int startId) { super .onStart(intent, startId); Log.d(TAG, "onStart" ); } @Override public void onDestroy () { super .onDestroy(); Log.d(TAG, "onDestroy" ); } @Override protected void onHandleIntent (@Nullable Intent intent) { int count = intent.getExtras().getInt("count" ); Log.d(TAG, "onHandleIntent: count=" +count); while (count > 0 ) { count--; Log.d(TAG, "onHandleIntent: count=" +count); try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } } } }
1 2 3 4 5 6 7 mBtnIntent.setOnClickListener((View view)->{ Intent intent1 = new Intent (this , MyIntentService.class); intent1.putExtra("count" ,20 ); startService(intent1); intent1.putExtra("count" ,5 ); startService(intent1); });
AndroidManifest.xml
application中加入
1 2 <service android:name =".MyIntentService" > </service >
前台Service
Android系统对运行的进程按优先级划分了四种进程类型
前台进程 (Foreground Process)
可见进程 (Visible Process)
服务进程 (Service Process)
后台进程 (Background Process)
当系统内存不足时,系统优先杀死后台进程,为防止后台的Service被杀,故可申请为前台进程
MainActivity.java中的点击事件
1 2 3 4 5 6 mBtnForeground.setOnClickListener((View view)-> { Intent intent1 = new Intent(this, MyForegroundService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startService(intent1); } });
MyForegroundService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 package com.example.servicetest;import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.graphics.BitmapFactory;import android.os.Build;import android.os.IBinder;import androidx.core.app.NotificationCompat;public class MyForegroundService extends Service { public MyForegroundService () { } @Override public IBinder onBind (Intent intent) { throw new UnsupportedOperationException ("Not yet implemented" ); } @Override public void onCreate () { super .onCreate(); showNotification(); } @Override public int onStartCommand (Intent intent, int flags, int startId) { return super .onStartCommand(intent, flags, startId); } @Override public void onDestroy () { super .onDestroy(); } public void showNotification () { String channelId = "MyChannel01" ; Intent intent = new Intent (this , MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this ,0 ,intent, PendingIntent.FLAG_CANCEL_CURRENT); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel (channelId, "MyChannel" , NotificationManager.IMPORTANCE_LOW); notificationManager.createNotificationChannel(channel); } Notification notification = new NotificationCompat .Builder(this ,channelId) .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("前台服务" ) .setContentText("This is a foreground" ) .setContentIntent(pendingIntent) .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher)) .build(); startForeground(1 , notification); } }
最终的AndroidManifest.xml文件
声明前台Service权限,声明几个service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?xml version="1.0" encoding="utf-8" ?> <manifest xmlns:android ="http://schemas.android.com/apk/res/android" package ="com.example.servicetest" > <uses-permission android:name ="android.permission.FOREGROUND_SERVICE" /> <application android:allowBackup ="true" android:icon ="@mipmap/ic_launcher" android:label ="@string/app_name" android:roundIcon ="@mipmap/ic_launcher_round" android:supportsRtl ="true" android:theme ="@style/Theme.ServiceTest" > <service android:name =".MyForegroundService" android:enabled ="true" android:exported ="true" > </service > <service android:name =".MyIntentService" /> <service android:name =".MyService" android:enabled ="true" android:exported ="true" /> <activity android:name =".MainActivity" android:exported ="true" > <intent-filter > <action android:name ="android.intent.action.MAIN" /> <category android:name ="android.intent.category.LAUNCHER" /> </intent-filter > </activity > </application > </manifest >
最终的MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 package com.example.servicetest;import androidx.appcompat.app.AppCompatActivity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Build;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private Button mBtnStart, mBtnStop; private Button mBtnBind, mBtnOperate, mBtnUnBind; private Button mBtnIntent; private Button mBtnForeground; private Intent intent; private MyService.MyBinder myBinder; private MyService myService; private ServiceConnection conn; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); intent = new Intent (this , MyService.class); Log.d(TAG, "onCreate: ThreadId" +Thread.currentThread().getId()); conn = new ServiceConnection () { @Override public void onServiceConnected (ComponentName name, IBinder binder) { Log.d(TAG, "ServiceConnected" ); myBinder = (MyService.MyBinder) binder; myService = myBinder.getService(); } @Override public void onServiceDisconnected (ComponentName name) { Log.d(TAG, "ServiceDisconnected" ); myBinder = null ; myService = null ; } }; initView(); initClick(); } private void initClick () { mBtnStart.setOnClickListener((View view)->{ startService(intent); }); mBtnStop.setOnClickListener((View view)->{ stopService(intent); }); mBtnBind.setOnClickListener((View view)->{ bindService(intent, conn, BIND_AUTO_CREATE); }); mBtnOperate.setOnClickListener((View view)->{ if (myService != null ) { String ret = myService.doSomeOperation("abc" ); Toast.makeText(this , ret, Toast.LENGTH_SHORT).show(); } }); mBtnUnBind.setOnClickListener((View view)->{ if (myBinder != null ){ unbindService(conn); } }); mBtnIntent.setOnClickListener((View view)->{ Intent intent1 = new Intent (this , MyIntentService.class); intent1.putExtra("count" ,20 ); startService(intent1); intent1.putExtra("count" ,5 ); startService(intent1); }); mBtnForeground.setOnClickListener((View view)-> { Intent intent1 = new Intent (this , MyForegroundService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startService(intent1); } }); } private void initView () { mBtnStart = findViewById(R.id.btn_start); mBtnStop = findViewById(R.id.btn_stop); mBtnBind = findViewById(R.id.btn_bind); mBtnOperate = findViewById(R.id.btn_operate); mBtnUnBind = findViewById(R.id.btn_unbind); mBtnIntent = findViewById(R.id.btn_intent); mBtnForeground = findViewById(R.id.btn_foreground); } }