Two of my users have reported a problem with my Android application, OftSeen Gestures. Both of them are using a Motorola Droid. The app saves a text file which is just a list of gesture names and phone numbers, both strings. It saves the file to the private data area. I don't know that it is this code that is failing but they report the assigned numbers disappearing after the phone comes out of screen sleep. Since the file is reread in OnCreate each time, I'm assuming the file doesn't exist on return.
As soon as I can get my hands on a Droid I will debug it but in the meantime can you see a reason why this save operation would fail on Droid (no other users have reported this)?
OutputStreamWriter out = new OutputStreamWriter(AppGlobal.getContext().openFileOutput(MAPPINGS_FILE_NAME, 0));
for (String key : mMap.keySet()) {
String number = mMap.get(key).number;
out.write(String.format("%s,%s\n", key, number == null ? "" : number));
}
out.close();
AppGlobal.getContext returns the application context and the MAPPINGS_FILE_NAME resolves to "gesture_mappings.txt".
Like I say, I don't know that this is the problem. It could be something else to do with state management inside the app. If anyone has a Droid, maybe they could download the app from Market and test it for me? Note this is a genuine request for help - not an attempt to increase my downloads.
This was diagnosed as being caused by extended character sets causing line-breaks to be misinterpreted and was solved by explicitly writing the file using UTF8. See How to read and write UTF-8 to disk on the Android? 1
Related
I am trying to diagnose an issue in an app I have written. The issue is a sporadic one, and occurs only under real-world conditions: in the field, away from my PC, and when I’m in the middle of something else, with no resources to spare for immediate debugging. Therefore, my best bet is collecting and analyzing log data.
Unfortunately, by the time I realize the issue has struck again and get around to debugging it, any log data has already rotated out of the Android log as I frequently have other chatty apps running at the same time. Increasing the size of the log buffer has not helped (either Android does not honor it or other apps are still too chatty) so I have abandoned this route.
For this reason, I am now considering having my app log to a separate text file in addition to the regular log.
Now I could easily double every call like
Log.i(TAG, "something happened");
adding another call that writes the same thing to the log file—but that does not seem very elegant to me.
Another option would be to replace all calls to Log with a wrapper that writes the event both to the Android log and the log file.
Question: Does the Android API provide a built-in mechanism for this, i.e. telling Log to write its data to the default log and a text file at the same time? Or do I need to code this by myself?
Edit:
Assumptions:
I know where in my code I need to generate log output (which can happen anywhere, which may or may not involve an exception) and what I want to be written to the log.
Getting log data from the device to my PC is also not a concern (one-man show, I just plug my phone into my PC and transfer the log file).
If you know the current Android API has no built-in mechanism to achieve what I want, then ”no, Android does not support this” is a perfectly acceptable answer. In that case the solution is clear—I would fall back to the wrapper function. I am specifically not looking for a different approach to the problem.
After doing some more research, it seems the Android API does not provide a standard way to do this. There are two possible workarounds:
Mirror output at the source
System.out and System.err output, which is written to the console in desktop systems, writes to the log on Android. These two can be redirected into any PrintStream of your choice, which would give you all Java console output. You can subclass PrintStream to duplicate its input, feeding it into the default stream as well as into a file of your choice.
Create a class which exposes the same methods as android.util.Log. In each method, call through to the respective android.util.Log method and additionally log the data to a file. If you call your class Log (but with a different package name, e.g. org.example.Log), then all you need to do is replace imports of android.util.Log with an import of your class, and any Log method calls will go to your class.
Caveats: This will only give you data explicitly logged by your code (i.e. for which you have the source files), as well as anything that goes to System.out or System.err. It will not include log output from JAR libraries (if you cannot modify their source code), nor any output generated by the system (such as stack traces from default exception handlers) or by other processes (some of which may be system processes and report conditions related to your process).
Read the logs from the command line
This article explains how to read the logs from within Android. In a nutshell:
Android includes a command line utility called logcat on the device, which will give you a continuous feed of log messages until stopped. (Try it by adb shelling into your device and running it. It has a bunch of command-line options to control its behavior. Not sure if it is present on all distributions, though.)
Launch this command via Runtime.getRuntime().exec("logcat"), then obtain the input stream of the process returned. This will give you an input stream of log messages.
According to the article, your app needs the android.permission.READ_LOGS permission to read logs.
I have read statements that certain versions of Android (4.2 was mentioned) do not allow this permission to be granted to non-system apps, though. According to my own tests, behavior without this permissions differ: Anbox will return the full logcat, while LineageOS (tested on 15.1) will only show log entries from the app which called it (including previous instances, presumably everything associated with the same Linux user). This can be a limitation or a welcome filter feature. YMMV.
logcat conveniently has a command line option, -f, to specify an output file. I tried
Runtime.getRuntime().exec("logcat -f " + absolutePathToLogFile);
and logcat keeps logging as long as the app’s process runs. Killing the app (by clicking the X in the title bar on Anbox) apparently also terminated the child process.
Now you can either run this code when your app starts up, or you can turn this functionality into a separate app which starts on boot and continuously collects logs for all apps.
Caveats: This may fill up your storage space quickly if you have some chatty apps running (which is why entries rotate out of the logcat so quickly in the first place). It is recommended to make log mirroring configurable (e.g. via Preferences) and/or ensure old files are deleted regularly. Also, if you keep the logcat process running until your app terminates, you will not be able to access the file over MTP as there is no easy way to run the media scanner (if you scan the file while it is still written to, it will appear truncated over MTP until another media scan runs).
You have not specified if some exception are thrown but you don't handle.
In case, take a look at this answer:
Android Handling Unhandled Exception
If you must look at a bunch of variables and objects, I'd suggest two choices:
Write a copy of your logs on a file. When your problem occurs, just ask the user to send the file to you. This is ideal during tests with self-aware users.
Obtain statistics about usage, like commercial software do. Just log user operations and send the data to your server (you would need one for this). This is the most transparent way to do remote logging.
In the case of writing log to a file, you can read and write what you want in internal memory (inside the app's sandbox) or external memory (in this case, write permission is required and explicit permission must have been granted at runtime if you are targeting Android 6 and above).
the App is called "3 Minute Retreat" by LoyolaPress and each time i run it, i get that response; i have tried all the available fixes online and nothing seems to work, from uninstalling to reinstalling, to clearing App and Cache Data, to Soft Rebooting, to moving Storage Location, to downgrading and updating Play Services ETC but nothing seems to work
here is what is being displayed before the "3 Minute Retreat has stopped working" notification comes up:
"Runtime Error
/Users/Jenkins/slaveroot/workspace/Templates/label/Android/subrepos/composer/composer.lua:1451:
?:0 attempt to index a nil value"
NB:
im not a Programmer, so i will really appreciate the easiest form of explanation/instructions that i at least may be able to follow/understand
and phone is Samsung J1 Ace (4.4.4)
You need to post the code around line 1451 in composer.lua file.
From the error it looks like you're trying to index a null object.
Try to debug the actual value of the variables being accessed during runtime, and try to figure out why the variable is null.
I thought there would be some straight forward solution to this.
Requirements:
Uniquely identify device across app install/uninstall sessions.
Options:
Use some kind of Android's device-identifier-API each time when needed (read it every time from Android's API). According to Identififying-app-installations blog post this is not recommended and not reliable solution.
Generate UUID once (on first app start) and persist it somewhere somehow that it would be preserved across multiple app installs/uninstalls. This "somewhere somehow" part is the mystery. Solutions like storing onto the SD card or Cloud are not an option. iOS has keychain that can be used for this kind of stuff but I didn't find Android's equivalent of it.
What are my other options here? I prefer going the (2) route because of my server implementation (server is generating UUID for the first time if not present). But if it is not an option, I can fallback to (1) and modify the server.
Thanks.
To uniquely identify an application between application installs/reinstalls, you need to get it's hardware ID and use that as your credentials/key.
To fetch the hardwareID, you can use the following method:
public static String getHardwareId(Context context) {
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
}
it's partially equivallent to a UUID with the following exception: The value may change if a factory reset is performed on the device.
The reason why i call it "partially equivallent" is this:
The HardwareID is a 64-bit number (as a hex string) that is randomly generated when the user first sets up the device and should remain constant for the lifetime of the user's device. The value may change if a factory reset is performed on the device.
Note: When a device has multiple users (available on certain devices running Android 4.2 or higher), each user appears as a completely separate device, so the ANDROID_ID value is unique to each user.
But this hits the #2 problem: where and how to store it; storing it in SharedPreferences is useless as that is wiped if the app is uninstalled. Same for /data/data/your.package.name/my_stored_keys folder as that one gets deleted from the phone during uninstallation as well.
You will need to save it server-side if you wish to persist between uninstalling and reinstalling the app.
Recently my users are complaining that application hangs while using it and the data stored getting lost when the reboot the mobile.
Its not happening everytime too.
Can some one please tell me for what are all the reasons sqlite data will get lost.?
Also for what are the reasons android application freeze?
Background : My application perform sqlite operation from all the screens. The device
Model Number: Samsung GT-18160 , Android Version:2.3.6 , Kernel
Version:2.6.35.7-1219296 dpi#DELL210#2
You can assume no data should be lost. But you may want to nail down crash culprit first - luckily your user is on 2.x so tell him to use tools like aLogCat and grab the logs after your app crash. Then check what's there and fix. That should solve your "data lost" issue as whatever it is, it occurs after your app crashed. If it stop crashing then it should not trigger the snowball....
I have an app that user's can draw with, and then 'export' that drawing as a .png file to external storage, if present. Generating the PNG, copying the file to external all work like a charm, but a rather unique problem happens; after the export, if the user navigates to the image via My files (Samsung Tab running 2.2 in this case), they can see the .png file, but when they open it, the screen is black for about 10 seconds... then they see the image, Additionally, the images don't show up in the user's 'Gallery' app either.
Now, if the user connects the device to the computer via USB, or reboots the device, they can access the images no problem from My files, and they appear in 'Gallery' from that point forward, but again, any newly esported files experience the same problems until they cycle/connect the device again.
My thinking was that this had to be related to the Media Scanner (at least in the case of the 'Gallery' problem, it most certainly is).
So, as I am targetting Api 8+, I am trying to use the static MediaScannerConnection.scanFile() method to have the OS re-scan and add my images into the Gallery, etc. Also hoping this solves the issue of the strange delay in opening the images. Here is my code:
MediaScannerConnection.scanFile(
context,
new String[] { "/mnt/sdcard/MyApp" },
null,
null
);
LogCat gives me the following entries when I export an image, and thus run the above call:
DEBUG/MediaScannerService(2567): IMediaScannerService.scanFile: /mnt/sdcard/MyApp mimeType: null
DEBUG/MediaScannerService(2567): onStartCommand : intent - Intent { cmp=com.android.providers.media/.MediaScannerService (has extras) }
DEBUG/MediaScannerService(2567): onStartCommand : flags [0], startId [1]
DEBUG/MediaScannerService(2567): ServiceHandler:handleMessage volume[null], filePath[/mnt/sdcard/MyApp]
DEBUG/MediaProvider(2567): getSdSerial() sd state = removed
INFO/Database(2567): sqlite returned: error code = 17, msg = prepared statement aborts at 43: [SELECT DISTINCT sd_serial FROM images WHERE sd_serial LIKE 'external_0x%']
ERROR/MediaProvider(2567): removeMediaDBData called
DEBUG/MediaScanner(2567): prescan enter: path - /mnt/sdcard/MyApp
DEBUG/MediaScanner(2567): prescan return
So, it looks like the MediaScanner is getting the correct location, but is failing to find the SD card, which is correct, and failing. The Samsung Tab has built-in non-SD external storage, which Android gives access to via Environment.getExternalStorageDirectory(). How do I tell it to scan the non-SD storage?
Any ideas how to proceed?
Paul
Found the solution here, which involves sending a broadcast request to the media scanner via an Intent:
How to update the Android media database
Never did figure out the issue with MediaScannerConnection.scanFile.
Whenever you add a file, let MediaStore Content Provider knows about it using
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(imageAddedOrDeleted)));
Main advantage: work with any mime type supported by MediaStore
For deletion: just use getContentResolver().delete(uri, null, null)