Does HMS ML Kit supporting for Background Thread works?

245 views Asked by At

I am using HMS ML Kit in android app to analyse the face detection from a background service. I am unable to initialise the MLFaceAnalyzer. Here below is Service class code snippet

@Suppress("Unused") class TestService : Service() {

private val TAG: String = "FaceDetectionPresenterHw"
private var faceDetectionPresenterhw: FaceDetectionPresenterHw? = null
private var isNotificationCalled = false

private fun createNotification() {

    isNotificationCalled = true

    val notificationIntent = Intent(this, MyActivity::class.java)
    notificationIntent.putExtra(Constants.INTENT_EXTRA_TYPE, "Background Service")
    notificationIntent.putExtra(Constants.INTENT_EXTRA_CHILD_ID, childId)

    val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT)

    val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val channelId = getString(R.string.default_notification_channel_id)
    val channelName = getString(R.string.channel_name)// The user-visible name of the channel.

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val importance = NotificationManager.IMPORTANCE_DEFAULT
        val mChannel = NotificationChannel(
            channelId, channelName, importance
        )
        mChannel.setSound(null, null)
        mChannel.enableVibration(false)
        notificationManager.createNotificationChannel(mChannel)
    }

    val notification = NotificationCompat.Builder(this, channelId)
        .setSmallIcon(R.drawable.ic_stat_notification)
        .setContentTitle(“MyApp”)
        .setDefaults(0)
        .setContentText("MyApp is running")
        .setContentIntent(pendingIntent).build()

    startForeground(1337, notification)
}

override fun onCreate() {
    super.onCreate()

    if (!isNotificationCalled) {
        createNotification()
    }

   faceDetectionPresenterhw = FaceDetectionPresenterHw(this@TestService)
   

}

@SuppressLint("MissingPermission")
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

    Log.d(TAG,"Service started")

  
    if (!isNotificationCalled) {
        createNotification()

    }

    if (Utils.permissionCheck(this@TestService)) {
      faceDetectionPresenterhw!!.startCamera()
    } else {
        stopSelf()
    }
    return START_STICKY
}

override fun onDestroy() {
    isNotificationCalled = false
    isDestroyCalled = true

    faceDetectionPresenterhw!!.stopCamera()


    super.onDestroy()
}

override fun onBind(intent: Intent): IBinder? {
    return null
}
}

FaceDetectionPresenter class code snippet is here below

class FaceDetectionPresenterHw(private val context: Context) : FaceDetectionInterface, KoinComponent {

private var cameraConfiguration: CameraConfiguration? = null
private var lensEngine: LensEngine? = null
private var preview: LensEnginePreview? = null

init {
    faceDetectorCreate(false)
}

override fun faceDetectorCreate(orientation: Boolean) {
    Log.d(TAG, "faceDetectorCreate()")
    cameraConfiguration = CameraConfiguration()
    createCameraSource()
}


private fun createCameraSource() {
    if (lensEngine == null) {
        Log.d(TAG, "createCameraSource() ${context ==null} ${cameraConfiguration ==null} ")
        lensEngine = LensEngine(context, this.cameraConfiguration)
    }

    setDetectorOptions()

}


private fun setDetectorOptions() {

    Log.d(TAG, "Option 1")
    val options: MLFaceAnalyzerSetting = MLFaceAnalyzerSetting.Factory()
            .setPerformanceType(MLFaceAnalyzerSetting.TYPE_SPEED)
            .setFeatureType(MLFaceAnalyzerSetting.TYPE_FEATURES)
            .setShapeType(MLFaceAnalyzerSetting.TYPE_SHAPES)
            .setKeyPointType(MLFaceAnalyzerSetting.TYPE_KEYPOINTS)
            .setTracingAllowed(true, MLFaceAnalyzerSetting.MODE_TRACING_FAST)
            .allowTracing(MLFaceAnalyzerSetting.MODE_TRACING_FAST)
            .create()


    Log.d(TAG, "Option  ${lensEngine != null} -- ${context==null} ")
    lensEngine?.setMachineLearningFrameTransactor(LocalFaceTransactor(options, context))
}

override fun startCamera() {
    Log.d(TAG, "Start Camera")
    if (lensEngine != null) {
        try {
            Log.d(TAG, "Start Camera inside")
            preview = LensEnginePreview(context)
            preview!!.start(lensEngine, true)
        } catch (e: IOException) {
            Log.e("FaceDetectionPr", "Unable to start lensEngine.", e)
            lensEngine!!.release()
            lensEngine = null
        }
    }
}


private inner class LocalFaceTransactor(options: MLFaceAnalyzerSetting?, context: Context) : BaseTransactor<List<MLFace?>?>() {

    init {

        detector = MLAnalyzerFactory.getInstance().getFaceAnalyzer(options)

    }
}
}

below issue is coming

android.content.Context com.huawei.agconnect.AGConnectInstance.getContext()' on a null object reference

Logcat

2021-07-07 13:20:28.051 16868-16868/? E/AndroidRuntime: FATAL EXCEPTION: main

Process: co.sample:sampleService, PID: 16868 java.lang.RuntimeException: Unable to create service co.sample.services.sampleService: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context com.huawei.agconnect.AGConnectInstance.getContext()' on a null object reference at android.app.ActivityThread.handleCreateService(ActivityThread.java:4169) at android.app.ActivityThread.access$2400(ActivityThread.java:273) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2055) at android.os.Handler.dispatchMessage(Handler.java:112) at android.os.Looper.loop(Looper.java:216) at android.app.ActivityThread.main(ActivityThread.java:7625) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context com.huawei.agconnect.AGConnectInstance.getContext()' on a null object reference at com.huawei.hms.mlsdk.common.MLApplication.getInstance(MLApplication.java:126) at com.huawei.hms.mlsdk.MLAnalyzerFactory.getInstance(MLAnalyzerFactory.java:1) at co.sample.services.facedetection.FaceDetectionPresenterHw$LocalFaceTransactor.(FaceDetectionPresenterHw.kt:352) at co.sample.services.facedetection.FaceDetectionPresenterHw.setDetectorOptions(FaceDetectionPresenterHw.kt:63) at co.sample.services.facedetection.FaceDetectionPresenterHw.createCameraSource(FaceDetectionPresenterHw.kt:86) at co.sample.services.facedetection.FaceDetectionPresenterHw.faceDetectorCreate(FaceDetectionPresenterHw.kt:75) at co.sample.services.facedetection.FaceDetectionPresenterHw.(FaceDetectionPresenterHw.kt:43) at co.sample.services.sampleService.onCreate(sampleService.kt:81) at android.app.ActivityThread.handleCreateService(ActivityThread.java:4150) at android.app.ActivityThread.access$2400(ActivityThread.java:273)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2055)  at android.os.Handler.dispatchMessage(Handler.java:112)  at android.os.Looper.loop(Looper.java:216)  at android.app.ActivityThread.main(ActivityThread.java:7625)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)  2021-07-07 13:20:28.078 1486-7158/? I/chatty: uid=1000(system) Binder:1486_1D expire 1 line 2021-07-07 13:20:28.091 1486-6494/? I/chatty: uid=1000(system) Binder:1486_1C expire 6 lines 2021-07-07 13:20:28.095 1915-4243/? I/BoosterSwitchP: notifyUidState do nothing 2021-07-07 13:20:28.095 1915-4243/? I/DeepNoDisturbP: notifyUidState 2021-07-07 13:20:28.095 1915-4243/? I/BrowserChrP: notifyUidState 2021-07-07 13:20:29.423 16932-16932/? D/ActivityThread: Attach thread to application 2021-07-07 13:20:30.122 16932-16932/? E/AndroidRuntime: FATAL EXCEPTION: main Process: co.sample:sampleService, PID: 16932 java.lang.RuntimeException: Unable to create service co.sample.services.sampleService: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context com.huawei.agconnect.AGConnectInstance.getContext()' on a null object reference at android.app.ActivityThread.handleCreateService(ActivityThread.java:4169) at android.app.ActivityThread.access$2400(ActivityThread.java:273) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2055) at android.os.Handler.dispatchMessage(Handler.java:112) at android.os.Looper.loop(Looper.java:216)

What is wrong here?

4

There are 4 answers

4
zhangxaochen On

Does the background service execute the following code in the Service class?

MLFaceAnalyzer analyzer = MLAnalyzerFactory.getInstance().getFaceAnalyzer(setting);

like following:

enter image description here

If the MLFaceAnalyzer object is created in the Service class, the test result is correct.Please describe your problem in more detail so we can help you properly.

1
Basavaraj On

​ Check 

isNotificationCalled = true

variable is already true.

if (!isNotificationCalled) {
    createNotification()

}

In the above code your creating a notification only when the variable is false. So the condition is failing. Check it by making isNotificationCalled = false 

Then notification will create.

Make sure you have added the ag-connect.json file in the app directory

1
Zinna On

The error is caused by context being null, which is the main context not yet ready.

Because it is trying to get FaceDetectionPresenterHw in onCreate when the context creation could be not done yet.

so do not call to use FaceDetectionPresenterHw inside onCreate. only declare variable and later in time, call getInstance, then use it. so that time Context is not null.

=============

additional edit:

use code below before in Service that starts using Analyzer

enter image description here

0
The Bala On

To use HMS ML Kit from background service, We should need to initialise AGConnect Instance in out Application's OnCreate() Method like mentioned below

class MyApplication : Application(){

override fun onCreate() {
    super.onCreate()

    if (AGConnectInstance.getInstance() == null) {
        AGConnectInstance.initialize(applicationContext)
    }
}