I've got a listview and I want to start a new activity when clicking on an item in that listview. How do I access the variables of that item from the new activity?
Edit: My listview is populated via an Asynctask and an RSS Feed. I want to access one of the items in the array and read out its url.
Method 1:
you can store it in an object of a custom class (which implements Serilizable) on click of listview and pass that object via intent. Make sure :
//to pass :
intent.putExtra("MyClass", obj);
// to retrieve object in second Activity
getIntent().getSerializableExtra("MyClass");
Method 2(not recommended):
Create a static custom class and store the variables in onclick to that class instance.
for Static Class A {...}
//To pass
A.variable = "stored value";
//retrieve
String s = A.variable;
Method 3
Use SharePreferences. Recommended only if you need to remember what user clicked last time he was using the app.
Related
I have created an ArrayList of media file paths and i want to get details of media file like title and album info in my JavaFX application. I want to add these details in ObservableList. So I created an iterator which gives path of all media files. Inside iterator loop, I have created a Media object. To get media information from Media object, I have created metadata event listener. I got media information in lambda function but i can't able to use them outside of lambda function. If i add info in ObservableList inside event listener lambda function than many null values inserting because of meta data iteration and only one useful information is inserting.
Here is my code:
ObservableList<PlayListModel> playListData = FXCollections.observableArrayList();
Iterator<JMPPlayListItem> it = playList.getIterator();
while(it.hasNext()) {
listMedia = new Media(it.next().getPath());
PlayListModel playListItem = new PlayListModel();
listMedia.getMetadata().addListener((MapChangeListener.Change<? extends String, ? extends Object> c)-> {
if (c.wasAdded()) {
if ("artist".equals(c.getKey())) {
playListItem.setArtist(c.getValueAdded().toString());
} else if ("title".equals(c.getKey())) {
// It prints title of song
System.out.println(c.getValueAdded().toString());
playListItem.setTitle(c.getValueAdded().toString());
} else if ("album".equals(c.getKey())) {
playListItem.setAlbum(c.getValueAdded().toString());
}
}
});
// It print null
System.out.println(playListItem.getTitle());
playListData.add(playListItem);
}
System.out.println(c.getValueAdded().toString()) is printing title of song but outside of lambda function System.out.println(playListItem.getTitle()) prints null. It means playListItem object's values isn't changing. I tried making playListItem final but wouldn't help. I also tried initializing playListItem object and playListData.add(playListItem) inside lambda function but it inserts title with many null title values because of event listener iteration.
I also tested with local variables but I'm not able to get values outside of listener lambda function.
I solved this problem. My solution is pass Media object in bean class's constructor and create another method in bean class that will retrieve media information and update bean object. This method is called through constructor. Now add this bean class's object in ObservableList. Observable list get updated automatically when media information event is fired. Now i can render tableview using ObservableList and using table.refresh() method, i can refresh table data when event is fired.
I am relatively new to Android development however I am very familiar with java.
I would like to create an app that displays the periodic table of elements which will have buttons for each element and when a button will be touched, the details of that elements would be shown.
I don't want to create a separate activities for each button. I want to create just one activity and when a button will be touched it's details will be shown. If I go on creating separate activities for each button, I will have to create 100+ activities, which I don't want.
How can I create just one activity and when a element's button is pressed, it's unique details is shown?
For this you can simply achieve this by fragments. In one fragment let's say fragment1 you keep the buttons and in the other fragment let's say fragment2 you keep the details. Whenever you press the button in fragment1 send the details by Bundle to fragment2 and update the details in fragment2.
By this you will used just one activity and two fragments.
Take this tutorial, this will help you to understand Fragments.
http://www.vogella.com/tutorials/AndroidFragments/article.html
You absolutely don't have to create a separate activity for every element.
Once you have the list of elements you can pass the element from the mainActivity to the detailsActivity and, using an adapter, inflate the detail activity with the selected element.
The steps are the following:
Create a Model class of your Element:
public Class Element {
// params
// constructor
// getters and setters
// implement parcelable
}
Create a List of elements:
List<Element> list = new List<>();
list.add(new Element(/* pass your params */));
...
Giving that you already have a Main_Activity where you have your element grid, create a second detailsActivity():
public class detailsActivity extends AppCompatActivity {
#Override protected void onCreate(Bundle b) {}
}
Pass your element from MainActivity to detailsActivity when you click on the grid using Intent and Bundle:
Intent details = new Intent();
Bundle b = new Bundle();
b.putParcelable("selected", element);
details.putExtras(b);
startActivity(details);
Create an adapter to inflate your detailsActivity with the selected Element.
I am in a peculiar situtation in my app.
When i app first loads there is a custom listview which is populated with data from the server.I am also using a class which contains different fields for the string data from the server.
When i click an item on the custom listview,the object of the corresponding class is passed onto the next fragment.
That is the current fragment is replaced with a new fragment and the object is passed with bundle.
Now a new listview loads with different tasks.On clicking a task a new fragment with a camera is loaded.
After taking the image and uploading to server, the status in the JSON changes to "COMPLETED".But now when i press back the old listview is shown.
Is there a way to populate the listview on back pressed with new data?
The issue is that I am passing an object right from the first fragment.
Now i need a new object on back pressed,how to pass the new object on back pressed?
When Fragment 2 gets the data, it should pass it along at some point before Fragment 1 is woken.
There are almost a half dozen ways to pass data, and the best way depends on a number of factors like who should own the lifecycle of the data, data pull vs push, dependency between fragments, do multiple components need updating, etc.
I'm just going to advise to simply cache the data on the activity until you learn more about the different methods.
//Fragment 2 puts data to activity
((MyActivity) getActivity).mListViewData = listViewData;
Then the next part of the question is how does fragment 1 get the data. Fragment 1 is hibernating on the backstack. When it wakes up it will call the onViewCreated() method (because it's previous view was destroyed before being placed on the backstack).
In that method, we check if there's new data waiting for Fragment 1.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
MyDataType listViewData = ((MyActivity) getActivity).mListViewData;
if(listViewData != null){
//setData is your own function for replacing the adapters
//data backing
listView.getAdapter().setData(listViewData);
}else{
listView.getAdapter().setData(...defaultData);
}
listView.getAdapter.notifyDataChanged();
}
Override the onBackPressed in the Activity that manages the Fragments. In it you can check if the fragment is visible or not (the one from which an action should be performed if the back is pressed) and then execute your action.
#Override
public void onBackPressed(){
Fragment myFragment = getFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment.isVisible()) {
String json = myFragment.getJsonData(); //update it locally
if(isUpdated){
Fragment listFragment = getFragmentManager().findFragmentByTag("MY_LIST_FRAGMENT");
listFragment.updateListView(json); //Add this method on your fragment
}
}
super.onBackPressed();
}
Obs.: To use the .findFragmentByTag() you should add tags once you're making the transaction like so:
fragTrans.replace(android.R.id.content, myFragment, "MY_FRAGMENT");
If, for any reason the listFragment has been cleaned from memory, you would have to reload the data anyway so just download the new data again.
To update the ListView please see: How to refresh Android listview? . Note thought that you will need to will need to send a new data set to the list view (which you can do inside the updateListView() method)
Background
I have a ViewPager that will display up to 4 Fragments. The number available at any given time is dynamic (it could be 1, 2, 3, or 4). It makes most sense to have these fragments manage themselves. By that I mean they are singletons. Rather than creating a new fragment with the new keyword, I've written a 'getInstance(String key)' method which attempts to retrieve the fragment for the specified key from the map, or if it does not exist in the map, creates a new instance, places the fragment in the map with the given key, sets the fragments arguments with a bundle containing that key so the fragment can retrieve it onCreate(), and then returns a new instance of that fragment.
For those who aren't following, here's the code:
public class DishListFragment extends ListFragment {
public static final String MENU = "menu";
...
private static Map<String, DishListFragment> mInstances = new HashMap<String, DishListFragment>();
public static DishListFragment getInstance(String menuKey) {
if (mInstances.containsKey(menuKey))
return mInstances.get(menuKey);
Bundle b = new Bundle();
b.putString(MENU, menuKey);
DishListFragment dlf = new DishListFragment();
dlf.setArguments(b);
mInstances.put(menuKey, dlf);
return dlf;
}
}
You may have noticed this is not thread safe.
Walkthrough
OnCreate, my main activity sets its view then spawns an AsyncTask responsible for obtaining data from a server which will populate my DishListFragments. Meanwhile, the main activity continues on and sets the PagerAdapter. When the PagerAdapter requests a new DishListFragment, the number is converted into a key dynamically and the value from the DishListFragment.getInstance(key); method is returned. Initially the content class that is observed by the ListFragments has dummy data so one page always shows up and so there is always one page available for the ViewPager to show.
When the AsyncTask starts, a progress dialog is shown. When it completes, it dismisses the progress dialog and calls a method in my activity which then sets the data in my content class. Then a method, refresh(), is called which tells all the DishListFragments in existence to notify their adapters that the dataset has changed. After that method completes, the ViewPagerAdapter is notified that its dataset has changed.
In my main Activity:
public void onRetrieveData(Result result) {
switch(result.getCode()) {
case Result.SUCCESS:
Log.i(UITHREAD, "Menu successfully loaded!");
/* On SUCCESS the MenuContent class should be given the data and
* the adapters notified. */
mRequestedDate = mPendingDate;
MenuContent.setMenuData(result.getValue());
DishListFragment.refresh();
mMenuPagerAdapter.notifyDataSetChanged();
...
}
}
And the refresh method in the DishListFragment class:
public static void refresh() {
for (String key : mInstances.keySet()) {
mInstances.get(key).mListAdapter.notifyDataSetChanged();
Log.d("glic", "DishListFragment: " + key + " refreshed");
}
Log.d("glic", "DishListFragments refreshed");
}
Problem
The problem is, on a cold start, everything but the frist page is updated. Further, from my Logcat output, I gather there is only one DishListFragment in my map:
10-18 22:11:41.624: I/##############(16802): Menu successfully loaded!
10-18 22:11:41.744: D/glic(16802): DishListFragment: breakfast refreshed
10-18 22:11:41.744: D/glic(16802): DishListFragments refreshed
10-18 22:11:41.744: D/GLIC(16802): lunch
However, my view pager shows 4 pages with the first still containing dummy data. If I rotate the screen, the first page is updated and displays the correct information. Also, if I select an item in the dummy list, a details fragment is displayed with real (from the server) information for the position of the item I selected -- even though I only selected a dummy item.
My first thought is I might have two instances of my singleton fragments. One with a map containing a fragment with the initial dummy data and one containing the real data returned from the server. I guess this is possible since my singleton is not thread safe. However, I don't think this should cause any problems. My DishListFragments do not contain the data they display, they only observe it so regardless of how many instances I might have of the same DishListFragment (same being for the same page), they should all observe the same data and should not show different data -- the dummy data is cleared when the new data from the server is parsed and added.
But, two instances of my mInstances map may explain why the view is not updating. Perhaps the Adapters in only one of the sets of DishListFragments are being notified that their dataset has changed. According to my Logcat though, breakfast, which is my first page and the one that is filled with dummy data, is indeed being notified that its dataset has changed. Interestingly, the others are not.
Question..
So, as for my original question: Am I implementing a singleton grouping of Fragments correctly? If so, what other factors might be causing the weird behavior I'm experiencing. Thanks in advance (=
I have a MyObj class with a name and an id. I have an AutoCompleteTextView that is currently letting you type MyObj names and it auto-completes them for you. There's a button next to the AutoCompleteTextView that, when pressed, I want to:
initiate a search based on the id of the selected MyObj, if one of the auto-complete suggestions was used, OR
initiate a search based on the value in the AutoCompleteTextView if none of the auto-complete suggestions was used (so a partial name string).
How should I go about this? I'm new to Android, so suggestions for other ways to do this are very welcome. Here's some of my current code:
AutoCompleteTextView actv = (AutoCompleteTextView)findViewById(R.id.searchText);
ArrayAdapter<MyObj> adapter = new ArrayAdapter<MyObj>(this,
android.R.layout.simple_dropdown_item_1line, myObjectsList);
actv.setAdapter(adapter);
And also:
public void searchButtonOnClick(View view) {
// Don't know how to get id of selected MyObj here, or just the value in the
// AutoCompleteTextView otherwise
}
I ended up creating a search instead of using an AutoCompleteTextView, since the search gives suggestions as you type also. I was able to pass the id along via the URI in an Intent to display another Activity with the MyObj details.