Implementing Anyline
This section will guide you through the implementation process of the Anyline Scan View, including configuration and handling scan results.
Adding a Scan View
-
Open the
Main.axml
file in yourResources/Layout
node-
Alternatively, create new
ScanActivity.java
andscan_activity.axml
Activity and Layout files, and open thescan_activity.axml
file
-
-
Switch from the Design tab to the Source tab
-
Change the XML Code to the example shown below:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/main_layout">
<io.anyline2.view.ScanView
android:id="@+id/scan_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
You now added a ScanView
to your Activity.
Your scanning use-case depends on initializing this ScanView
with a specific configuration. For this documentation show-case, we’re going to scan the MRZ string of Identification Documents.
Providing an Anyline Configuration to the Scan View
With the Anyline Configuration, you can define your whole use case, including scanning parameters and the look & feel of your scanning view.
The configuration parameters define the visual information presented to the user, as well as the scan settings (like the resolution, etc.) and feedback that is presented to the user.
Have a look at the Scanning Capabilities section for more specific implementation details.
You can adapt your scan view easily by adding a .json file as an asset to your project and loading it. In this example, we will create a .json file and configure it for the MRZ scanning.
Visual Studio
-
In your Assets treenode, right-click on the folder and select Add > New Item…
-
Choose Visual C# > Text File and name it
scanConfig.json
Build Action
Make sure that the build action for this file is set to AndroidAsset. |
Now open the file and paste the code from the following example:
{
"cameraConfig": {
"captureResolution": "1080p",
"zoomGesture": true
},
"flashConfig": {
"mode": "manual",
"alignment": "top_left"
},
"viewPluginConfig": {
"pluginConfig": {
"id": "ID",
"cancelOnResult": true,
"mrzConfig": {
"strictMode": false,
"cropAndTransformID": false
}
},
"cutoutConfig": {
"style": "none",
"maxWidthPercent": "90%",
"maxHeightPercent": "90%",
"alignment": "center",
"ratioFromSize": {
"width": 50,
"height": 31
},
"cropPadding": {
},
"outerColor": "000000",
"outerAlpha": 0.3,
"strokeWidth": 2,
"strokeColor": "0099FF",
"cornerRadius": 4,
"feedbackStrokeColor": "0099FF"
},
"scanFeedbackConfig": {
"style": "rect",
"visualFeedbackRedrawTimeout": 100,
"strokeWidth": 2,
"strokeColor": "0099FF",
"fillColor": "220099FF",
"beepOnResult": true,
"vibrateOnResult": true,
"blinkAnimationOnResult": false
}
}
}
This JSON builds the whole MRZ scanning use-case.
The Activity Lifecycle
In the Scan Activity lifecycle, it’s important to configure/initialize and start/stop Anyline at the right places. This section will cover where you should implement which functionality in order to avoid pitfalls and provide a smooth scanning experience.
OnCreate
The OnCreate
lifecycle method is where the ScanView
should be set up.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
try
{
SupportActionBar.SetHomeButtonEnabled(true);
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
Title = "I'm scanning with Anyline!"
Window.SetFlags(WindowManagerFlags.KeepScreenOn, WindowManagerFlags.KeepScreenOn);
SetContentView(Resource.Layout.scan_activity);
_scanView = FindViewById<IO.Anyline2.View.ScanView>(Resource.Id.scan_view);
// the initialization parses the JSON configuration file and builds the whole use-case
_scanView.Init("scan_config.json");
// attributes this activity as the listener for results
_scanView.ScanViewPlugin.ResultReceived = this;
// handle camera open events
_scanView.CameraView.CameraOpened += ScanView_CameraOpened;
// handle camera error events
_scanView.CameraView.CameraError += ScanView_CameraError;
_isInitialized = true;
}
catch (Exception e)
{
System.Diagostics.Debug.WriteLine(e.ToString());
// treat the exception accordingly
}
}
Start Scanning
OnResume
is usually the lifecycle method where you want to start the scanning process. To do so, you can follow the example below:
protected override void OnResume()
{
base.OnResume();
try
{
if (_isInitialized)
_scanView.Start();
}
catch (Exception e)
{
System.Diagostics.Debug.WriteLine(e.ToString());
// treat the exception accordingly
}
}
Stop Scanning
When your ScanView loses focus, you should also stop the scanning process.
The OnPause
is usually the lifecycle method where you want to stop the scanning process. To do so, you can follow the example below:
protected override void OnPause()
{
base.OnPause();
StopScanning();
}
Also, make sure to stop the scanning process when the Home and Back buttons are tapped. You can also use the Dispose()
method to release any attached listener and avoid memory leaks.
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
StopScanning();
return true;
default:
return base.OnOptionsItemSelected(item);
}
}
public override void OnBackPressed()
{
base.OnBackPressed();
StopScanning();
}
private void StopScanning()
{
if (_scanView != null)
{
_scanView.Stop();
_scanView.CameraView.ReleaseCameraInBackground();
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
try
{
if (_scanView != null)
{
_scanView.Dispose();
_scanView.CameraView.CameraOpened -= ScanView_CameraOpened;
_scanView.CameraView.CameraError -= ScanView_CameraError;
_scanView = null;
_isInitialized = false;
}
}
catch (Exception) { }
}
Handling Scan Results
In this example, we’ve set our own ScanActivity as the listener for results (in the OnCreate
method). To receive those results, the ScanActivity needs to implement the IEvent
interface.
The interface can be implemented by right-clicking on the IEvent
interface and selecting Implement Interface. A method that is called each time our scan view is scanning and reporting a result will be generated.
public class ScanActivity : AppCompatActivity, IO.Anyline2.IEvent
{
...
public void EventReceived(Java.Lang.Object data)
{
var scanResult = (data as IO.Anyline2.ScanResult);
System.Diagnostics.Debug.WriteLine(scanResult.Result);
}
...
}
Cleaning up Resources
Anyline is using a lot of memory and processing power in order to perform scans in the fastest and most accurate way possible. Therefore, it is important that the resources are freed again. Usually, the GarbageCollector (GC
) does this automatically. However, it cannot clean up a resource if there is still a handle on that resource, for example an Anyline scanning thread is still running or Events are still registered. Please also take care of freeing the Anyline images from the scan result when you don’t need to display them anymore.
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
try
{
if (_scanView != null)
{
_scanView.Dispose();
_scanView.CameraOpened -= ScanView_CameraOpened;
_scanView.CameraError -= ScanView_CameraError;
_scanView = null;
_isInitialized = false;
}
}
catch (Exception) { }
}
Full Source Code
You can find the full source code on GitHub.
Open the solution in Visual Studio, build and deploy the application onto your Android device. For more Android-specific documentation, please refer to the documentation of the Anyline Native Android SDK.
Reduce Final App Size
Check now the Reduce App Size to learn how to remove unnecessary assets and reduce the final app’s size.