I have an audio app with the home Activity containing a list of items. The user selects an item and I pass an ID to another Activity which has the controls (play/pause/volume, etc). The audio playback is handed in a MediaBrowserService. I need to detect if the item the user selects is currently playing but I can't figure out how outside of saving the ID in local storage (SharedPrefs or SQlite).
I pass the ID of the item from the second Activity to the MediaBrowserService though a Bundle. I thought I could then retrieve the ID in the second Activity using getExtras() but it always returns 0 or null, depending on which code I use (see below).
I'm not opposed to using local storage but seem like there should be a better way. This is what I have so far:
public class EpisodeActivity extends Activity {
private MediaBrowserCompat mMediaBrowserCompat;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle extras = new Bundle();
extras.putInt("episodeid", getIntent().getExtras().getInt("episodeid")); //passed in from Home Activity
mMediaBrowserCompat = new MediaBrowserCompat(
this,
new ComponentName(this, MediaPlayerService.class),
mMediaBrowserCompatConnectionCallback,
extras
);
mPlayButton.setOnClickListener(view -> {
final Bundle extras = new Bundle();
extras.putInt("episodeid", getIntent().getExtras().getInt("episodeid")); //passed in from Home Activity
String url = "http://www.example.com/media.mp3"
MediaControllerCompat.getMediaController(mActivity).getTransportControls().playFromUri(Uri.parse(uri), extras);
});
if (MediaControllerCompat.getMediaController(mActivity).getPlaybackState() != null &&
MediaControllerCompat.getMediaController(mActivity).getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING) {
int episodeID = mMediaBrowserCompat.getExtras().getInt("episodeid"); //always returns 0
//also tried this but getExtras is null
int episodeID = MediaControllerCompat.getMediaController(mActivity).getExtras().getInt("episodeid");
}
}
}
public class MediaPlayerService extends MediaBrowserServiceCompat {
private MediaSessionCompat mMediaSessionCompat;
#Override
public void onCreate() {
super.onCreate();
final ComponentName mediaButtonReceiver = new ComponentName(getApplicationContext(), MediaButtonReceiver.class);
mMediaSessionCompat = new MediaSessionCompat(getApplicationContext(), getString(R.string.app_name), mediaButtonReceiver, null);
mMediaSessionCompat.setCallback(mMediaSessionCallback);
...
}
private MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {
#Override
public void onPlayFromUri(final Uri uri, final Bundle extras) {
super.onPlayFromUri(uri, extras);
int episodeId = extras.getInt("episodeid");
String url = GetUrl(episodeId);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(uri);
mMediaPlayer.prepareAsync();
...
}
}
}
media_controller.getMetadata().getDescription().getMediaId() may be what you're looking for. If not, maybe try using MediaMetadataCompat.Builder() to set some metadata to each of your episodes
MediaMetadataCompat.Builder().putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, episodeID).build()
something like that, I don't think you need to use the METADATA_KEYs either, you can probably replace that with "episode id" or whatever string you want to use as a key.
edit: if you go the metadata route, you may want to use that to build mediaitems.
MediaMetadataCompat episode_meta = new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, episodeID)
.build();
episode_mediaitem = new MediaBrowserCompat.MediaItem(episode_meta.getDescription(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE));
Hope i helped
edit: using the media items enables you to use the media_controller.getMetadata().getDescription().getMediaId() from above, I think
mPlayButton.setOnClickListener(view -> {
final Bundle extras = new Bundle();
extras.putInt("episodeid", getIntent().getExtras().getInt("episodeid")); //passed in from Home Activity
String url = "http://www.example.com/media.mp3"
MediaControllerCompat.getMediaController(mActivity).getTransportControls().playFromUri(Uri.parse(uri), extras);
});
here you should put url instead uri when you parse Uri.
Related
I have a main activity with a recyclerview that contains images inside imageviews. When you click on an image, a detail activity is launched.
I need to pass 2 objects to an intent and retrieve them in the detail activity, but for some reason I can't do it. When I use a debugger, I can see that both objects are saved in the intent extras.
However, when I fetch them on the other side, I can't find my arraylist extra.
Can you help me to figure out why?
This is my code:
holder.mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mActivity.isTwoPaneMode()) {
Bundle arguments = new Bundle();
arguments.putParcelable(MovieListActivity.MOVIE,movie);
arguments.putStringArrayList("TRAILERS", (ArrayList)movie.getTrailerList());
MovieDetailFragment fragment = new MovieDetailFragment();
fragment.setArguments(arguments);
mActivity.getSupportFragmentManager().beginTransaction()
.replace(R.id.movie_detail_container, fragment)
.commit();
} else {
Context context = v.getContext();
Intent intent = new Intent(context, MovieDetailActivity.class);
intent.putExtra(MovieListActivity.MOVIE, movie);
intent.putStringArrayListExtra("TRAILERS", (ArrayList)movie.getTrailerList());
context.startActivity(intent);
}
}
});
On the other activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_detail);
if (savedInstanceState == null) {
Intent intent = getIntent();
ArrayList<String> trailers = intent.getStringArrayListExtra("TRAILERS");
Movie movie = intent.getParcelableExtra(MovieListActivity.MOVIE);
Bundle arguments = new Bundle();
arguments.putParcelable(MovieListActivity.MOVIE, movie);
arguments.putStringArrayList(MovieListActivity.MOVIE,
getIntent().getStringArrayListExtra("TRAILERS"));
MovieDetailFragment fragment = new MovieDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.movie_detail_container, fragment)
.commit();
}
}
My movie class implements parcelable correctly.
Take a look at the Android Intent docs here.
Specifically, the The name must include a package prefix, ... when using Intent#putStringArrayListExtra.
Try something like this:
intent.putStringArrayListExtra(PACKAGE_NAME + ".TRAILERS", (ArrayList)movie.getTrailerList());
where PACKAGE_NAME is equal to your application's package name.
Try fetching data from a Bundle instead of and Intent. This way you can know if data was actually passed to the activity because the Bundle will be null if nothing was passed. Also add the package name to the data String.
PACKAGE_NAME = getApplicationContext().getPackageName();
arguments.putStringArrayList(PACKAGE_NAME+"TRAILERS,(ArrayList)movie.getTrailerList());
Instead of doing:
Intent intent = getIntent();
ArrayList<String> trailers = intent.getStringArrayListExtra(PACKAGE_NAME+"TRAILERS");
do:
Bundle extras = getIntent().getExtras();
ArrayList<String> trailers;
if(extras!=null){
ArrayList<String> trailers = extras.getStringArrayList("TRAILERS");
}else{
Toast.makeToast(this, "No data was passed", Toast.LENGTH_LONG).show();
}
If the Toast shows up it means your data wasn't passed correctly.
sorry if this is a dummy question, but I am quite new coding in Android and using the Google Drive API.
In my app, I need to create a file within a folder I previously created. At the time that the folder is created, I can only retrieve the DriveID using DriveId.encodeToString. So, in order to get the ResourceID for the creation of the file in that folder, I have implemented the following code. Although the code is working, this code never returns to the previous activity.
Could anyone help me and explain the reason? I suspect that it should be something related to the .setResultCallback.
This is how I call the activity:
Intent intent = new Intent(this, test.class);
intent.putExtra("projectFolderID", selectedProject.getpId());
intent.putExtra("FileName", LIKED_FILE_NAME);
intent.putExtra("LikedArticle", userLikes);
//startActivityForResult(intent, LIKE_FILE);
startActivity(intent);
This is the code in the activity to create the file
public class test extends BaseActivity {
private DriveId mFolderDriveId;
private DriveId projectFolderID;
private String folderResourceID;
private DriveFolder appFolder;
private String nFile;
private LikedArticles userLikes;
private boolean printed = false;
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
//Get Data from previous activity
Intent intentDisplayQuery = getIntent();
projectFolderID = DriveId.decodeFromString(intentDisplayQuery.getStringExtra("projectFolderID"));
nFile = intentDisplayQuery.getStringExtra("FileName");
userLikes = (LikedArticles) intentDisplayQuery.getSerializableExtra("LikedArticle");
//Retrieve the resourceId of the project folder from decoding Id
if (userLikes.getmLikedArticle().size()>0){
appFolder = projectFolderID.asDriveFolder();
appFolder.getMetadata(getGoogleApiClient())
.setResultCallback(metadataCallback);
}
}
final private ResultCallback<DriveResource.MetadataResult> metadataCallback = new
ResultCallback<DriveResource.MetadataResult>() {
#Override
public void onResult(DriveResource.MetadataResult metadataResult) {
if (!metadataResult.getStatus().isSuccess()) {
showMessage("Problem while retrieving files");
return;
}
Metadata mdb;
try {
mdb = metadataResult.getMetadata();
mFolderDriveId = mdb.getDriveId();
folderResourceID = mFolderDriveId.getResourceId();
/*Drive.DriveApi.fetchDriveId(getGoogleApiClient(), folderResourceID)
.setResultCallback(idCallback);*/
} finally { }
}
};
}
Thanks in advance for your help.
I have an app I am developing that polls a vehicle's sensors via the obd2 port. Everything is going great and now I am adding a new activity that shows which sensors are supported and which aren't.
The issue now is that there is a possibility that a user might start the activity before all the supported commands have been checked, thus the ListView needs to be updated when the variable does change.
Now all the available pids are stored on a variable on the mainview, but once it changes it gets broadcasted and updated on the supportview.
The issue I am having is that it doesn't want to update the listview automatically. I have gone through multiple threads on SF and haven't found a solution thus far. I have tried everything from creating a custom handler and receiver to running it on the UI-thread.
This is the complete activity:
public class SupportedView extends ListActivity {
ArrayAdapter<Spanned> mAdapter;
ArrayList<Spanned> commandsList;
private String availpids;
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"ObdReader");
if (!wakeLock.isHeld()){
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
wakeLock.acquire();
}
String pids32 = intent.getParcelableExtra("pids");
updateList(pids32);
Log.d("receiver", "Got message: Updated PIDS" );
mAdapter.notifyDataSetChanged();
Toast.makeText(context, "Received and tried update", Toast.LENGTH_LONG).show();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sl_listview);
//Set fullscreen
availpids = MainView.pids32_val;
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("pids"));
updateList(availpids);
mAdapter = new ArrayAdapter<Spanned>(this, R.layout.sllist_item, commandsList);
setListAdapter(mAdapter);
//ListView lv = getListView();
}
public void updateList(String listPids){
commandsList = new ArrayList<>();
final ArrayList<Spanned> tmpEnabled = new ArrayList<>();
final ArrayList<Spanned> tmpDisabled = new ArrayList<>();
for (ObdCommand Command : ObdConfig.getCommands()) {
int commandKey = Command.getKey();
if(commandKey > 0 && commandKey < 999 && listPids != null) {
boolean isSupported = String.valueOf(listPids.charAt(commandKey - 1)).equals("1");
if (isSupported) {
tmpEnabled.add(Html.fromHtml( "<font color=\"green\">" + Command.getName() + " isn't supported</font>"));
}else {
tmpDisabled.add(Html.fromHtml("<font color=\"red\">" + Command.getName() + " is supported</font>"));
}
}
}
commandsList.addAll(tmpEnabled);
commandsList.addAll(tmpDisabled);
}
#Override
protected void onDestroy() {
// Unregister since the activity is about to be closed.
super.onDestroy();
}
}
Let's take a look at your 'updateList()' method:
it takes the String with the pids and creates and populates a
new ArrayList()
named 'commandsList'.
In fact, you are using the same name for two different objects. The other object is the ArrayList<Spanned> you declared as a class variable (member) and assigned to be the data source for the ListView in your 'onCreate()' method.
I think what you meant to do in your method 'updateList()' was to empty the data source list and then fill it with the pids.
To achieve that, change the method as follows:
public void updateList(String listPids)
{
// empty the data source list:
commandsList.clear();
final ArrayList<Spanned> tmpEnabled = new ArrayList<>();
final ArrayList<Spanned> tmpDisabled = new ArrayList<>();
for (ObdCommand Command : ObdConfig.getCommands())
{
// keep this part as before ...
}
commandsList.addAll(tmpEnabled);
commandsList.addAll(tmpDisabled);
// now, you have indeed changed the data set :)
}
In addition to that, in order to make sure that the BroadcastReceiver is available when needed, you should register it in 'onResume()' and unregister it in 'onPause()' (the method 'onDestroy()' is not guaranteed to be called).
I have an activity from where I start a second activity like so:
public void onItemSelected(long id) {
// start the detail activity for the selected item ID.
Intent detailIntent = new Intent(this, FeedDetailActivity.class);
detailIntent.putExtra(FeedDetailFragment.ARG_ITEM_ID, id);
startActivityForResult(detailIntent, DETAIL_REQUEST_ID);
}
In the secondary activity I do this:
if (getArguments().containsKey(ARG_ITEM_ID))
{
long id = getArguments().getLong(ARG_ITEM_ID);
[...]
}
But I get a class cast exception when that getLong is executed stating the parameter is a java.lang.Integer. I was running this in the debugger and noticed that the Intent is created with id of type Long, but it is received with id of type Integer with the value set to 0 (see screenshots).
The Intent as I create it
The intent as I receive it
What is going on?
You are passing Intent to FeedDetailActivity. But reading extras from the FeedDetailFragment which is inside the FeedDetailActivity I think so. So getting wrong value.
Try this approach
First of all read extras from onCreate method of FeedDetailActivity as we read read from an activity.
if(getIntent().hasExtras(ARG_ITEM_ID) {
id = getIntent().getLongExtra(ARG_ITEM_ID);
}
Create Fragment using beginTransaction().replace(/*YourContainer*/, FeedDetailFragment.getInstance(id))
Create a function in FeedDetailFragment as
public static FeedDetailFragment getInstance(long userId) {
FeedDetailFragment mFragment = new FeedDetailFragment();
Bundle mBundle = new Bundle();
mBundle.putLong(ARG_ITEM_ID, userId);
mFragment.setArguments(mBundle);
return mFragment;
}
Now you can read your ID from FeedDetailFragment
if (getArguments() != null && getArguments().containsKey(ARG_ITEM_ID)) {
ID= getArguments().getLong(ARG_ITEM_ID, -1);
}
I explained this badly originally. This is my question: The Intent I send to the startActivity() method, contains a private field, mMap, which is a Map containing the strings I sent to putExtra(). When the target activity starts, a call to getIntent() returns an Intent that does not contain those values. The mMap field is null. Obviously, something in the bowels of the View hierarchy or the part of the OS that started the new activity created a new Intent to pass to it, since the object IDs are different.
But why? And why are the putData() values not carried fowrard to the new Intent?
The activity that starts the new activity extends Activity. Here's the startup code:
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case 4:
i = new Intent(this, StatList.class);
i.putExtra("Name1", "Test1");
i.putExtra("Name3", "Test2");
startActivity(i);
}
}
I've tried the key values with and without the (recommended) complete package name prefix.
In the Eclipse debugger, I have verified the values for the player names are being inserted into i.mExtras.mMap properly.
Here's the code from the startee:
public class StatList extends ListActivity {
private final StatsListAdapter statsAdapter;
public StatList() {
statsAdapter = StatsListAdapter.getInstance(this);
} // default ctor
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent i = getIntent();
final Bundle extras = i.getExtras();
< more code here >
}
When execution gets to this method, mIntent.mExtras.mMap is null, and mIntent.mExtras.mParcelledData now contains some values that don't look sensible (it was null when startActivity() was called). getIntent() returns mIntent.
I've also tried startActivityForResult(), with the same result.
From the docs and the samples I've seen online & in the sample apps, this should be easy. I've found another way to meet my immediate need, but I'd like to know if anyone can help me understand why something this simple doesn't work.
In your main Activity:
i = new Intent(this, StatList.class);
i.putExtra("Name1", "Test1");
i.putExtra("Name3", "Test2");
startActivity(i);
Then in StatList.class
Bundle extras = getIntent().getExtras();
String name1 = extras.getString("Name1");
String name3 = extras.getString("Name3");
Log.i("StatList", "Name1 = " + name1 + " && Name3 = " + name3)
Update the following two line
final Intent i = getIntent();
final Bundle extras = i.getExtras();
Replace it with
Bundle extras = getIntent().getExtras();
if(extras!= null){
String var1= extras.getString("Name1");
String var2= extras.getString("Name2");
}