Java Question Service in a B4A library

Johan Schoeman

Expert
Licensed User
Longtime User
I am starting a service like this:

B4X:
    public void Initialize(BA paramBA, String EventName) {
        this.eventName = EventName.toLowerCase(BA.cul);
        ba = paramBA;

        conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
              //Bind successfully
              scanservice = ((IMyBinder) iBinder).getService();
              if (ba.subExists(eventName + "_onbind")) {
                ba.raiseEvent2(ba, false, eventName + "_onbind", true, new Object[] {});
              }        
        
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
              BA.Log("scanservice disconnected");
              scanservice = null;
              //ba.raiseEventFromDifferentThread(ba.applicationContext, null, 0, eventName + "_onunbind", true, new Object[] {});
            }
        };
 
         intent = new Intent(ba.context,ScanService.class);
        ba.context.bindService(intent, conn, 1);
    }

it works 100%. But when I "unbind" the service with...
B4X:
ba.context.unbindService(conn);
.....and then quite and restart the app the scanner wont work. I have logged various variables and scannerservice is definitely not null upon a restart of the app.

If I set scannerservice to null when quitting the app and then restart the app then it works. My question is - if I set scannerservice to null when quitting the app, does it actually stop/kill the service that I have started before?
 

Johan Schoeman

Expert
Licensed User
Longtime User
Are you sure that the process was actually killed?

Is this Initialize method actually called when the app is restarted?
It definitely gets there Erel. Have added some logging statements is the service as well as in the wrapper. When I use ba.context.unbindService(conn) I get the following in the IDE log:
B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
in Initialize
** Activity (main) Resume **
in onCreate of ScanService
scanservice = com.qs.service.ScanService@48f1863
in B4A onbind
in scanCode
in addListener3
in B4A and result = 6009702269245
** Activity (main) Pause, UserClosed = true **
in onDestroy of ScanService
** Activity (main) Create, isFirst = false **
in Initialize
** Activity (main) Resume **
in onCreate of ScanService
scanservice = com.qs.service.ScanService@8f29caa
in B4A onbind
in scanCode
in addListener3

The first scanservice (@48F1863) is when I start the app after installing it (compile the B4A project). It then does a successful scan (barcode = 6009702269245). I then closed the app and restarted it. So it seems as if the old service is destroyed and a new service is created (@8f29caa). But when then trying to scan nothing happens.

If I comment out ba.context.unbindService(conn) then the service is not destroyed as it logs the same @xxxxxxx for the service when I close and restart the app.

The wrapper code looks as follows:

B4X:
package pda3506newsdkwrapper;

import anywheresoftware.b4a.AbsObjectWrapper;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.Hide;
import anywheresoftware.b4a.BA.Pixel;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;
import anywheresoftware.b4a.BALayout;
import anywheresoftware.b4a.BA.DependsOn;
import anywheresoftware.b4a.keywords.Common.DesignerCustomView;
import anywheresoftware.b4a.objects.LabelWrapper;
import anywheresoftware.b4a.objects.PanelWrapper;
import anywheresoftware.b4a.objects.ViewWrapper;
import anywheresoftware.b4a.BA.ActivityObject;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.IOnActivityResult;
import anywheresoftware.b4a.BA.Permissions;

import android.content.Intent;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.graphics.Color;

import java.util.ArrayList;

//import com.qs.acivity.MainActivity;

import com.qs.demo3506.R;
import com.qs.service.ScanService;
import com.qs.service.ScanService.IMyBinder;
import com.qs.wiget.App;

import android.posapi.PosApi;
import android.posapi.PosApi.OnCommEventListener;
import android.widget.Toast;

import android.content.ServiceConnection;

import android.os.IBinder;
import android.os.Binder;
import android.content.ComponentName;

//@ActivityObject
@ShortName("PDA3506NewSDK_2")
@Events(values={"scan_result(scanresult As String)", "onbind()"})
//@Author("Github: Jean Carlos, Wrapped by: Johan Schoeman")
//@Version(1.00f)
@DependsOn(values={"IdCardUartLib", "core123", "zypos1.8"})
@Permissions(values={"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.NFC", "android.permission.READ_PHONE_STATE", "android.permission.READ_EXTERNAL_STORAGE",
                     "android.permission.RECEIVE_BOOT_COMPLETED"})

public class pda3506newsdkWrapper_2 {

   
    @Hide
    public static BA ba;
    @Hide
    public static String eventName;
   
    private byte mGpioPower = 0x1E ;//PB14
    private byte mGpioTrig = 0x29 ;//PC9

    private int mCurSerialNo = 3; //usart3
    private int mBaudrate = 4; //9600   
   
//    private PosApi  mApi;
   
    private ScanService scanservice = null;

    private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
              //Bind successfully
              scanservice = ((IMyBinder) iBinder).getService();
              BA.Log("scanservice = " + scanservice);
              if (ba.subExists(eventName + "_onbind")) {
                ba.raiseEvent2(ba, false, eventName + "_onbind", true, new Object[] {});
              }            
            
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
              BA.Log("scanservice disconnected");
              scanservice = null;
              //ba.raiseEventFromDifferentThread(ba.applicationContext, null, 0, eventName + "_onunbind", true, new Object[] {});  
            }
        };   
   
    IMyBinder binder;
    Intent intent;



    public void Initialize(BA paramBA, String EventName) {
        this.eventName = EventName.toLowerCase(BA.cul);
        ba = paramBA;
        BA.Log("in Initialize");
       
    }
   
    public void setStartIntent() {
        intent = new Intent(ba.context,ScanService.class);
        ba.context.bindService(intent, conn, 1);
    }
   
    private void openDevice(){
        //open power
        scanservice.mApi.gpioControl(mGpioPower,0,1);
        scanservice.mApi.extendSerialInit(mCurSerialNo, mBaudrate, 1, 1, 1, 1);
    }

    public void closeDevice(){
        //close power
        scanservice.mApi.gpioControl(mGpioPower,0,0);
        scanservice.mApi.extendSerialClose(mCurSerialNo);
        ba.context.unbindService(conn);
        conn = null;
        scanservice = null;
    }   
   
    public void scanCode() {
        BA.Log("in scanCode");
        addListener3();
        scanservice.mApi.gpioControl(mGpioPower,0,0);
        scanservice.mApi.gpioControl(mGpioPower,0,1);
        scanservice.mApi.extendSerialInit(mCurSerialNo, mBaudrate, 1, 1, 1, 1);
        scanservice.mApi.gpioControl(mGpioTrig, 0, 1);
        scanservice.mApi.gpioControl(mGpioTrig, 0, 0);   
    }
   
    private void stopScanCode() {
        scanservice.mApi.gpioControl(mGpioTrig, 0, 1);
    }
   
    @Hide
    public void addListener3(){
        BA.Log("in addListener3");
        scanservice.setCallback(new ScanService.Callback() {
            @Override
            public void scan_result() {

              if (ba.subExists(eventName + "_scan_result")) {
                ba.raiseEvent2(ba, false, eventName + "_scan_result", true, new Object[]{scanservice.getScanValue()});
              }
            }
           
        });
    }
    
}


and the B4A code as follows:
B4X:
Region  Project Attributes
    #ApplicationLabel: b4aPDA3506NewSDK_2
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: portrait
    #CanInstallToExternalStorage: False
#End Region

#AdditionalRes: ..\LibRes

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.

End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
   
    Dim pd As PDA3506NewSDK_2

    Private Button1 As Button
    Private Label1 As Label
   
   

End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("main")
   
    pd.Initialize("myscan")
    Label1.Visible = False

End Sub

Sub Activity_Resume
   
    pd.setStartIntent
   

End Sub

Sub Activity_Pause (UserClosed As Boolean)
   
    pd.closeDevice
   
End Sub


Sub Button1_Click
   
    Label1.Visible = False
    pd.scanCode
   
End Sub

Sub myscan_scan_result(result As String)
    Label1.Visible = True
    Log("in B4A and result = " & result)
    Label1.Text = result
   
End Sub

Sub myscan_onbind()
    Log("in B4A onbind")
   
End Sub

and the B4A manifest:
B4X:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: https://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
SetApplicationAttribute(android:name, "com.qs.wiget.App")
'End of default text.

AddApplicationText(<receiver android:name="com.qs.service.StartReceiver" >

        </receiver>)
       
AddApplicationText(<service android:name="com.qs.service.ScanService" >

        </service>)
 

Johan Schoeman

Expert
Licensed User
Longtime User
The app is not really restarted. It is only resumed.

Consider keeping the connection open and let the OS kill the process when the app is in the background.
You should move all the scanner related code to the starter service.
Thanks Erel - will let it die a natural death....
 
Top