Android Memory Leak? Bitmap exceeds VM budget error with MapView - android

I've written an application that creates a map activity. From there the user can switch to a menu and goes back to the map activity. After about 10 of those loops, the following error occurs:
02-28 21:35:54.780: E/AndroidRuntime(23502): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
I've tried the unbind drawables solution proposed here http://www.alonsoruibal.com/bitmap-size-exceeds-vm-budget/ and in various other threads but that did not help.
The only thing that helps is closing the map activity manually via finish(), but that causes an unnatural navigation behavior.
Here is my code:
MapActivity class
public class TestMapsForgeActivity extends MapActivity {
View mapView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mapView = new MapView(this);
}
#Override
public boolean onCreateOptionsMenu(android.view.Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.map_menu, menu);
return true;
};
#Override
public boolean onOptionsItemSelected(MenuItem item) {
startActivity(new Intent(getApplicationContext(), MenuActivity.class));
return true;
}
}
MenuActivity Class
public class MenuActivity extends Activity {
#Override
public boolean onCreateOptionsMenu(android.view.Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
};
#Override
public boolean onOptionsItemSelected(MenuItem item) {
startActivity(new Intent(getApplicationContext(), TestMapsForgeActivity.class));
return true;
}
}
What I don't understand is, the garbage collector does apparently not destroy the MapActivity properly unless I close it with finish(). But shouldn't android call finish() by itself as soon as the application needs more memory?
Does anyone have some thoughts on this issue?
Thanks in advance!

I think the problem is that you are starting an activity over another that wasn't closed.
Try this:
Intent i = new Intent(getApplicationContext(), TestMapsForgeActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
Setting the Intent flag CLEAR_TOP, will finish the others previous activitys, read more here: http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP

Related

onCreate is not called after switching back from preferences

My app only has two activities: main and preferences
In the PreferenceActivity (or in my case SettingsActivity), the user can change some stuff, that affects the MainActivity.
This is my SettingsActivity:
public class SettingsActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
public static class SettingsFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener {
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
return false;
}
}
}
Now I have two issue:
When the user presses the HomeButton the main screen does not seem to call the onCreate so the changed preferences are not loaded in the main activity. What do I need to change, to tell android to call the onCreate function?
Since android nougat there are these "activity-change-animations", so when switching to a new activity, the new screen kind of slides in. But when the user presses the HomeButton the expected animation would be slide out, but it is also slide in. How can I fix that?
Explanation for the first issue:
There's a difference between onCreate and onResume
onCreate: Activity launched for the first time. Here is where you may initialize your stuff.
onResume: User returns to the activity after another activity goes to the background. (onPause is called on the other activity)
For the second issue, try this:
Intent intent = NavUtils.getParentActivityIntent(this);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent);
Instead of
NavUtils.navigateUpFromSameTask(this);

Android: Data passed with intent disappears when coming back from deeper hierarchy

I have an OverviewActivity that contains a listview. When an item is selected, an intent is created to move to the DetailActivity and I pass an int with it.
This int is assigned to a private variable and is used to query the database.
DetailActivity code:
private int mIssueId;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_issue_detail);
mIssueId = getIntent().getIntExtra(IssueOverviewFragment.INTENT_ISSUE_ID, -1);
...
}
In the DetailActivity I can go to a GraphActivity. But when I press the upButton in the GraphActivity, the application crashes because the variable became -1 in the DetailActivity (and the database can thus not be queried properly).
The hierarchy is:
OverviewActivity -> DetailActivity -> GraphActivity
GraphActivity code:
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_graph );
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
...
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_detail, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_logout: {
Utility.redirectToLogin(this);
break;
}
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
How do I retain the values of my mIssueId attribute in the DetailActivity?
The Intent intends to pass information between activities. When Activity1 pass control to Activity2 mostly related to the behavior of the activity.
If you have information you need to share across a complex hierarchy or to be available for your entire app, you can choice between Shared Preferences if you need persistence or use a Singleton class if the data only will be needed while the app is running.
This is a sample for a Singleton class keeping information to available to the entire app:
public class AppData {
private static AppData ourInstance = new AppData ();
public int score;
public static AppData getInstance () {
return ourInstance;
}
}
And how to access it:
AppData.getInstance().score = 100;
Hope it helps.
It looks like you are getting as a default value because there was an issue getting the intent in DetailActivity. You could try breaking up your request a little with
mIssueId = getIntent().getExtras().getInt();
But I think the issue is probably with how you are putting the int into the intent.
It should look something like
Intent intent = new Intent(context, DetailActivity.class);
intent.putExtra(IssueOverviewFragment.INTENT_ISSUE_ID, mIssueId);
startActivity(intent);

onOptionItemsSelected not called

I've added menu items to the overflow area of the action bar programatically.
I've created the onOptionsItemsSelected method as well.
Yet, when I click on the options in the overflow menu, I get the following errors:-
I/ListPopupWindow: Could not find method setEpicenterBounds(Rect) on
PopupWindow. Oh well. 03-19 05:49:33.907
18143-18143/com.cs478.arjan.a3 W/art: Before Android 4.1, method int
android.support.v7.widget.ListViewCompat.lookForSelectablePosition(int,
boolean) would have incorrectly overridden the package-private method
in android.widget.ListView 03-19 05:49:34.876
18143-18143/com.cs478.arjan.a3 I/Choreographer: Skipped 49 frames!
The application may be doing too much work on its main thread. 03-19
05:51:00.461 1258-1577/? D/hwcomposer: hw_composer sent 216 syncs in
119s 03-19 05:51:55.146 3080-3086/com.cs478.arjan.a2 W/art: Suspending
all threads took: 35.702ms
I've defined my class as :-
public class Basketball extends AppCompatActivity implements ListSelectionListener {
private android.app.ActionBar a;
...
public boolean onCreateOptionsMenu(Menu menu){
menu.add(Menu.NONE, 1, Menu.NONE, "Baseball");
return true;
}
public boolean onOptionsItemsSelected(MenuItem item){
Log.i("project III",TAG+" in optionsItems Selected");
switch (item.getItemId()){
case 1:
Intent intent = new Intent(Basketball.this,Baseball.class);
startActivity(intent);
break;
}
return true;
}
...
}
Any suggestions to resolve this issue will be highly appreciated.
Regards
Arjan
I think #override is missing in this case android won't call it.please check it.
write override over methods:
public class Basketball extends AppCompatActivity implements ListSelectionListener {
private android.app.ActionBar a;
...
#Override
public boolean onCreateOptionsMenu(Menu menu){
menu.add(Menu.NONE, 1, Menu.NONE, "Baseball");
return true;
}
#Override
public boolean onOptionsItemsSelected(MenuItem item){
Log.i("project III",TAG+" in optionsItems Selected");
switch (item.getItemId()){
case 1:
Intent intent = new Intent(Basketball.this,Baseball.class);
startActivity(intent);
break;
}
return true;
}
...
}

Update an activity after use of optionsMenu

I have an app with 5 activities. All these activities have settings that can be modified using the menu-button (optionsmenu) and selecting 'Settings'. This will open a dialog where all settings shown and where modification is possible.
When I close this settings-dialog by press the 'ok'-button, I want the activity that called optionsmenu to update its view.
The optionsmenu is activited like this in all activities:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.firstactivity_options_menu, menu);
return true;
}
And an example of onOptionsItemSelected follows...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.settings) {
class.settingsDialog(this);
} else if (item.getItemId() == R.id.about) {
try {
alertDialog(getResources().getString(R.string.settings_about), getAssets().open("about"), this);
} catch (IOException e) {
}
}
return true;
}
My problem is updating an activities view after I've had a match for R.id.settings. Is this possible? And if so, please give me some pointers...
There's probably different ways to do this but after clicking Ok you can use an Intent to start the activity and call finish() on the activity to re-create the views
I would implement a super/subclass approach or an interface since Dialogs do not force an Activity's onResume() method to be called.
Make a top abstract Activity class, e.g. SuperMainActivity.
public abstract class SuperMainActivity extends Activity
{
public abstract void updateUI();
}
Then, have each of your Activities extend SuperMainActivity instead of just Activity and implement the updateUI() method.
Then in your settingsDialog() method, make it either:
Accept a SuperMainActivity param instead of an Activity/Context param.
or:
Do a cast when you want to callback, such as
((SuperMainActivity)myVariable).updateUI();
An interface is largely similar:
public interface ActivityCallback
{
public void updateUI();
}
And each activity will implement ActivityCallback
such as
public class MainActivity implements ActivityCallback
{
public void updateUI()
{
//implementation. Differs per class
}
}
Then again, your settingsDialog() method should accept in an ActivityCallback parameter or you will cast again.
Note that if you do decide on this approach, when you call settingsDialog() you can still call it with
settingsDialog(this);
Since your Activities will meet the requirements for a parameter.

How do you turn off share history when using ShareActionProvider?

The new ShareActionProvider available in Android 4.0 (or in earlier versions if you're using ActionBarSherlock) has a feature where the last used item is displayed in the action bar. Is there anyway to turn this off?
For me, the best solution for avoid the history icon is don't use ShareActionProvider, instead of it, create it as any other action:
<item
android:id="#+id/menu_action_share"
android:showAsAction="ifRoom"
android:icon="#drawable/ic_action_share"
android:title="#string/share"/>
at the menu/activity_actions.xml put a item with the ic_action_share icon...
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_actions, menu);
return super.onCreateOptionsMenu(menu);
}
Inflate the menu normally...
private void actionShare(){
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_SUBJECT, "my string");
i.putExtra(Intent.EXTRA_TEXT, "another string");
startActivity(i);
//Or like above will always display the chooser
//startActivity(Intent.createChooser(i, getResources().getText(R.string.share)));
}
Create a method with an ACTION_SEND intent
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_share:
actionShare();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
And finally call to this method from onOptionsItemSelected
more info ->Sending Simple Data to Other Apps
Start the share activity by yourself:
shareActionProvider.setShareIntent(intent);
shareActionProvider.setOnShareTargetSelectedListener(this);
#Override
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) {
// start activity ourself to prevent search history
context.startActivity(intent);
return true;
}
Then the ShareActionProvider will not add the chosen activity to the share history.
I created my own version of the ShareActionProvider (and supporting classes), you can copy them into your project (https://gist.github.com/saulpower/10557956). This not only adds the ability to turn off history, but also to filter the apps you would like to share with (if you know the package name).
private final String[] INTENT_FILTER = new String[] {
"com.twitter.android",
"com.facebook.katana"
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.journal_entry_menu, menu);
// Set up ShareActionProvider's default share intent
MenuItem shareItem = menu.findItem(R.id.action_share);
if (shareItem instanceof SupportMenuItem) {
mShareActionProvider = new ShareActionProvider(this);
mShareActionProvider.setShareIntent(ShareUtils.share(mJournalEntry));
mShareActionProvider.setIntentFilter(Arrays.asList(INTENT_FILTER));
mShareActionProvider.setShowHistory(false);
((SupportMenuItem) shareItem).setSupportActionProvider(mShareActionProvider);
}
return super.onCreateOptionsMenu(menu);
}
There is no API to do this. However, the class is really simple and you could very easily create your own version of ShareActionProvider that did not keep a history. You would just have to determine the sort order of the possible targets using some other means of ordering (e.g., alphabetically).
Point of clarification: It's not the "last used", it's "most often used", across a sliding window period of time.
If you prefer not to use history, then before creating your views, call
yourShareActionProvider.setShareHistoryFileName(null);
Description of this method, from the official docs (emphasis mine):
Sets the file name of a file for persisting the share history which history will be used for ordering share targets. This file will be used for all view created by onCreateActionView(). Defaults to DEFAULT_SHARE_HISTORY_FILE_NAME. Set to null if share history should not be persisted between sessions.
EDIT: I should clarify — The "most often used" item won't show up if there's no history, so this is currently the only way of removing that button.
Although It's been 2 years ago today but I'd like to share my experience as I made a custom ShareActionProvider class and add this line chooserView.getDataModel().setHistoryMaxSize(0); inside onCreateActionView() which did all the magic for me ! .. I tested it on Lollipop device and on API 16 emulator device and it works perfectly. here is my custom class :
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v7.internal.widget.ActivityChooserView;
import android.support.v7.widget.ShareActionProvider;
import android.view.View;
public class MyShareActionProvider extends ShareActionProvider {
/**
* Creates a new instance.
*
* #param context Context for accessing resources.
*/
public MyShareActionProvider(Context context) {
super(context);
}
#Override
public View onCreateActionView() {
ActivityChooserView chooserView = (ActivityChooserView) super.onCreateActionView();
Drawable icon;
if (Build.VERSION.SDK_INT >= 21) {
icon = getContext().getDrawable(R.drawable.share_icon);
}else{
icon = getContext().getResources().getDrawable(R.drawable.share_icon);
}
chooserView.setExpandActivityOverflowButtonDrawable(icon);
chooserView.getDataModel().setHistoryMaxSize(0);
return chooserView;
}
}
add the code like this:
private void addShareSelectedListener() {
if (null == mShareActionProvider) return;
OnShareTargetSelectedListener listener = new OnShareTargetSelectedListener() {
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) {
mContex.startActivity(intent);
return true;
}
};
//Set to null if share history should not be persisted between sessions.
mShareActionProvider.setShareHistoryFileName(null);
mShareActionProvider.setOnShareTargetSelectedListener(listener);
}
getSupportMenuInflater().inflate(R.menu.share_action_provider, menu);
// Set file with share history to the provider and set the share intent.
MenuItem actionItem = menu.findItem(R.id.menu_item_share_action_provider_action_bar);
ShareActionProvider actionProvider = (ShareActionProvider) actionItem.getActionProvider();
***actionProvider.setShareHistoryFileName(null);
OnShareTargetSelectedListener listener = new OnShareTargetSelectedListener() {
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) {
startActivity(intent);
return true;
}
};
actionProvider.setOnShareTargetSelectedListener(listener);***

Categories

Resources