I try to collect a custom metric from an Android application using Google Analytics SDK v3.
The doc says to do it like this :
// May return null if EasyTracker has not yet been initialized with a
// property ID.
EasyTracker easyTracker = EasyTracker.getInstance();
// Set the custom metric to be incremented by 5 using its index.
easyTracker.set(Fields.customMetric(1), 5);
// Custom metric value sent is with this screen view.
easyTracker.send(MapBuilder
.createAppView("Home screen")
.build()
);
https://developers.google.com/analytics/devguides/collection/android/v3/customdimsmets
However set(Fields.customMetric(1), 5); is undefined because only EasyTracker.set(String,String) exists. The documentation seems not up to date with the v3 SDK.
So here is what I tried instead :
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onStart() {
super.onStart();
EasyTracker.getInstance(this).activityStart(this);
}
#Override
public void onStop() {
super.onStop();
EasyTracker.getInstance(this).activityStop(this);
}
public void onDetected()
{
EasyTracker easyTracker = EasyTracker.getInstance(this);
easyTracker.set(Fields.customMetric(1), "1"); //not working
easyTracker.send(MapBuilder
.createEvent("cat", "detected", "beacon", (long) 1) // also tried with createAppView
.set(Fields.customMetric(1), "1") // not working
.set("&cm1", "1") // not working
.build());
}
But none of this actually works. How can I collect custom metrics using Google Analytics Android SDK ?
Have you looked at using the method:
Tracker.setCustomMetric(int, long)
I have done something similar with a custom dimension and it worked for me (tracker.setCustomDimension(String, string)). Another gotcha that I ran into is that I had to make sure that the dimension was defined in the admin panel before GA would accept it.
Related
I'm developing Android app on Android studio using Opencv library and when I try to open my app it opens then right after that it closes and displaying crash message. I'm new on mobile development
Using : OpenCV310, Android Studio 3.0,
public class ScanLicensePlateActivity extends AppCompatActivity {
protected AnylineOcrScanView scanView;
private LicensePlateResultView licensePlateResultView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set the flag to keep the screen on (otherwise the screen may go dark during scanning)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_anyline_ocr);
String license = getString(R.string.anyline_license_key);
// Get the view from the layout
scanView = (AnylineOcrScanView) findViewById(R.id.scan_view);
// Configure the view (cutout, the camera resolution, etc.) via json
// (can also be done in xml in the layout)
scanView.setConfig(new AnylineViewConfig(this, "license_plate_view_config.json"));
// Copies given traineddata-file to a place where the core can access it.
// This MUST be called for every traineddata file that is used
// (before startScanning() is called).
// The file must be located directly in the assets directory
// (or in tessdata/ but no other folders are allowed)
scanView.copyTrainedData("tessdata/GL-Nummernschild-Mtl7_uml.traineddata",
"8ea050e8f22ba7471df7e18c310430d8");
scanView.copyTrainedData("tessdata/Arial.traineddata", "9a5555eb6ac51c83cbb76d238028c485");
scanView.copyTrainedData("tessdata/Alte.traineddata", "f52e3822cdd5423758ba19ed75b0cc32");
scanView.copyTrainedData("tessdata/deu.traineddata", "2d5190b9b62e28fa6d17b728ca195776");
// Configure the OCR for license plate scanning via a custom script file
// This is how you could add custom scripts optimized by Anyline for your use-case
AnylineOcrConfig anylineOcrConfig = new AnylineOcrConfig();
anylineOcrConfig.setCustomCmdFile("license_plates.ale");
// set the ocr config
scanView.setAnylineOcrConfig(anylineOcrConfig);
// initialize with the license and a listener
scanView.initAnyline(license, new AnylineOcrListener() {
#Override
public void onReport(String identifier, Object value) {
// Called with interesting values, that arise during processing.
// Some possibly reported values:
//
// $brightness - the brightness of the center region of the cutout as a float value
// $confidence - the confidence, an Integer value between 0 and 100
// $thresholdedImage - the current image transformed into black and white
// $sharpness - the detected sharpness value (only reported if minSharpness > 0)
}
#Override
public boolean onTextOutlineDetected(List<PointF> list) {
// Called when the outline of a possible text is detected.
// If false is returned, the outline is drawn automatically.
return false;
}
#Override
public void onResult(AnylineOcrResult result) {
// Called when a valid result is found
String results[] = result.getText().split("-");
String licensePlate = results[1];
licensePlateResultView.setLicensePlate(licensePlate);
licensePlateResultView.setVisibility(View.VISIBLE);
}
#Override
public void onAbortRun(AnylineOcrError code, String message) {
// Is called when no result was found for the current image.
// E.g. if no text was found or the result is not valid.
}
});
// disable the reporting if set to off in preferences
if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
SettingsFragment.KEY_PREF_REPORTING_ON, true)) {
// The reporting of results - including the photo of a scanned meter -
// helps us in improving our product, and the customer experience.
// However, if you wish to turn off this reporting feature, you can do it like this:
scanView.setReportingEnabled(false);
}
addLicensePlateResultView();
}
private void addLicensePlateResultView() {
RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.main_layout);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
licensePlateResultView = new LicensePlateResultView(this);
licensePlateResultView.setVisibility(View.INVISIBLE);
mainLayout.addView(licensePlateResultView, params);
licensePlateResultView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startScanning();
}
});
}
private void startScanning() {
licensePlateResultView.setVisibility(View.INVISIBLE);
// this must be called in onResume, or after a result to start the scanning again
scanView.startScanning();
}
#Override
protected void onResume() {
super.onResume();
startScanning();
}
#Override
protected void onPause() {
super.onPause();
scanView.cancelScanning();
scanView.releaseCameraInBackground();
}
#Override
public void onBackPressed() {
if (licensePlateResultView.getVisibility() == View.VISIBLE) {
startScanning();
} else {
super.onBackPressed();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
}}
source code is here.
If possible please help.
Logcat error shown here
Ideally more information regarding the error would be best i.e the opencv library version etc. Given it seems to be an Android issue, I would advise
File and issue or view issues pertaining to this error on their github page. Search for related Android errors to see if they match.
IF you cannot find a related error, file an issue there.
I use GCM in my project.Where do I get an ID, so it is always available at all times? Here is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!CloudMessaging.checkPlayServices(this)) {
return;
}
CloudMessaging.getInstance(this).setRegistrationListener(eventHandler);
}
"but if I turn aside and then expand Programmes at, then again will get ID." ->Possibly:
If I change my orientation, then again I get a new Id.
You can get your ID for GCM
if (m_gcm == null)
{
m_gcm = GoogleCloudMessaging.getInstance(m_context);
}
m_regid = m_gcm.register("Your project id from google api console");
Note : please do this network operation in background thread..
Use SharedPreferences to store your ID once you get a new one.
Steps required: (do this in your onCreate)
Check if you already have a valid GCM id in your SharedPreferences
If you already have one, use it.
Otherwise, request a new one and save it in your SharedPreferences.
I wish to get a bit more detailed statistic about my app instead of standart google statistic. I was advised to use flury. However I dont see tutorial how to integrate it to my app or use it. Can any one explain or give a link to tutorials?
Flurry works with an ID to open a session an retrieve infos. I'm using it and it's quite simple to use.
1 - Head to flurry.com and register your app, which will generate a unique tracking code.
2 - Download and add the FlurryAgent jar to your project libraries. If you're using Eclipse, right-click your project folder, select properties, select Java Build Path, and choose Add External JARs...
3 - Add android.permission.INTERNET to your AndroidManifest.xml.
4 - Add a call to the Flurry agent from the onStart() and onStop() methods of your activities.
Note: replace the ID below with your unique tracking code.
public void onStart()
{
super.onStart();
FlurryAgent.onStartSession(this, "9GKQD4EBX123FEP6874H");
// your code
}
public void onStop()
{
super.onStop();
FlurryAgent.onEndSession(this);
// your code
}
See the answer here
1st you need to download Flurry agent.jar
and add this to your lib folder after that
do the following in following methods
private void getFlurryEvents()
{
HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("Title of page", "Your page Title" );
FlurryAgent.logEvent("View Page",parameters);
}
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
FlurryAgent.onStartSession(this, Constants.FLURRY_API_KEY);
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
//FlurryAgent.onEndSession(this);
}
in onstart method strt the Session and in on stop stop the session and in oncreate add the method getFlurry agent
and get your API key from flurry
I'm trying to use the APK Expansion extension from Google to download expansion files I have hosted with them. I'm also using the code from the SampleDownloadActivity to do this, albeit slightly modified to fit in my app.
My problem is that the download is never initiated. In my class that implements IDownloadClient, onStart() is called, but onServiceConnected() is not.
I have traced this down to this line in DownloaderClientMarshaller:
if( c.bindService(bindIntent, mConnection, Context.BIND_DEBUG_UNBIND) ) {
This always returns false, and therefore the service is not bound.
I'm using the calling activity within a TabHost, which has caused problems for other people. They were saying that you must not pass the TabHost context, rather that the Application context to the connect function. I've changed this by doing:
mDownloaderClientStub.connect(getApplicationContext());
instead of:
mDownloaderClientStub.connect(this);
but it doesn't help, I still get false. I'm doing all my testing on the Emulator if that makes a difference.
I'm really pulling my hair out on this one. If anyone has any ideas, I'd be extremely grateful!
In most cases, bindService() method returns false if the service was not declared in the application's Manifest file.
In my case, the problem was that I had given the wrong class object to the DownloaderClientMarshaller.CreateStub() method. I accidentally used DownloaderService.class instead of MyDownloaderService.class.
When using the downloader API, make sure to pass the correct class object that extends the base DownloaderService.
I recommend using the updated Downloader Library included in Better APK Expansion package. It has this and other issues fixed and also provides simplified API that minimizes chances to shoot yourself in the foot.
To receive the download progress, you will just have to extend the BroadcastDownloaderClient.
public class SampleDownloaderActivity extends AppCompatActivity {
private final DownloaderClient mClient = new DownloaderClient(this);
// ...
#Override
protected void onStart() {
super.onStart();
mClient.register(this);
}
#Override
protected void onStop() {
mClient.unregister(this);
super.onStop();
}
// ...
class DownloaderClient extends BroadcastDownloaderClient {
#Override
public void onDownloadStateChanged(int newState) {
if (newState == STATE_COMPLETED) {
// downloaded successfully...
} else if (newState >= 15) {
// failed
int message = Helpers.getDownloaderStringResourceIDFromState(newState);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onDownloadProgress(DownloadProgressInfo progress) {
if (progress.mOverallTotal > 0) {
// receive the download progress
// you can then display the progress in your activity
String progress = Helpers.getDownloadProgressPercent(
progress.mOverallProgress, progress.mOverallTotal);
Log.i("SampleDownloaderActivity", "downloading progress: " + progress);
}
}
}
}
Check the full documentation on the library's page.
I want to extend a common security check to nearly every view of my application. To do this, I have made this class
public class ProtectedActivity extends ActivityBase {
boolean isAuthenticated = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread validationThread = new Thread()
{
#Override
public void run()
{
try
{
isAuthenticated = UserService.validateToken();
}
catch (FTNIServiceException e)
{
//eat it
}
finally
{
if (!isAuthenticated)
{
startActivity(new Intent(ProtectedActivity.this, SignInActivity.class));
finish();
}
}
}
};
validationThread.start();
}
}
The logic is simple. Validate the user against my restful api to make sure they are signed in. If they aren't, show them to the signin page.
This works great, because to add the security check, all I need to do is inherit from my ProtectedActivity.
public class MainMenuActivity extends ProtectedActivity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
The problem is, however, that I periodically receive View not attached to window manager errors. I understand why this is happening. I am starting a new intent in the parent class, and the child lives on. to attempt to alter it's view even though a new intent has started. What is a better way to handle this so that if a user is not authenticated (such as their session expires serverside), it won't error when sending the user to the sign in screen?
Don't you Thread. Use AsyncTask instead which should handle your references to windows correctly.
On a different note, I would change this to a different implementation. Why don't use the Preferences storage on the phone to store some kind token. If the token is not valid then request a new token and all the stuff you are doing currently. This way is better because you don't want to request a REST call every time.
I imagine something like this (pseudo code)
Check if credentials exist in Preference
if(valid) then do nothing
else use AsyncTask and pop up a loader screen "Waiting..."