On Android services using --Service (b)

Related documents:
Android services using --service Analysis (a)

1. IntentService basic use

If the thread takes place directly to the Service in the onStart()process, likely to cause ** ANR (Application Not Responding) ** abnormal .Service is not a separate process, with the same application in a process; Service is not a thread to avoid time-consuming operation in the Service.

We can use multi-threading technology before, opening a child thread in each specific service method, the logic in here to deal with time-consuming, it is a standard logic can be written as:

public class MyService extends Service {
    ...
    @override
        public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @override
            public void run() {
                //处理具体逻辑
                stopself();//执行完毕自动停止服务
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }
}

However, this method is easy to forget, or forget to call open threadstopSelf()

IntentServiceService and handling inherited from a class asynchronous request, there is a worker in IntentService to handle time-consuming operation, the requested records Intent will join the queue.

IntentServiceYou do the following :

  • Create a default worker threads for application delivery outside the main thread to perform onStartCommand()all of Intent
  • Create a work queue for passing one by one Intent to onHandleIntent()achieve
  • In After processing all requests to stop the service to start , because you do not call yourselfstopSelf()
  • Provides onBind()a default implementation (returns null)
  • Providing onStartCommand () The default implementation can be sequentially transmitted to the work queue and IntentonHandleIntent()

Thus, and only achieved a constructor onHandleIntent()method may be

To sum up : client to start IntentService by startService (Intent), without having to manually control IntentService region, when the job is finished, IntentService will stop automatically; you can start IntentService several times, each time-consuming operation will work queue IntentService way of onHandleIntent callback method, and each time a worker thread will execute, execute a complete, to the two so!

A simple example :

Modify On Android services --service use (a) of the Code

  • Create a new class that inherits IntentService MyIntentService
public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
    	// 在这里执行具体的逻辑,做你想要的处理
        Log.d("MyIntentService", "Thread id is" + Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService", "onDestory ececuted");
    }
}
  • Modify activity_main.xml, add a button to start the service MyIntentService
<Button
    android:id="@+id/start_intent_service"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Start IntentService" />
  • Last Modified MainActivity code
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    //...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //...
        Button startIntentService = (Button) findViewById(R.id.start_intent_service);
        startIntentService.setOnClickListener(this);
    }
    
     @Override
    public void onClick(View v) {
        switch (v.getId()) {
                //...
                case R.id.start_intent_service:
                Log.d("MainActivity", "Thread id is" + Thread.currentThread().getId());
                Intent intentService = new Intent(this, MyIntentService.class);
                startService(intentService);
                break;
                 default:
                break;

        }
    }
}
  • The last registration services in AndroidManifest.xml
<service android:name=".MyIntentService" />

Remarks :

  • Since IntentService need the class definition provides a constructor with no arguments , and must call the parent class in its interior with a constructor parameter.
  • To achieve subclass onHandleIntent()of this abstract method, processing logic in this specific method, the processing tasks through a serial
  • After running this service is automatically stopped, rewrite onDestroy()method.

1.1 IntentService Why do not need to create a new thread

// IntentService 源码中的 onCreate() 方法
@Override
public void onCreate() {
    super.onCreate();
    // HandlerThread 继承自 Thread,内部封装了 Looper,在这里新建线程并启动,所以启动 IntentService 不需要新建线程。
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    // 获得工作线程的 Looper,并维护自己的工作队列。
    mServiceLooper = thread.getLooper();
    // mServiceHandler 是属于工作线程的。
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

private volatile ServiceHandler mServiceHandler;

private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        // onHandleIntent 方法在工作线程中执行,执行完调用 stopSelf() 结束服务。
        onHandleIntent((Intent)msg.obj);
        stopSelf(msg.arg1);
    }
}

@WorkerThread
protected abstract void onHandleIntent(Intent intent);

1.2 is not recommended by bindService () start IntentService

@Override
public IBinder onBind(Intent intent) {
    return null;
}

IntentService source in onBind () by default returns null, not suitable for bindService () to start the service

1.3 times IntentService will start the implementation of the order to stop the service, not the implementation of subsequent events

IntentService used in Handler, Looper, MessageQueue mechanism to send messages to the thread to be executed, so many times to start IntentService not re-create new services and new thread, but the news added to the message queue waiting to be executed, and if the service stop, will clear the message queue of the message, subsequent events can not be executed .

2. Reception

Service is one of the four Android components, but background services when insufficient system memory might be killed by the system, how to get through the background service may not be killed, there are several ideas:

  1. Improve the Service's priorities
<!-- 为防止Service被系统回收,可以尝试通过提高服务的优先级解决,1000是最高优先级,数字越小,优先级越低 -->  
android:priority="1000"
  1. The Service written system services, will not be recovered
    in Manifest.xml file set persistent attribute to true , will enable the service from the effects of out-of-memory killer is. However, this approach must be careful, too many system service would seriously affect the overall efficiency of the system.

  2. The front desk service intoforeground service
    rewriting onStartCommand method, using a StartForeground(int,Notification)method to start the service.

  3. With Android broadcasting system
    run state broadcasting system utilizing ANDROID inspection Service, if killed, will rise again, the system broadcasts are Intent.ACTION_TIME_TICK, this broadcast is sent once every minute, every minute we can check the status of a Service operation, if it has been ended , and then restart Service

Reception those considered the user knows (user recognized) and does not allow the system to kill the service when insufficient system memory. Front desk must provide a notice to the status bar, it is placed in the running (Ongoing) under the heading - which means that the notification can only be released after the service termination notice or actively removed from the front desk.

The service is set to reception timing in general are:

  • Requiring immediate implementation
  • Important (must be completed)
  • Users can perceive (in most cases the initiative launched by the user)
  • There are definite start time and end time

The front desk Typical applications include playing music, to complete the purchase transaction, location tracking and so on. Between the front desk and general services biggest difference is that : it will have a running icon in the status bar display system, pull down the status bar you can see more detailed information.

Prior to 2.1 Androd 8.0 front desk before use

Not complicated in Android does not do too many restrictions on the background services before 8.0, create a front desk, modify the aforementioned MyService Code:

public class MyService extends Service {
    //.......
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService", "onCreate executed");
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("this is the content title")
                .setContentText("this is the content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .setContentIntent(pi)
                .build();
        startForeground(1, notification);
    }
    //......
}

Notification can be viewed on
Android notification --Notification use Analysis (a)
Android notification --Notification use analysis (two)
Android notification --Notification 8.0 Detailed Adapter

Android8.0 later sat Notification large changes in Android9.0 version, if you want to set the front desk, you need to apply for FOREGROUND_SERVICEpermission, which is a common authority, no dynamic applications only need to add AndroidMenifest.xml file :


 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
public class ForeService extends Service {

    private static final String CHANNEL_ID = "fore_Service";

    public ForeService() {
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //处理任务

        return START_STICKY;
    }
    @SuppressLint("CommitPrefEdits")
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("foreground", "onCreate");
        //如果API在26以上即版本为O则调用startForefround()方法启动服务
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            setForegroundService();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     *通过通知启动服务
     */
    @TargetApi(Build.VERSION_CODES.O)
    public void  setForegroundService()
    {
        //设定的通知渠道名称
        String channelName = "fore";
        //设置通知的重要程度
        int importance = NotificationManager.IMPORTANCE_HIGH;
        //向系统注册通知渠道,注册后不能改变重要性以及其他通知行为
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //构建通知渠道
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, channelName, importance);
        notificationManager.createNotificationChannel(channel);

        //在创建的通知渠道上发送通知
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
        builder.setSmallIcon(R.drawable.ic_launcher_foreground) //设置通知图标
                .setContentTitle("前台服务标题")//设置通知标题
                .setContentText("前台服务通知内容")//设置通知内容
                .setAutoCancel(true) //用户触摸时,自动关闭
                .setOngoing(true);//设置处于运行状态
        //将服务置于启动状态 NOTIFICATION_ID指的是创建的通知的ID
        startForeground(101,builder.build());
    }
}

Activity in the services open to:

Intent foreIntentService = new Intent(this, ForeService.class);
                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                {
                    startForegroundService(foreIntentService);
                }
                else{
                    startService(foreIntentService);
                }

Remarks :

  • After Android 8.0, is to call the front desk to open startForegroundService(), and in turn the service must be called within five seconds startForeground()of this method to enhance the service for the reception, if more than this time will be reported IllegalArgumentException: Not allowed to start service Intent error.
  • Note that startForeground()the first parameter can not be 0 ( the pit miserable, Bitter Tears )

Guess you like

Origin blog.csdn.net/weixin_43499030/article/details/90230265