I have a crash for which I receive the following report in Google Play.
java.lang.OutOfMemoryError: [memory exhausted]
at dalvik.system.NativeStart.main(Native Method)
As you can see, not a lot of information. There is this question that asks the same thing but I don't believe the answer of ignoring it is acceptable.
The fact there is nothing about my application in the stack trace suggests that it's the OS that's not allowing the application to start. This implies there isn't much we can do however, even after users have rebooted their devices, they still cannot open the application. My application isn't big: 22.20MB on the device.
Please see the following or the crash report stats.
Is there anything I can do to rectify this or at least minimise the chances of this happening?
Don't know if its a right solution or not but it solved my issue. The common reason of java.lang.OutOfMemoryError is overflowing the limit of cache. What I did, I have cleared the Application cache on the launcher activity. So whenever the application is launched at first it clears the cache.
add this methods out side of the onCreate method of your launcher activity.
//Following two methods are used to clear the Cache memory of this application
public static void deleteCache(Context context) {
try {
File dir = context.getCacheDir();
if (dir != null && dir.isDirectory()) {
deleteDir(dir);
}
} catch (Exception e) {}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
And call deleteCache(this); inside of the onCreate.
Related
I'm using the libaums library (version 0.7.0) for reading SD cards via a USB card reader.
The issue I'm having is that if I don't go into the phone storage options and choose to unmount the SD card before removing it, it always becomes corrupted when I take it out, even if I don't actually write anything to it (Windows complains about it when inserted in a Windows machine). Calling device.init() is enough to trigger the problem.
I wonder if I'm perhaps using the library incorrectly or if nothing else, there is a way to unmount the USB card reader automatically from my app once I'm finished with it? As I understand it calling device.close() SHOULD be enough to flush data and secure the card for removal.
This is the code I'm using for accessing the card:
private class FindDevicesTask extends AsyncTask<Integer, Integer, String> {
private WeakReference<Context> mContext;
FindDevicesTask (Context context){
mContext = new WeakReference<>(context);
}
#Override
protected String doInBackground(Integer... dummy) {
Context ctx = mContext.get();
if (ctx == null)
return null; // Context expired
UsbMassStorageDevice[] devices = UsbMassStorageDevice.getMassStorageDevices(ctx);
for (final UsbMassStorageDevice device : devices) {
// If we don't have permission, request it and leave this function (if we get
// permission the function will be called again)
if (!mUsbManager.hasPermission(device.getUsbDevice())) {
mUsbManager.requestPermission(device.getUsbDevice(), mPermissionIntent);
return null;
}
try {
device.init();
// Do work
} catch (IOException e) {
return e.getMessage();
} finally {
device.close();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
if (result == null || result.isEmpty())
return;
Context ctx = mContext.get();
if (ctx != null)
displayString(result, "USB connection error", ctx);
}
};
Started by calling new FindDevicesTask(context).execute();
I just wanted to report that this issue was not with the libaums library but rather Android itself. My device automatically configures SD cards it sees to work with Android (it adds some system folders and files). When this happens it does something that makes Windows not like the SD card anymore, although it's by no means corrupt (Windows can read it no problem).
After some research I found that Android likes to cache some parts of an app while installing to improve the performance while runtime.
Is there a way to prevent Android from caching things from my app?
I am sharing my app via my website and users install and update the app manually. As soon as I update my app some Activities and Code-parts seems to be cached on their devices.
You could delete your cache everytime before you update or before you close you application.
Code to clear the cache:
public static void trimCache(Context context) {
try {
File dir = context.getCacheDir();
if (dir != null && dir.isDirectory()) {
deleteDir(dir);
}
} catch (Exception e) {
// TODO: handle exception
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// The directory is now empty so delete it
return dir.delete();
}
Call Trimcache when you want to clear the cache (before you update perhaps? or override the onStop() method, to clear the cache when the application is going to close.
The way I see you should also have a cache problem when you're NOT updating your app.
If you want to force a server fetch when you upgrade your app you could store a boolean in Shared Preferences, using a key associated with the app version. So when you install version 1 you fetch and make putsBoolean(version, true) where version == "1". When version 2 is installed you'll find a false, which will trigger a fetch, followed by setting putsBoolean(version, true) - but in this case version == "2".
If you are reusing information that have a different meaning when you update, the solution is storing the information in a different part of the cache, so it's not sent to an activity that is not prepared to display it.
Otherwise the solution by #jordy-dieltjens seems a good one.
I am using the Android Billing API V3 for querying purchase information from the play store. I am wondering if it is possible to clear the local cache.
V3 added the local caching feature for the billing API to cut down on network traffic. I have an update service which is run daily which updates my metadata and since I display the costs in my application I wish to flush the local cache and trigger an update in case I have updated prices to ensure the correct price is shown.
Documentation says:
Because the Google Play client now caches In-app Billing information locally on the device, you can use the Version 3 API to query for this information more frequently, for example through a getPurchases call. Unlike with previous versions of the API, many Version 3 API calls will be serviced through cache lookups instead of through a network connection to Google Play, which significantly speeds up the API's response time.
You must know that the android in app purchase one time purchases are allow only one time in the lifetime for one user. you want it again you have to make a request or create a new product in play console. for more go to this link.
https://developer.android.com/google/play/billing/billing_onetime
Unfortunately not, the Google Play client is app doing the caching, and there is not an API exposed to clear the cache.
I don't see why you want to clear the cache though? The Google Play client is notified of any changes, so would invalidate it's cache accordingly. Just assume the calls returned are correct.
Try this :
Add this Application class :
package com.hrupin.cleaner;
import java.io.File;
import android.app.Application;
import android.util.Log;
public class MyApplication extends Application {
private static MyApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static MyApplication getInstance() {
return instance;
}
public void clearApplicationData() {
File cache = getCacheDir();
File appDir = new File(cache.getParent());
if (appDir.exists()) {
String[] children = appDir.list();
for (String s : children) {
if (!s.equals("lib")) {
deleteDir(new File(appDir, s));
Log.i("TAG", "**************** File /data/data/APP_PACKAGE/" + s + " DELETED *******************");
}
}
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
}
Then, Make this call from any Activity:
MyApplication.getInstance().clearApplicationData();
Reference :
How to Clear User Data in your Android Application programmatically
Thanks.
Requirement
Scan all folders and files on external storage to find all apk files and for each apk file, get info and display progress.
How I did it so far
My initial thought is that this is a simple thing to achieve. But well... even it it sort of works, it does not perform as expected.
I use an AsyncTask to perform the scanning in background. Here is how I do:
private ArrayList<String> sdcardAppsPath;
protected class ScanTask extends AsyncTask<Context, Scanner, ArrayList<Apk>> {
private ArrayList<Apk> sdcardApps;
#Override
protected ArrayList<App> doInBackground(Context... params) {
visitAllDirsAndFiles(Environment.getExternalStorageDirectory());
for (String path : sdcardAppsPath) {
//get info about apk file and
publishProgress(values) //show in some textviews number of files scanned, total files
sdcardApps.add(currentScannedItemFoundInfo);
}
return sdcardApps
}
#Override
protected void onProgressUpdate(Scanner... values) {
super.onProgressUpdate(values);
// update some textView texts based on values
}
}
And
// Process all files and directories under dir
public void visitAllDirsAndFiles(File dir) {
if (dir != null) {
if (dir.getAbsoluteFile().toString().endsWith(".apk")) {
sdcardAppsPath.add(dir.getAbsoluteFile().toString());
}
if (dir.isDirectory()) {
String[] children = dir.list();
if (children != null) {
for (int i = 0; i < children.length; i++) {
visitAllDirsAndFiles(new File(dir, children[i]));
}
}
}
}
}
As you can see after vistitAllDirsAndFiles I get an ArrayList<String> with all apk files I need, so I can check for each what I want. The downside is that it might take a lot of time to build this sdcardAppsPath if there are many files on the card and the app shows no progress while the paths are being found.
What I want to achieve
I want to be able in the doInBackground to somehow for each found file, get the info I need, update progress and then continue with scanning. Any ideas how to update my code to work like this ?
I would think that you would want to call publishProgress inside your visitAllDirsAndFiles method if you want to update progress while searching for files, instead of iterating through the list afterwards and calling it then...
I am developing automated tests for an android application (using Robotium). In order to ensure the consistency and reliability of tests, I would like to start each test with clean state (of the application under test). In order to do so, I need to clear the app data. This can be done manually in Settings/Applications/Manage Applications/[My App]/Clear data
What is the recommended way to get this done programmatically?
You can use the package-manager tool to clear data for installed apps (similar to pressing the 'clear data' button in the app settings on your device).
So using adb you could do:
adb shell pm clear my.wonderful.app.package
Following up to #edovino's answer, the way of clearing all of an application's preferences programmatically would be
private void clearPreferences() {
try {
// clearing app data
Runtime runtime = Runtime.getRuntime();
runtime.exec("pm clear YOUR_APP_PACKAGE_GOES HERE");
} catch (Exception e) {
e.printStackTrace();
}
}
Warning: the application will force close.
you can clear SharedPreferences app-data with this
Editor editor =
context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE).edit();
editor.clear();
editor.commit();
and for clearing app db, this answer is correct -> Clearing Application database
From API version 19 it is possible to call ActivityManager.clearApplicationUserData().
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).clearApplicationUserData();
Check this code to:
#Override
protected void onDestroy() {
// closing Entire Application
android.os.Process.killProcess(android.os.Process.myPid());
Editor editor = getSharedPreferences("clear_cache", Context.MODE_PRIVATE).edit();
editor.clear();
editor.commit();
trimCache(this);
super.onDestroy();
}
public static void trimCache(Context context) {
try {
File dir = context.getCacheDir();
if (dir != null && dir.isDirectory()) {
deleteDir(dir);
}
} catch (Exception e) {
// TODO: handle exception
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// <uses-permission
// android:name="android.permission.CLEAR_APP_CACHE"></uses-permission>
// The directory is now empty so delete it
return dir.delete();
}
If you have just a couple of shared preferences to clear, then this solution is much nicer.
#Override
protected void setUp() throws Exception {
super.setUp();
Instrumentation instrumentation = getInstrumentation();
SharedPreferences preferences = instrumentation.getTargetContext().getSharedPreferences(...), Context.MODE_PRIVATE);
preferences.edit().clear().commit();
solo = new Solo(instrumentation, getActivity());
}
Using Context,We can clear app specific files like preference,database file.
I have used below code for UI testing using Espresso.
#Rule
public ActivityTestRule<HomeActivity> mActivityRule = new ActivityTestRule<>(
HomeActivity.class);
public static void clearAppInfo() {
Activity mActivity = testRule.getActivity();
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(mActivity);
prefs.edit().clear().commit();
mActivity.deleteDatabase("app_db_name.db");
}
if android version is above kitkat you may use this as well
public void onClick(View view) {
Context context = getApplicationContext(); // add this line
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
((ActivityManager) context.getSystemService(ACTIVITY_SERVICE))
.clearApplicationUserData();
return;
}
What is the recommended way to get this done programmatically?
The only possible option is to run ADB command adb shell pm clear package before the test. The biggest problem is that it's kind of headache combining tests execution and shell commands.
However, we (at Mediafe) came with some solution that can work for you on regular unrooted device. All you need to do is to add an annotation. All the rest is done by running simple bash script.
Just add #ClearData annotation before ANY of your tests and tada 🎉, ADB clear command will be executed before the test execution.
This is an example of such test:
#Test
#ClearData
public void someTest() {
// your test
}
The idea is as follows
Read all tests by using adb shell am instrument -e log true
Build execution plan by parsing the output from (1)
Run the execution plan line by line
Using the same idea these are all options you can easily support:
Clear data
Clear notification bar
Parameterize
Filter and run by tags
Use only annotations. Like this:
#Test
#ClearData
#Tags(tags = {"sanity", "medium"})
#Parameterized.Repeat(count = 3)
public void myTest() throws Exception {
String param = params[index];
// ...
}
Bonus! 🎁 For each failed test:
Collect Logcat + stacktrace
Record video (mp4)
Dump DB (sqlite)
Dump default shared preferences (xml)
Collect dumpsys files like: battery, netstats and other.
In general, it's easy to add more options, since the tests are executed one by one from bash script rather than from gradle task.
📗 The full blog post: https://medium.com/medisafe-tech-blog/running-android-ui-tests-53e85e5c8da8
📘 The source code with examples: https://github.com/medisafe/run-android-tests
Hope this answers 6 years question ;)
This way added by Sebastiano was OK, but it's necessary, when you run tests from i.e. IntelliJ IDE to add:
try {
// clearing app data
Runtime runtime = Runtime.getRuntime();
runtime.exec("adb shell pm clear YOUR_APP_PACKAGE_GOES HERE");
}
instead of only "pm package..."
and more important: add it before driver.setCapability(App_package, package_name).