I am using a GridView and universalimageloader (1.8.6) and seem to be encountering a memory leak - though maybe I am misinterpreting DDMS and MAT results? This is code I did not write, but it is pretty basic - we are showing a number of photos and allowing the user to select as many as they want and then storing those for future reference. The code seems to work fine, but in MAT "Leak Suspect" the GridView from below keeps on showing up, chewing upwards of 5 mb each time, even when I have called finish() on the Activity. From what I have read Android can keep the Activity in memory until it wants to release it (and have seen this with other Activities) but it never seems to want to release this one - even when I force GC. The "new thread" allocation looks a bit suspicious, but wouldn't that get dellocated with the calling Activity?
Probably just missing something obvious, but here is the code:
public class PhotoGalleryPickerActivity extends MyActivity {
private Boolean mMultiple = false;
GridView gridGallery;
Handler handler;
GalleryAdapter adapter;
ImageView imgNoMedia;
Button btnGalleryOk;
String action;
private ImageLoader imageLoader;
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo_gallery_picker);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle("Photo Gallery Capture");
Bundle extras = getIntent().getExtras();
mMultiple = extras.getBoolean("multiple");
initImageLoader();
init();
}
private void initImageLoader() {
try {
String CACHE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/.temp_tmp";
new File(CACHE_DIR).mkdirs();
File cacheDir = StorageUtils.getOwnCacheDirectory(getBaseContext(), CACHE_DIR);
DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
.cacheOnDisc(true).imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.RGB_565).build();
ImageLoaderConfiguration.Builder builder = new ImageLoaderConfiguration.Builder(
getBaseContext())
.defaultDisplayImageOptions(defaultOptions)
.discCache(new UnlimitedDiscCache(cacheDir))
.memoryCache(new WeakMemoryCache());
ImageLoaderConfiguration config = builder.build();
imageLoader = ImageLoader.getInstance();
imageLoader.init(config);
} catch (Exception e) {
Utilities.logException(e);
}
}
private void init() {
handler = new Handler();
gridGallery = (GridView) findViewById(R.id.gridGallery);
gridGallery.setFastScrollEnabled(true);
adapter = new GalleryAdapter(getApplicationContext(), imageLoader);
PauseOnScrollListener listener = new PauseOnScrollListener(imageLoader, true, true);
gridGallery.setOnScrollListener(listener);
if (mMultiple == true){
findViewById(R.id.llBottomContainer).setVisibility(View.VISIBLE);
gridGallery.setOnItemClickListener(mItemMulClickListener);
adapter.setMultiplePick(true);
}
else {
findViewById(R.id.llBottomContainer).setVisibility(View.GONE);
gridGallery.setOnItemClickListener(mItemSingleClickListener);
adapter.setMultiplePick(false);
}
gridGallery.setAdapter(adapter);
imgNoMedia = (ImageView) findViewById(R.id.imgNoMedia);
btnGalleryOk = (Button) findViewById(R.id.btnGalleryOk);
btnGalleryOk.setOnClickListener(mOkClickListener);
new Thread() {
#Override
public void run() {
Looper.prepare();
handler.post(new Runnable() {
#Override
public void run() {
adapter.addAll(getGalleryPhotos());
checkImageStatus();
}
});
Looper.loop();
};
}.start();
}
private void checkImageStatus() {
if (adapter.isEmpty()) {
imgNoMedia.setVisibility(View.VISIBLE);
} else {
imgNoMedia.setVisibility(View.GONE);
}
}
View.OnClickListener mOkClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<CustomGallery> selected = adapter.getSelected();
String[] photos = new String[selected.size()];
for (int i = 0; i < photos.length; i++) {
photos[i] = selected.get(i).sdcardPath;
}
Intent data = new Intent().putExtra("photos", photos);
if(photos.length == 0) {
data = null;
}
setResult(RESULT_OK, data);
finish();
}
};
AdapterView.OnItemClickListener mItemMulClickListener = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
adapter.changeSelection(v, position);
}
};
AdapterView.OnItemClickListener mItemSingleClickListener = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
CustomGallery item = adapter.getItem(position);
String[] photos = new String[1];
photos[0] = item.sdcardPath;
Intent data = new Intent().putExtra("photos", photos);
setResult(RESULT_OK, data);
finish();
}
};
private ArrayList<CustomGallery> getGalleryPhotos() {
ArrayList<CustomGallery> galleryList = new ArrayList<CustomGallery>();
try {
String[] dirs = new String[1];
final String where = MediaStore.Images.Media.DATA + " not like ? ";
String mediaDir = GlobalState.getInstance().currentForm.mediaDirectory();
if (mediaDir != null) {
int slash = mediaDir.lastIndexOf("/");
dirs[0] = mediaDir.substring(0, slash) + "%";
}
final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID };
final String orderBy = MediaStore.Images.Media._ID;
Cursor imagecursor = null;
try {
if (mediaDir != null && mediaDir.trim().length() > 0) {
imagecursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, where, dirs, orderBy);
}
else {
imagecursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy);
}
if (imagecursor != null && imagecursor.getCount() > 0) {
while (imagecursor.moveToNext()) {
CustomGallery item = new CustomGallery();
int dataColumnIndex = imagecursor
.getColumnIndex(MediaStore.Images.Media.DATA);
item.sdcardPath = imagecursor.getString(dataColumnIndex);
galleryList.add(item);
}
}
}
catch (Exception ex) {
Utilities.logException(ex);
Utilities.logError("PhotoGalleryPickerActivity", "getGalleryPhotos : " + ex.getMessage());
}
finally {
if (imagecursor != null) {
imagecursor.close();
}
}
} catch (Exception e) {
Utilities.logException(e);
e.printStackTrace();
}
// show newest photo at beginning of the list
Collections.reverse(galleryList);
return galleryList;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
PhotoGalleryPickerActivity.this.finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
The MAT results, run from Eclipse, look like this. It shows all the various calls I have made to this Activity, as though none of them have been actually released:
The normal memory for the application hangs around 11-15mb, but as you can see it is now at ~50mb, and grows each time I call the activity. If all the memory for the suspects was reclaimed I think I would be right where I should be:
Finally, could this be a result of running from Eclipse remotely to the device? I saw something similar with another control and was not able to replicate. Whereas I am definitely able to replicate this.
Thanks!
Just to wrap this one up, the issue was the new Thread(), which was holding onto the resources and specifically the GridView (at +4mb per hit). My final solution was to just get rid of the thread and looper, and just call the two methods directly in the init() of the Activity. I have no idea why it was coded into a looping thread to begin with, though I suspect it may have been to update the list of images on the fly (or cut and pasted code that was not really understood). Anyway seems to be working and the memory is being successfully garage collected. Thanks to #dharms you the help!
Related
I made an app in android and it is working fine but when I shifted my app to my main app it start showing error from that point package name is same as that of my previous app then also this is the error that i am getting .I followed many question but cant able to find any solution .
FATAL EXCEPTION: main
Process: unnion.neelay.beatbox, PID: 12739
java.lang.RuntimeException: Unable to start activity ComponentInfo{unnion.neelay.beatbox/unnion.neelay.beatbox.ringdroid.RingdroidSelectActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2423)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2483)
at android.app.ActivityThread.access$900(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1349)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5441)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
at unnion.neelay.beatbox.ringdroid.RingdroidSelectActivity.onCreate(RingdroidSelectActivity.java:123)
at android.app.Activity.performCreate(Activity.java:6303)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2376)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2483)
at android.app.ActivityThread.access$900(ActivityThread.java:153)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1349)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5441)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
it is showing null point exception but it was working properly when not added to the main app.
the ringdroid select activity
public class RingdroidSelectActivity
extends ListActivity
implements LoaderManager.LoaderCallbacks<Cursor> {
private SearchView mFilter;
private SimpleCursorAdapter mAdapter;
private boolean mWasGetContentIntent;
private boolean mShowAll;
private Cursor mExternalCursor;
// Result codes
private static final int EXT_STORAGE_PERMISSION_REQ_CODE = 2;
private static final int WRITE_EXTERNAL_STORAGE = 4;
private static final int READ_PHONE_STATE = 3;
private static final int WRITE_SETTINGS = 3;
private static final int CHANGE_CONFIGURATION = 1;
private static final int MODIFY_AUDIO_SETTINGS = 5;
private static final int INTERNET = 6;
private static final int REQUEST_CODE_EDIT = 1;
private static final int REQUEST_CODE_CHOOSE_CONTACT = 2;
// Context menu
private static final int CMD_EDIT = 4;
private static final int CMD_DELETE = 5;
private static final int CMD_SET_AS_DEFAULT = 6;
private static final int CMD_SET_AS_CONTACT = 7;
public RingdroidSelectActivity() {
}
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
checkReadStoragePermission();
mShowAll = false;
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
showFinalAlert(getResources().getText(R.string.sdcard_readonly));
return;
}
if (status.equals(Environment.MEDIA_SHARED)) {
showFinalAlert(getResources().getText(R.string.sdcard_shared));
return;
}
if (!status.equals(Environment.MEDIA_MOUNTED)) {
showFinalAlert(getResources().getText(R.string.no_sdcard));
return;
}
Intent intent = getIntent();
mWasGetContentIntent = intent.getAction().equals(
Intent.ACTION_GET_CONTENT);
// Inflate our UI from its XML layout description.
setContentView(R.layout.media_select);
getActionBar().setIcon(new ColorDrawable(getResources().getColor(android.R.color.transparent)));
getActionBar().setDisplayShowTitleEnabled(false);
try {
mAdapter = new SimpleCursorAdapter(
this,
// Use a template that displays a text view
R.layout.media_select_row,
null,
// Map from database columns...
new String[]{
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media._ID},
// To widget ids in the row layout...
new int[]{
R.id.row_artist,
R.id.row_title,
R.id.row_icon,
R.id.row_options_button},
0);
setListAdapter(mAdapter);
// Normal click - open the editor
getListView().setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent,
View view,
int position,
long id) {
startRingdroidEditor();
}
});
mExternalCursor = null;
getLoaderManager().initLoader(EXTERNAL_CURSOR_ID, null, this);
} catch (SecurityException e) {
// No permission to retrieve audio?
Log.e("Ringdroid", e.toString());
// TODO error 1
} catch (IllegalArgumentException e) {
// No permission to retrieve audio?
Log.e("Ringdroid", e.toString());
// TODO error 2
}
mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.row_options_button) {
// Get the arrow ImageView and set the onClickListener to open the context menu.
ImageView iv = (ImageView) view;
iv.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
openContextMenu(v);
}
});
return true;
} else if (view.getId() == R.id.row_icon) {
setSoundIconFromCursor((ImageView) view, cursor);
return true;
}
return false;
}
});
// Long-press opens a context menu
registerForContextMenu(getListView());
}
private void setSoundIconFromCursor(ImageView view, Cursor cursor) {
if (0 != cursor.getInt(cursor.getColumnIndexOrThrow(
MediaStore.Audio.Media.IS_MUSIC))) {
view.setImageResource(R.drawable.type_music);
((View) view.getParent()).setBackgroundColor(
getResources().getColor(R.color.type_bkgnd_music));
}
String filename = cursor.getString(cursor.getColumnIndexOrThrow(
MediaStore.Audio.Media.DATA));
}
/**
* Called with an Activity we started with an Intent returns.
*/
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent dataIntent) {
if (requestCode != REQUEST_CODE_EDIT) {
return;
}
if (resultCode != RESULT_OK) {
return;
}
setResult(RESULT_OK, dataIntent);
//finish(); // TODO(nfaralli): why would we want to quit the app here?
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.select_options, menu);
mFilter = (SearchView) menu.findItem(R.id.action_search_filter).getActionView();
if (mFilter != null) {
mFilter.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
public boolean onQueryTextChange(String newText) {
refreshListView();
return true;
}
public boolean onQueryTextSubmit(String query) {
refreshListView();
return true;
}
});
}
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.action_record).setVisible(true);
// TODO(nfaralli): do we really need a "Show all audio" item now?
menu.findItem(R.id.action_show_all_audio).setVisible(true);
menu.findItem(R.id.action_show_all_audio).setEnabled(!mShowAll);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_record:
onRecord();
return true;
case R.id.action_show_all_audio:
mShowAll = true;
refreshListView();
return true;
default:
return false;
}
}
#Override
public void onCreateContextMenu(ContextMenu menu,
View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
Cursor c = mAdapter.getCursor();
String title = c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
menu.setHeaderTitle(title);
menu.add(0, CMD_EDIT, 0, R.string.context_menu_edit);
menu.add(0, CMD_DELETE, 0, R.string.context_menu_delete);
// Add items to the context menu item based on file type
if (0 != c.getInt(c.getColumnIndexOrThrow(MediaStore.Audio.Media.IS_RINGTONE))) {
menu.add(0, CMD_SET_AS_DEFAULT, 0, R.string.context_menu_default_ringtone);
menu.add(0, CMD_SET_AS_CONTACT, 0, R.string.context_menu_contact);
} else if (0 != c.getInt(c.getColumnIndexOrThrow(MediaStore.Audio.Media.IS_NOTIFICATION))) {
menu.add(0, CMD_SET_AS_DEFAULT, 0, R.string.context_menu_default_notification);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case CMD_EDIT:
startRingdroidEditor();
return true;
case CMD_DELETE:
confirmDelete();
return true;
case CMD_SET_AS_DEFAULT:
setAsDefaultRingtoneOrNotification();
return true;
case CMD_SET_AS_CONTACT:
return chooseContactForRingtone(item);
default:
return super.onContextItemSelected(item);
}
}
private void setAsDefaultRingtoneOrNotification() {
Cursor c = mAdapter.getCursor();
// If the item is a ringtone then set the default ringtone,
// otherwise it has to be a notification so set the default notification sound
if (0 != c.getInt(c.getColumnIndexOrThrow(MediaStore.Audio.Media.IS_RINGTONE))) {
RingtoneManager.setActualDefaultRingtoneUri(
RingdroidSelectActivity.this,
RingtoneManager.TYPE_RINGTONE,
getUri());
Toast.makeText(
RingdroidSelectActivity.this,
R.string.default_ringtone_success_message,
Toast.LENGTH_SHORT)
.show();
} else {
RingtoneManager.setActualDefaultRingtoneUri(
RingdroidSelectActivity.this,
RingtoneManager.TYPE_NOTIFICATION,
getUri());
Toast.makeText(
RingdroidSelectActivity.this,
R.string.default_notification_success_message,
Toast.LENGTH_SHORT)
.show();
}
}
private int getUriIndex(Cursor c) {
int uriIndex;
String[] columnNames = {
MediaStore.Audio.Media.INTERNAL_CONTENT_URI.toString(),
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString()
};
for (String columnName : Arrays.asList(columnNames)) {
uriIndex = c.getColumnIndex(columnName);
if (uriIndex >= 0) {
return uriIndex;
}
// On some phones and/or Android versions, the column name includes the double quotes.
uriIndex = c.getColumnIndex("\"" + columnName + "\"");
if (uriIndex >= 0) {
return uriIndex;
}
}
return -1;
}
private Uri getUri() {
//Get the uri of the item that is in the row
Cursor c = mAdapter.getCursor();
int uriIndex = getUriIndex(c);
if (uriIndex == -1) {
return null;
}
String itemUri = c.getString(uriIndex) + "/" +
c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
return (Uri.parse(itemUri));
}
private boolean chooseContactForRingtone(MenuItem item) {
try {
//Go to the choose contact activity
Intent intent = new Intent(Intent.ACTION_EDIT, getUri());
intent.setClassName(
"unnion.neelay.beatbox.ringdroid",
"unnion.neelay.beatbox.ringdroid.ChooseContactActivity");
startActivityForResult(intent, REQUEST_CODE_CHOOSE_CONTACT);
} catch (Exception e) {
Log.e("Ringdroid", "Couldn't open Choose Contact window");
}
return true;
}
private void confirmDelete() {
// See if the selected list item was created by Ringdroid to
// determine which alert message to show
Cursor c = mAdapter.getCursor();
String artist = c.getString(c.getColumnIndexOrThrow(
MediaStore.Audio.Media.ARTIST));
CharSequence ringdroidArtist =
getResources().getText(R.string.artist_name);
CharSequence message;
if (artist.equals(ringdroidArtist)) {
message = getResources().getText(
R.string.confirm_delete_ringdroid);
} else {
message = getResources().getText(
R.string.confirm_delete_non_ringdroid);
}
CharSequence title;
if (0 != c.getInt(c.getColumnIndexOrThrow(
MediaStore.Audio.Media.IS_RINGTONE))) {
title = getResources().getText(R.string.delete_ringtone);
} else if (0 != c.getInt(c.getColumnIndexOrThrow(
MediaStore.Audio.Media.IS_ALARM))) {
title = getResources().getText(R.string.delete_alarm);
} else if (0 != c.getInt(c.getColumnIndexOrThrow(
MediaStore.Audio.Media.IS_NOTIFICATION))) {
title = getResources().getText(R.string.delete_notification);
} else if (0 != c.getInt(c.getColumnIndexOrThrow(
MediaStore.Audio.Media.IS_MUSIC))) {
title = getResources().getText(R.string.delete_music);
} else {
title = getResources().getText(R.string.delete_audio);
}
new AlertDialog.Builder(RingdroidSelectActivity.this)
.setTitle(title)
.setMessage(message)
.setPositiveButton(
R.string.delete_ok_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
onDelete();
}
})
.setNegativeButton(
R.string.delete_cancel_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
}
})
.setCancelable(true)
.show();
}
private void onDelete() {
Cursor c = mAdapter.getCursor();
int dataIndex = c.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
String filename = c.getString(dataIndex);
int uriIndex = getUriIndex(c);
if (uriIndex == -1) {
showFinalAlert(getResources().getText(R.string.delete_failed));
return;
}
if (!new File(filename).delete()) {
showFinalAlert(getResources().getText(R.string.delete_failed));
}
String itemUri = c.getString(uriIndex) + "/" +
c.getString(c.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
getContentResolver().delete(Uri.parse(itemUri), null, null);
}
private void showFinalAlert(CharSequence message) {
new AlertDialog.Builder(RingdroidSelectActivity.this)
.setTitle(getResources().getText(R.string.alert_title_failure))
.setMessage(message)
.setPositiveButton(
R.string.alert_ok_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
finish();
}
})
.setCancelable(false)
.show();
}
private void onRecord() {
try {
Intent intent = new Intent(Intent.ACTION_EDIT, Uri.parse("record"));
intent.putExtra("was_get_content_intent", mWasGetContentIntent);
intent.setClassName("unnion.neelay.mediaplayer.ringdroid", "unnion.neelay.mediaplayer.ringdroid.RingdroidEditActivity");
startActivityForResult(intent, REQUEST_CODE_EDIT);
} catch (Exception e) {
Log.e("Ringdroid", "Couldn't start editor");
}
}
private void startRingdroidEditor() {
Cursor c = mAdapter.getCursor();
int dataIndex = c.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
String filename = c.getString(dataIndex);
try {
Intent intent = new Intent(Intent.ACTION_EDIT, Uri.parse(filename));
intent.putExtra("was_get_content_intent", mWasGetContentIntent);
intent.setClassName("unnion.neelay.mediaplayer.ringdroid", "unnion.neelay.mediaplayer.ringdroid.RingdroidEditActivity");
startActivityForResult(intent, REQUEST_CODE_EDIT);
} catch (Exception e) {
Log.e("Ringdroid", "Couldn't start editor");
}
}
private void refreshListView() {
mExternalCursor = null;
Bundle args = new Bundle();
args.putString("filter", mFilter.getQuery().toString());
getLoaderManager().restartLoader(EXTERNAL_CURSOR_ID, args, this);
}
private static final String[] EXTERNAL_COLUMNS = new String[]{
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.IS_RINGTONE,
MediaStore.Audio.Media.IS_ALARM,
MediaStore.Audio.Media.IS_NOTIFICATION,
MediaStore.Audio.Media.IS_MUSIC,
"\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\""
};
private static final int EXTERNAL_CURSOR_ID = 1;
/* Implementation of LoaderCallbacks.onCreateLoader */
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
ArrayList<String> selectionArgsList = new ArrayList<String>();
String selection;
Uri baseUri;
String[] projection;
switch (id) {
case EXTERNAL_CURSOR_ID:
baseUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
projection = EXTERNAL_COLUMNS;
break;
default:
return null;
}
if (mShowAll) {
selection = "(_DATA LIKE ?)";
selectionArgsList.add("%");
} else {
selection = "(";
for (String extension : SoundFile.getSupportedExtensions()) {
selectionArgsList.add("%." + extension);
if (selection.length() > 1) {
selection += " OR ";
}
selection += "(_DATA LIKE ?)";
}
selection += ")";
selection = "(" + selection + ") AND (_DATA NOT LIKE ?)";
selectionArgsList.add("%espeak-data/scratch%");
}
String filter = args != null ? args.getString("filter") : null;
if (filter != null && filter.length() > 0) {
filter = "%" + filter + "%";
selection =
"(" + selection + " AND " +
"((TITLE LIKE ?) OR (ARTIST LIKE ?) OR (ALBUM LIKE ?)))";
selectionArgsList.add(filter);
selectionArgsList.add(filter);
selectionArgsList.add(filter);
}
String[] selectionArgs =
selectionArgsList.toArray(new String[selectionArgsList.size()]);
return new CursorLoader(
this,
baseUri,
projection,
selection,
selectionArgs,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER
);
}
/* Implementation of LoaderCallbacks.onLoadFinished */
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch (loader.getId()) {
case EXTERNAL_CURSOR_ID:
mExternalCursor = data;
break;
default:
return;
}
// TODO: should I use a mutex/synchronized block here?
if (mExternalCursor != null) {
Cursor mergeCursor = new MergeCursor(new Cursor[]{mExternalCursor});
mAdapter.swapCursor(mergeCursor);
}
}
/* Implementation of LoaderCallbacks.onLoaderReset */
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
#TargetApi(Build.VERSION_CODES.M)
private void checkReadStoragePermission() {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
ActivityCompat.requestPermissions(RingdroidSelectActivity.this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, EXT_STORAGE_PERMISSION_REQ_CODE);
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
onPermissionsNotGranted();
}
dialog.dismiss();
finish();
startActivity(getIntent());
}
};
new android.support.v7.app.AlertDialog.Builder(this)
.setTitle(R.string.permissions_title)
.setMessage(R.string.read_ext_permissions_message)
.setPositiveButton(R.string.btn_continue, onClickListener)
.setNegativeButton(R.string.btn_cancel, onClickListener)
.setCancelable(false)
.show();
return;
}
ActivityCompat.requestPermissions(RingdroidSelectActivity.this, new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.READ_PHONE_STATE}, EXT_STORAGE_PERMISSION_REQ_CODE);
return;
}
}
private void onPermissionsNotGranted() {
Toast.makeText(this, R.string.toast_permissions_not_granted, Toast.LENGTH_SHORT).show();
Log.v("tom", "JERRY");
}
}
Looking at your callstack it should really help you narrow down your problem.
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
at unnion.neelay.beatbox.ringdroid.RingdroidSelectActivity.onCreate(RingdroidSelectActivity.java:123)
at android.app.Activity.performCreate(Activity.java:6303)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2376)
For example, in your callstack, you first have the exception that's being thrown, NullPointerException, and it's telling you what is causing it.
java.lang.String.equals(java.lang.Object)
So, you have a String that you're attempting to call .equals on, but the String is null.
Now, a bit lower, it shows the line number of where this issue is happening.
unnion.neelay.beatbox.ringdroid.RingdroidSelectActivity.onCreate(RingdroidSelectActivity.java:123)
So, you're calling .equals within your RingdroidSelectActivity's onCreate at line 123.
However, perhaps your code has changed since you posted your error, there isn't a .equals around that line, but I'm thinking it may be your getExternalStroage().
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
showFinalAlert(getResources().getText(R.string.sdcard_readonly));
return;
}
Perhaps you don't have the permission for this or something else. Add in some checks for null, and that will help you debug the problem.
Hopefully that helps!
Edit:
The issue was this
so the answer is
mWasGetContentIntent = Intent.ACTION_GET_CONTENT.equals(intent.getAction());
I've made a music player usim MediaPlayer. When I close the app the song keeps playing but when I resume, onCreate is called everything starts again and previous song also keeps playing. So if now I start new song, both the songs play even though there's only one MediaPlayer variable. Why is onCreate called when app is reopened. What is the way to prevent it?
EDIT: Note that xml file also gets reset. PLus I loose control over song playing before leaving the app.
public class MainActivity extends AppCompatActivity {
SeekBar seekBar;
MediaPlayer mediaPlayer;
ImageView imageView;
Handler handler = new Handler();
private String[] mAudioPath;
private String[] mMusicList;
static int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button ctrl = (Button) findViewById(R.id.play);
Button stop = (Button) findViewById(R.id.stop);
imageView = (ImageView) findViewById(R.id.imageView);
ListView listView = (ListView) findViewById(R.id.listView);
seekBar = (SeekBar) findViewById(R.id.seekBar);
mediaPlayer = MediaPlayer.create(MainActivity.this,R.raw.song);
seekBar.setMax(mediaPlayer.getDuration());
//get tracks list
mMusicList = getAudioList();
mAudioPath = getmAudioPath();
ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mMusicList);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Toast.makeText(MainActivity.this,mAudioPath[position],Toast.LENGTH_SHORT).show();
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(mAudioPath[position]);
mediaPlayer.prepare();
mediaPlayer.seekTo(0);
seekBar.setMax(mediaPlayer.getDuration());
seekBar.setProgress(0);
ctrl.setText("║");
try {
byte[] art;
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(mAudioPath[position]);
art = mediaMetadataRetriever.getEmbeddedPicture();
Bitmap songImage = BitmapFactory.decodeByteArray(art, 0, art.length);
imageView.setImageBitmap(songImage);
}
catch (Exception e){
byte[] art;
Bitmap songImage = BitmapFactory.decodeResource(getResources(), R.drawable.default_artwork);
imageView.getLayoutParams().width= ViewGroup.LayoutParams.MATCH_PARENT;
imageView.setImageBitmap(songImage);
}
mediaPlayer.start();
handler.postDelayed(runnable,1);
} catch (IOException e) {
e.printStackTrace();
}
}
});
//Get track data
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(MainActivity.this, Uri.parse("android.resource://in.swapsha96.playtime/"+R.raw.song));
String artist;
artist = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
if (artist == null)
artist = "Unknown Artist";
try {
byte[] art;
art = mediaMetadataRetriever.getEmbeddedPicture();
Bitmap songImage = BitmapFactory.decodeByteArray(art, 0, art.length);
imageView.setImageBitmap(songImage);
}
catch (Exception e){
imageView.setBackgroundColor(Color.BLACK);
}
Toast.makeText(MainActivity.this,artist,Toast.LENGTH_SHORT).show();
//Controls
ctrl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!mediaPlayer.isPlaying()) {
mediaPlayer.start();
ctrl.setText("║");
}
else {
mediaPlayer.pause();
ctrl.setText("►");
}
seekBar.setProgress(mediaPlayer.getCurrentPosition());
handler.postDelayed(runnable,1);
}
});
stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mediaPlayer.pause();
mediaPlayer.seekTo(0);
ctrl.setText("►");
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
handler.removeCallbacks(runnable);
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
handler.removeCallbacks(runnable);
mediaPlayer.seekTo(seekBar.getProgress());
handler.postDelayed(runnable,1);
}
});
}
//update seekBar
Runnable runnable = new Runnable() {
#Override
public void run() {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
handler.postDelayed(this,1);
}
};
private String[] getAudioList() {
final Cursor mCursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATA }, null, null,
"LOWER(" + MediaStore.Audio.Media.TITLE + ") ASC");
int count = mCursor.getCount();
String[] songs = new String[count];
String[] mAudioPath = new String[count];
int i = 0;
if (mCursor.moveToFirst()) {
do {
songs[i] = mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
mAudioPath[i] = mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
i++;
} while (mCursor.moveToNext());
}
mCursor.close();
return songs;
}private String[] getmAudioPath() {
final Cursor mCursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATA }, null, null,
"LOWER(" + MediaStore.Audio.Media.TITLE + ") ASC");
int count = mCursor.getCount();
String[] songs = new String[count];
String[] path = new String[count];
int i = 0;
if (mCursor.moveToFirst()) {
do {
songs[i] = mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
path[i] = mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
i++;
} while (mCursor.moveToNext());
}
mCursor.close();
return path;
}
}
As you know : onCreate(), onStart() and onResume() will be called when you start an Activity.So to avoid onCreate recall, you can use a boolean in your onCreate method for example isActivityReopened that is set to false, then set to true in the first use of onCreate. Here an example you can inspire from it :
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
// Other stuff
if (!isActivityReopened) {
// Run what do you want to do only once.
// To avoid onCreate() if it will be called a second time,
// so put the boolean to true
isActivityReopened = true;
}
}
In your code you are not checking whether the mediaplayer was playing or not every time you choose a new song.
if(mediaPlayer.isPlaying())
{mediaplyer.stop()}
you need to stop it and then reset it again.
try as well to set the launch mode in the Manifest file of the activitg tag to be singleTask.
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
My advice for you if you want yourself to get out of all this is to use a bound service. It will help you managing the mediaplayer states and will keep running in the background. This great tutorial might help.
I tried to make a custom Adapter and I made it functionall maybe not the best way and may be not the intelligentes Way so I ask here what I can do to make this a little more efficient
public class MovieDataAdapter extends BaseAdapter implements FetchImage.AsyncResponse {
private Context mContext;
public MovieDataAdapter(Context context) {
mContext = context;
}
#Override
public int getCount() { // get coutn Method
SQLiteDatabase db = new MvDBHelper(mContext).getReadableDatabase();
Cursor cur = db.query(MovieContract.MovieEntry.TABLE_NAME, null, null, null, null, null, null);
return cur.getCount();
}
#Override
public Object getItem(int position) {
return null;
}//Not needed at the moment
#Override
public long getItemId(int position) {
return 0;
}// Not needed at the moment
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ImageView imageview;
if (convertView != null) {
imageview = (ImageView) convertView; //if used view just use ist again
} else {//if new view set the fitting parameters
imageview = new ImageView(mContext);
imageview.setLayoutParams(new GridView.LayoutParams(getw('w'), getw('h')));
imageview.setScaleType(ImageView.ScaleType.FIT_XY);
}
SQLiteDatabase picturedb = new MvDBHelper(mContext).getReadableDatabase();
Cursor cur = picturedb.query(MovieContract.MovieEntry.TABLE_NAME,
null, null, null, null, null, null
);//get the entries from the db
if (cur != null && cur.moveToFirst()) {
cur.moveToPosition(position); // move to the appropriate position
//defining nessesary Variables
int index_PosterPath = cur.getColumnIndex(MovieContract.MovieEntry.COL_POSTERPATH);
int index_FilePath = cur.getColumnIndex(MovieContract.MovieEntry.COL_FILE);
int index_ortTitel = cur.getColumnIndex(MovieContract.MovieEntry.COL_ORTITEL);
final String Filename = cur.getString(index_ortTitel) + ".jpg";
final String selection = MovieContract.MovieEntry.COL_ORTITEL + " = ?";
final String[] where = {cur.getString(index_ortTitel)};
picturedb.close();// db not needed so is closed
if (cur.isNull(index_FilePath)) {//if file not already saved in the storage save it there
FetchImage getImage = new FetchImage(mContext, new FetchImage.AsyncResponse() {
#Override
public void processfinished(Bitmap output) { // get the image as an Bitmap in asynchronus task throug interface callback
FileOutputStream fos = null;
try {
fos = mContext.openFileOutput(Filename, Context.MODE_PRIVATE);
if (fos != null)
output.compress(Bitmap.CompressFormat.PNG, 100, fos); //put bitmap in file
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
ContentValues values = new ContentValues();
values.put(MovieContract.MovieEntry.COL_FILE, Filename);
SQLiteDatabase picwr = new MvDBHelper(mContext).getWritableDatabase();
int updated = picwr.update(MovieContract.MovieEntry.TABLE_NAME, values, selection, where);
//put the filname in the db for later use
picwr.close();
}
BitmapDrawable draw = new BitmapDrawable(mContext.getResources(), output);
Drawable gridimag = draw;
imageview.setImageDrawable(gridimag); // set the drawable as an image
}
});
String[] ptg = {cur.getString(index_PosterPath)};
getImage.execute(ptg);
} else { // if pic already saved in the internal storage get it from there
FileInputStream fis = null;
try {
fis = mContext.openFileInput(Filename);
Bitmap pic = BitmapFactory.decodeStream(fis);
BitmapDrawable draw = new BitmapDrawable(mContext.getResources(), pic);
Drawable gridimag = draw;
imageview.setImageDrawable(gridimag);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
cur.close();
}
return imageview;
}
public int getw(char c) {
int DisplayWidth = mContext.getResources().getDisplayMetrics().widthPixels;
if (c == 'w') {
return (int) (DisplayWidth / 2);
} else {
return DisplayWidth;
}
}
public static float convertDpToPixel(float dp, Context context) {
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float px = dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
return px;
}
#Override
public void processfinished(Bitmap output) {
}
}
Would be happy about every help I can get even if it's a complet new Way because at the moment the grid view does not work fluently
You should avoid close cursor each time you draw a cell. You can close it only when you done with your activity.
Also you need to avoid using cur.moveToFirst(). Because you are already moving your cursor to given position, why should i moving it first before?
Another trick to use a image loader library (Picasso is one of the best) to load it async and faster. It also handles to stop threads if view is not shown. More optimized.
You dont need to find indexs of coloumn each time you want a new cell. Find them once, use them everytime :)
Also you can use CursorAdapter class to implement it way better :)
From the given ListView in picture, I select the contact to send sms and move to another activity (second picture). And from this sms Activity picture. When I press back hardware button available on phone, I should move where I want. I don't want a default Activity to be displayed. How can I do this?
public class SendSms extends Activity{
ListView listView;
List<RowItems> rowItems;
CustomListViewAdapter adapter;
String toNumbers = "";
String separator;
int i=0,j,count=0,count1; String a[]=new String[5];
String number,val2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new4);
listView = (ListView) findViewById(R.id.list);
rowItems = new ArrayList<RowItems>();
val2=getIntent().getStringExtra("name");
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String rawContactId = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
Cursor c = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {
ContactsContract.CommonDataKinds.Phone.NUMBER,
// ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.PHOTO_ID
}, ContactsContract.Data.RAW_CONTACT_ID + "=?", new String[] { rawContactId }, null);
if (c != null) {
if (c.moveToFirst()) {
String number = c.getString(0);
//int type = c.getInt(1);
String name = c.getString(1);
int photoId = c.getInt(2);
Bitmap bitmap = queryContactImage(photoId);
RowItems p=new RowItems(bitmap, number, name);
rowItems.add(p);
}
adapter = new CustomListViewAdapter(this,
R.layout.new5, rowItems);
listView.setAdapter(adapter);
c.close();
}
}
}
}
private Bitmap queryContactImage(int imageDataRow) {
Cursor c = getContentResolver().query(ContactsContract.Data.CONTENT_URI, new String[] {
ContactsContract.CommonDataKinds.Photo.PHOTO
}, ContactsContract.Data._ID + "=?", new String[] {
Integer.toString(imageDataRow)
}, null);
byte[] imageBytes = null;
if (c != null) {
if (c.moveToFirst()) {
imageBytes = c.getBlob(0);
}
c.close();
}
if (imageBytes != null) {
return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
} else {
return null;
}
}
public void showResult(View v) {
// String result = "";
String result1="";
for (RowItems p : adapter.getBox()) {
if (p.chck){
// result += "\n" + p.getTitle();
result1 +="\n" +p.getDesc();
a[i]=p.getTitle();
i++;
count++;
}
count1=count;
}
Toast.makeText(this, result1+"\n", Toast.LENGTH_LONG).show();
}
public void send(View v) throws IOException {
int value=a.length-count1;
for(j=0;j<a.length-value;j++){
if(android.os.Build.MANUFACTURER.equalsIgnoreCase("Samsung")){
separator = ",";
} else
separator = ";";
number = a[j];
toNumbers= toNumbers +number +separator;
}
toNumbers = toNumbers.substring(0, toNumbers.length());
Uri sendSmsTo = Uri.parse("smsto:" + toNumbers);
String smsValue = "help iam in danger..i am presently at \n"+val2;
if(val2==null){
Toast.makeText(SendSms.this, "wait.....", Toast.LENGTH_LONG).show();
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType("vnd.android-dir/mms-sms");
intent.putExtra("sms_body", smsValue);
intent.setData(sendSmsTo);
startActivity(intent);
}
Use startAtctivityForResult, and in onActivityResult check the resultCode. If it is Activity.RESULT_CANCELLED, the user 'backed out' of the SMS activity. Due to the implementation of the SMS activity being outside of your control, this might not be the only case when the result code says it has been cancelled.
I think you should, when the Activity picture is displayed, try to call the onBackPressed method.
// back button pressed method
#Override
public void onBackPressed() {
super.onBackPressed();
// new intent to call an activity that you choose
Intent intent = new Intent(this, NewActivity.class);
startActivity(intent);
// finish the activity picture
this.finish();
}
If you don't want to call an external Activity, you can hide the layout calling by the Intent as below:
// back button pressed method
#Override
public void onBackPressed() {
super.onBackPressed();
// your layout with the picture is displayed, hide it
if(MySecondView.getVisibility() == View.VISIBLE)
MySecondView.setVisibility(View.Gone);
// display the layout that you want
MyDefaultView.setVisibility(View.VISIBLE);
}
As I said below, try with a boolean that you initialize to false at the beginning of your Class. When you start the Intent.ACTION_VIEW, make this boolean to true:
public class Foo extends Activity {
private boolean isSms = false;
// some stuff
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType("vnd.android-dir/mms-sms");
// ...
startActivity(intent);
// make your boolean to true
isSms = true;
// create the onBackPressed method
#Override
public void onBackPressed() {
// check if the user is on the sms layout
if(isSms)
// do something
else
// do something else like finish(); your activity
}
}
Or you can try to use the onKeyDown method (see here: onKeyDown (int keyCode, KeyEvent event)) as below:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK && event.getRepeatCount()==0) {
// dome some stuff
return true;
}
return super.onKeyDown(keyCode, event);
}
You can see the diffence between these two methods here: onBackPressed() not working and on the website that I talk in the comments below.
Hope this will be useful.
UPDATE:
A better way should make an startActivityForResult to start the Intent.ACTION_VIEW:
startActivityForResult(intent, 1);
And then, you return the cancel code like this:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode != 1 && resultCode == RESULT_CANCELED) {
// do something
}
}
This is #FunkTheMonk, just above, who tells the good choice!
Add this method to the class to handle device back button.
#Override
public void onBackPressed() {
// do something
}
Please note that it requires API Level 5 or higher.
You have to overide go back behaviour of hardware back button by calling a method name onbackpressed();
#Override
public void onBackPressed() {
super.onBackPressed();
// set intent to activity where you want to move on after back press
Intent intent = new Intent(this, NewActivity.class);
startActivity(intent);
// also clean the current activity from stack.
youractivityname.this.finish();
}
I found this file picker online, which the developer said that people could use if they wanted to.
Since I thought the code was easy to understand - I decided to use it and change it a bit for my application.
All credit goes to the original developer (https://github.com/mburman/Android-File-Explore)
loadFileList();
showDialog(DIALOG_LOAD_FILE);
Log.d(TAG, path.getAbsolutePath());
}
private void loadFileList() {
try {
path.mkdirs();
} catch (SecurityException e) {
Log.e(TAG, "unable to write on the sd card ");
}
// Checks whether path exists
if (path.exists()) {
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String filename) {
File sel = new File(dir, filename);
// Filters based on whether the file is hidden or not
return (sel.isFile() || sel.isDirectory())
&& !sel.isHidden();
}
};
String[] fList = path.list(filter);
fileList = new Item[fList.length];
for (int i = 0; i < fList.length; i++) {
fileList[i] = new Item(fList[i], R.drawable.file_icon);
// Convert into file path
File sel = new File(path, fList[i]);
// Set drawables
if (sel.isDirectory()) {
fileList[i].icon = R.drawable.directory_icon;
Log.d("DIRECTORY", fileList[i].file);
} else {
Log.d("FILE", fileList[i].file);
}
}
if (!firstLvl) {
Item temp[] = new Item[fileList.length + 1];
for (int i = 0; i < fileList.length; i++) {
temp[i + 1] = fileList[i];
}
temp[0] = new Item("Up", R.drawable.directory_up);
fileList = temp;
}
} else {
Log.e(TAG, "path does not exist");
}
adapter = new ArrayAdapter<Item>(this,
android.R.layout.select_dialog_item, android.R.id.text1,
fileList) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// creates view
View view = super.getView(position, convertView, parent);
TextView textView = (TextView) view
.findViewById(android.R.id.text1);
// put the image on the text view
textView.setCompoundDrawablesWithIntrinsicBounds(
fileList[position].icon, 0, 0, 0);
// add margin between image and text (support various screen
// densities)
int dp5 = (int) (5 * getResources().getDisplayMetrics().density + 0.5f);
textView.setCompoundDrawablePadding(dp5);
return view;
}
};
}
private class Item {
public String file;
public int icon;
public Item(String file, Integer icon) {
this.file = file;
this.icon = icon;
}
#Override
public String toString() {
return file;
}
}
#Override
protected Dialog onCreateDialog(int id) {
Dialog dialog = null;
AlertDialog.Builder builder = new Builder(this);
if (fileList == null) {
Log.e(TAG, "No files loaded");
dialog = builder.create();
return dialog;
}
switch (id) {
case DIALOG_LOAD_FILE:
builder.setTitle("Choose your file");
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
chosenFile = fileList[which].file;
File sel = new File(path + "/" + chosenFile);
if (sel.isDirectory()) {
firstLvl = false;
// Adds chosen directory to list
str.add(chosenFile);
fileList = null;
path = new File(sel + "");
loadFileList();
removeDialog(DIALOG_LOAD_FILE);
showDialog(DIALOG_LOAD_FILE);
Log.d(TAG, path.getAbsolutePath());
}
// Checks if 'up' was clicked
else if (chosenFile.equalsIgnoreCase("up") && !sel.exists()) {
// present directory removed from list
String s = str.remove(str.size() - 1);
// path modified to exclude present directory
path = new File(path.toString().substring(0,
path.toString().lastIndexOf(s)));
fileList = null;
// if there are no more directories in the list, then
// its the first level
if (str.isEmpty()) {
firstLvl = true;
}
loadFileList();
removeDialog(DIALOG_LOAD_FILE);
showDialog(DIALOG_LOAD_FILE);
Log.d(TAG, path.getAbsolutePath());
}
// File picked
else {
chosenFile = fileList[which].file;
File test = new File(path + "/" + chosenFile);
sendback(test);
}
}
});
break;
}
dialog = builder.show();
return dialog;
}
Sorry, if it's a bit too long. But that's the entire file picker which is in the onCreate().
I open it by using this code:
Bundle b = new Bundle();
b.putInt("tallet", 1);
Intent i = new Intent(getApplicationContext(), FileExplore.class);
i.putExtras(b);
startActivityForResult(i, 0);
The code works perfectly. But when I press "back" (onBackPressed), it gives me blank (black) screen if I say finish(); .
Right now I'm using this code:
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
Intent backIntent = new Intent(FileExplore.this, AndroidTabLayoutActivity.class);
startActivity(backIntent);
}
Which actually works, but it gives me black screen if I press back once, and then the menu, when I hit the back button again. EDIT: it goes INTO the onBackPressed code on second back-press, not the first.
Here's my onActivityResult code in PhotosActivity (it's a tablayout - photosactivity is just one of the screens):
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
// Bundle b = getIntent().getExtras();
if (resultCode == -1)
{
Bundle b = data.getBundleExtra("FiletoPhoto");
int knappen = b.getInt("number");
String titlen = b.getString("title");
{
Listofsounds los = new Listofsounds();
String shortname = los.puttextonit(titlen, knappen);
putnameinit(shortname,knappen);
}
}
else if (resultCode == 0)
{
//If I press "back" i've made the resultCode to be 0 in the onBackPressed. What should I do here then?
}
}
What should I do so I could just press it once and get back to the menu?
The issue is that when you use this code:
Intent backIntent = new Intent(FileExplore.this, AndroidTabLayoutActivity.class);
startActivity(backIntent);
You are basically creating and starting a new activity of AndroidTabLayoutActivity which already exists, so now there will be two copies of this activity running simultaneously. However, the original activity will be expecting a result as you've called startActivityForResult(). I think the solution to your problem is probably to do a check if the resultCode you are getting back as a onActivityResult is RESULT_OK or whatever successful resultCode you are setting in setResult(...) in FileExplore.
This is really strange because in all of my apps I don't override onBackPressed and yet, I am able to finish the activity without causing any weird side effects.