I am sending images and audio files to my php server. I am using Asynctask for this. I have two activities in my program. The problem is if I launch my second activity (AudioActivity) from MainActivity like this
upload_audio.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, AudioActivity.class);
startActivity(intent);
}
});
then when i click the button upload_audio the screen goes black but the process still running successfully . so if i make this audio activity my mainActivity then everything works perfect.so how can i make my app still visible during processing files while launching activity from MainActivity.hope you understand my question
here is my code of AudioActivity
public class AudioActivity extends Activity {
private static final int SELECT_AUDIO = 2;
String selectedPath = "";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
upload();
}
public void upload() {
ArrayList<Uri> fileName = getFileList(this);
for ( int i = 0 ; i < fileName.size() ; i++ )
{
try {
selectedPath = getPath(fileName.get(i)).toString();
System.out.println(getPath(fileName.get(i)));
new AudioSync(selectedPath).execute(getPath(fileName.get(i))).get();
// AudioSync sync = new AudioSync(getPath(fileName.get(i))).get;
//new AudioSync().execute("").get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Audio.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
private ArrayList<Uri> getFileList(Context context) {
Cursor actualimagecursor = null;
ArrayList<Uri> fileList = new ArrayList<Uri>();
try
{
String[] proj = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media._ID };
actualimagecursor = managedQuery(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj,
null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
for ( int i = 0 ; i < actualimagecursor.getCount() ; i++ )
{
actualimagecursor.moveToPosition(i);
String fileName = actualimagecursor.getString(actual_image_column_index);
fileList.add(( Uri.withAppendedPath( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, fileName )));
}
return fileList;
}
catch ( Exception e )
{
return null;
}
}
}
You don't want to create an Activity for uploading or playing Audio. Activities are always linked with views and are use to interact with the user.
http://developer.android.com/guide/components/activities.html
You want to use a service to do that: http://developer.android.com/guide/components/services.html
Related
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 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!
On one of my device, the following code can't make my video appear in Gallery:
File file = new File(path);
Uri uri = Uri.fromFile(file);
Intent scanFileIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
activity.sendBroadcast(scanFileIntent);
So I use scanFile explicitly:
android.media.MediaScannerConnection.scanFile(activity, new String[]{file.getAbsolutePath()},
new String[]{"video/" + mMimeType}, null);
When my video is xxx.mpeg4, the value of mMimeType is mp4, the result is that the video can appear in MediaStore but I can't get the duration later(the returned value is always 0). Need help on this.
public static long[] getVideoDetail(Context context, Uri uri) {
long[] result = new long[] {DEFAULT_VIDEO_FRAME_WIDTH, DEFAULT_VIDEO_FRAME_HEIGHT, -1};
if(uri == null || (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()))) {
return result;
}
String[] projection = new String[] {MediaStore.Video.Media.RESOLUTION, MediaStore.Video.VideoColumns.DURATION};
Cursor cursor = null;
boolean success = false;
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor.moveToFirst()) {
String resolution = cursor.getString(0);
if(!StringUtils.isEmpty(resolution)) {
int index = resolution.indexOf('x');
result[0] = Integer.parseInt(resolution.substring(0, index));
result[1] = Integer.parseInt(resolution.substring(index + 1));
if(result[0] != 0 && result[1] != 0) {
success = true;
}
if(result[0] > result[1]) {
swap(result, 0, 1);
}
}
result[2] = cursor.getLong(1);
if(result[2] >= 0 && success) {
success = true;
} else {
success = false;
}
}
if (null != cursor) {
cursor.close();
}
}
catch (Exception e) {
// do nothing
} finally {
try {
if (null != cursor) {
cursor.close();
}
} catch (Exception e2) {
// do nothing
}
}
if (!success) {
try {
ContentResolver contentResolver = context.getContentResolver();
String selection = MediaStore.Images.Media._ID + "= ?";
String id = uri.getLastPathSegment();
String[] selectionArgs = new String[]{ id };
cursor = contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null);
if (cursor.moveToFirst()) {
String resolution = cursor.getString(0);
if(!StringUtils.isEmpty(resolution)) {
int index = resolution.indexOf('x');
result[0] = Integer.parseInt(resolution.substring(0, index));
result[1] = Integer.parseInt(resolution.substring(index + 1));
if(result[0] > result[1]) {
swap(result, 0, 1);
}
}
result[2] = cursor.getLong(1);
}
if (null != cursor) {
cursor.close();
}
} catch (Exception e) {
// do nothing
} finally {
try {
if (cursor != null) {
cursor.close();
}
} catch (Exception e) {
// do nothing
}
}
}
if(result[0] <= 0) {
result[0] = DEFAULT_VIDEO_FRAME_WIDTH;
}
if(result[1] <= 0) {
result[1] = DEFAULT_VIDEO_FRAME_HEIGHT;
}
return result;
}
As I see in your code you are requesting duration in your projection
String[] projection = new String[] {MediaStore.Video.Media.RESOLUTION, MediaStore.Video.VideoColumns.DURATION};
now you just need to retrieve it from the cursor like shown below:
long timeInMs = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DURATION));
get help from MediaPlayer :
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(context, Uri.parse(uri));
} catch (IOException e) {
Log.d("-MS-","Cannot parse url");
e.printStackTrace();
}
int duration= mp.getDuration();
String[] projection = new String[] {MediaStore.Video.Media.RESOLUTION,duration};
I always get Duration by MediaPlayer.
I have been trying to figure this out for days, but can't seem to find the solution.
The problem is that even after getting the album art bitmap from MediaStore, and converting it to a drawable, it is assigned to an ImageView in a custom ListView layout via HashMap (String, Object), but finally after running on actual device and emulator, no album art is shown.
No LogCat error either. The ImageView of the custom listview layout does not show the album art.
public class AllSongs extends Fragment
{
Bitmap bitmap = null;
BitmapDrawable drawable = null;
private ArrayList<HashMap<String,Object>> list = new ArrayList<HashMap<String,Object>>();
private HashMap<String, Object> item;
private SimpleAdapter sa;
private ListView listview;
...
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
...
AsyncTaskRunner runner = new AsyncTaskRunner();
runner.execute("500");
}
private class AsyncTaskRunner extends AsyncTask<String, String, String>
{
#Override
protected String doInBackground(String... params) {
getAllMusicFiles();
return "Done!";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
listview.setAdapter(sa); //Set all the file in the list.
}
}
private void getAllMusicFiles() {
// TODO Auto-generated method stub
//Some audio may be explicitly marked as not being music
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
String[] projection = {
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID
};
Cursor cursor = getActivity().getApplicationContext().getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
null);
while(cursor.moveToNext()){
item = new HashMap<String,Object>();
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
long albumId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
final Uri ART_CONTENT_URI = Uri.parse("content://media/external/audio/albumart");
Uri albumArtUri = ContentUris.withAppendedId(ART_CONTENT_URI, albumId);
ContentResolver res = context.getContentResolver();
InputStream in;
try { // Yes, the album art has been found. I am sure of this.
if(bitmap != null)
{
bitmap.recycle();
bitmap = null;
if(drawable != null)
{
drawable = null;
}
}
in = res.openInputStream(albumArtUri);
bitmap = BitmapFactory.decodeStream(in);
drawable = new BitmapDrawable(getResources(), bitmap);
} catch (FileNotFoundException e) { // Album not found so set default album art
e.printStackTrace();
drawable = (BitmapDrawable) getActivity().getResources().getDrawable(R.drawable.default_albumart);
}
item.put("icon", drawable);
item.put("title", title);
item.put("artist", artist);
list.add(item);
if(cursor.isLast())
{
sa = new SimpleAdapter(getActivity(), list,
R.layout.custom_listview_layout,
new String[] {"icon", "title","artist" },
new int[] {R.id.icon,R.id.title, R.id.artist});
}
}
}
I have detected that the drawable may be the one causing the image to not be shown because if I replace -
item.put("icon", drawable);
with -
item.put("icon", R.drawable.default_albumart);
it shows the default album art.
Any idea what's causing this?
It's your adapter implementation is causing the problems, not the Drawable.
Look at these two lines of code:
item.put("icon", drawable) - this puts a Drawable object to your hashmap
item.put("icon", R.drawable.default_albumart) - this puts an int value to your map, but as map only works with objects, it is autoboxed before being put there
Thus, the problem is that your adapter works fine with integer identifiers of drawables, but not the drawables themselves. These are the constraints of SimpleAdapter
To solve this issue I would suggest you to implement your custom CursorAdapter. Its implementation is simply straightforward, and will save you from unnecessary steps, such as creating unnecessary lists, hashmaps etc, wasting app memory.
Feel free to ask anything else in comments, good luck!
The answer was given correctly by Drew but here is how it was finally implemented. Here are the changes -
private void getAllMusicFiles() {
// TODO Auto-generated method stub
//Some audio may be explicitly marked as not being music
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
String[] projection = {
MediaStore.Audio.Media._ID, // this is required acc to documentation
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID
};
cursor = getActivity().getApplicationContext().getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
null);
getActivity().startManagingCursor(cursor);
listview.setAdapter(new CustomCursorAdapter(context, cursor));
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
if(cursor != null)
{
getActivity().stopManagingCursor(cursor);
cursor.close();
}
super.onDestroy();
}
removed the AsyncTask as it wasn't here required anymore.
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
...
AsyncTaskRunner runner = new AsyncTaskRunner();
runner.execute("500");
}
CustomCursorAdapter.java -
public class CustomCursorAdapter extends CursorAdapter {
#SuppressWarnings("deprecation")
public CustomCursorAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}
private Bitmap bitmap = null;
private BitmapDrawable drawable = null;
#Override
public void bindView(View view, Context context, Cursor cursor) {
// TODO Auto-generated method stub
TextView title1 = (TextView) view.findViewById(R.id.title);
TextView artist1 = (TextView) view.findViewById(R.id.artist);
ImageView album1 = (ImageView) view.findViewById(R.id.icon);
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
long albumId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
StringBuilder titleBuild = new StringBuilder();
titleBuild.append(title);
if(titleBuild.length() > 35)
{
titleBuild.setLength(32);
title = titleBuild.toString()+"...";
}
else
{
title = titleBuild.toString();
}
StringBuilder artistBuild = new StringBuilder();
artistBuild.append(artist);
if(artistBuild.length() > 35)
{
artistBuild.setLength(32);
artist = artistBuild.toString()+"...";
}
else
{
artist = artistBuild.toString();
}
final Uri ART_CONTENT_URI = Uri.parse("content://media/external/audio/albumart");
Uri albumArtUri = ContentUris.withAppendedId(ART_CONTENT_URI, albumId);
ContentResolver res = context.getContentResolver();
InputStream in;
try {
if(bitmap != null)
{
bitmap = null;
if(drawable != null)
{
drawable = null;
}
}
in = res.openInputStream(albumArtUri);
bitmap = BitmapFactory.decodeStream(in);
// bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), albumArtUri);
drawable = new BitmapDrawable(context.getResources(), bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
drawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.default_albumart);
}
album1.setImageDrawable(drawable);
title1.setText(title);
artist1.setText(artist);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater inflater = (LayoutInflater)context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.custom_listview_layout, parent, false);
}
}
After factory reset of the device.
I'm trying to retrieve the calendars display names(by the code below), it returns that there is no calendars.
but when opening the device Calendar application at least one time, the default phone calendar will be retrieved correctly.
Is there any way to retrieve the calendars (especially the default ) without opening the device Calendar application?
Thanks in advance.
Here is the code for retrieving calendars exist on the device:
private Uri getCalendarUri() {
return Uri.parse(Integer.parseInt(Build.VERSION.SDK) > 7 ? "content://com.android.calendar/calendars" : "content://calendar/calendars");
}
private String[] getCalendars(Context context) {
String[] res = null;
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = contentResolver.query( getCalendarUri(),
Integer.parseInt(Build.VERSION.SDK) > 13 ? new String[]{"_id", "calendar_displayName"} : new String[]{"_id", "displayName"}, null, null, "_id ASC");
if (cursor.getCount() > 0) {
res = new String[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
res[i] = cursor.getString(0) + ": " + cursor.getString(1);
i++;
}
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (cursor != null)
cursor.close();
}
return res;
}
I solved the issue.
using this code in my activity:
private static boolean calendar_opened = false;
private void openCalendar() {
String[] calendars = getCalendars(this);
if (!calendar_opened && calendars != null && calendars.length <= 0) {
new Timer().schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
try {
//bring back my activity to foreground
final Intent tmpIntent = (Intent) MainScreen.this.getIntent().clone();
tmpIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
tmpIntent.setClass(MyExams.getInstance(), MainScreen.class);
PendingIntent.getActivity(MyExams.getInstance(), 0, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT).send();
}
catch (Exception e) {
}
}
});
}
}, 100 );//time is your dissection
Intent i = new Intent();
i.setClassName("com.android.calendar", "com.android.calendar.LaunchActivity");
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(i);
calendar_opened = true;
}
}
//After my activity is on foreground I killed the calendar using this code, even there's no need because of FLAG_ACTIVITY_NO_HISTORY:
ActivityManager activityManager = (ActivityManager) MainScreen.this.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses("com.android.calendar");
I think the device calendar application must be installing a calendar when you open it which may not be available before you open it after a factory reset.
I think you don't want the user to have to open the calendar application. If you don't mind the calendar application being opened in background, you could consider opening it through a Service an then closing it soon so that the user won't notice and the device calendar would be available.
android-codes-examples.blogspot.in/2011/11/… Check this link out, is it useful?