I have some Acitivity with a ListView.
I want that after clicking the ListView item there should be new Activity with the same type of layout contains another info(e.g.ListView) related to the clicked item.
I have known that there is not way to create dynamically Activities.
What should I do to be able to go from one Layout to another(by clicking ListView items) and should be able to go back in the same back-sequence by back-key?
I have known that there is not way to create dynamically Activities.
What should I do to be able to go from one Layout to another(by
clicking ListView items) and should be able to go back in the same
back-sequence by back-key?
Why can't you create activities dynamically? You can easily create a new one from your ListView onclick listener
lv.setOnItemClickListener(new OnItemClickListener(){
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
//Based on the position of the clicked item create a new activity with the position id
Intent intent = new Intent(currentActivity.this, newActivity.this);
intent.putExtra("id", position);
startActivity(intent);
}
};
And now in the newActivity you would check what is the passed id by doing
Bundle bundle = getIntent().getExtras();
theId = bundle.getInt("id");
//Now do something based on that id
Pressing on the back key from the new activity should take you back to the previous one
You can use A Fragment to implements your ListView:
http://developer.android.com/reference/android/app/ListFragment.html
then you can simply replace the current ListFragment with a new one by using the FragmentManager class and the FragmentTransation class. In this way the FragmentManager will take care of replacing the new ListFragment with the old one when you press the back button.
Be careful since if you use ListFragment your SDK target must be 11 or more. If this is a concern for you, you can use the class Fragment from the support library putting inside it a ListView. FragmentManager and FragmentTransation are also part of the support library.
Related
I'm a beginner in Android, so I apologize for the mistakes and I'd appreciate any constructive criticism.
I'm writing a basic application with a ListView of images, and when the user clicks on an item in the list, I want to display that image in a ViewPager, where the user can swipe back and forth to browse the whole list of images. Afterwards when the user presses the back button, I want to switch back to the ListView.
I manage the business logic in the MainActivity, which uses MainActivityFragment for the ListView and ImageHolderFragment for ViewPager.
The simplified code so far is as follows:
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListItems = new ArrayList<>();
mListItemAdapter = new ListItemAdapter(this, R.layout.list_item, R.id.list_item_name, mListItems);
mListView = (ListView) findViewById(R.id.list_view_content);
mListView.setAdapter(mListItemAdapter);
mDeletedListItems = new ArrayList<>();
mViewPager = (ViewPager) getLayoutInflater().inflate(R.layout.image_display, null, true);
mImageAdapter = new ImageAdapter(getSupportFragmentManager(), mListItems);
mViewPager.setAdapter(mImageAdapter);
mViewPager.setOffscreenPageLimit(3);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mViewPager.setCurrentItem(position);
setContentView(mViewPager); // TODO: this is very wrong!
}
});
loadImages();
noContentText = (TextView) findViewById(R.id.no_content_text);
if (mListItems.isEmpty()) {
noContentText.setText(R.string.no_images);
} else {
mImageAdapter.notifyDataSetChanged();
}
}
Although this does work to some extent, meaning that it manages to display the ViewPager when an item in the list is clicked, there are two things about it ringing the alarm bells:
I've read that calling setContentView() for the second time in the same class is pretty much a sin. Nobody explained me why.
The back button doesn't work in this case. When it's pressed, the application is terminated instead of going back to the list view. I believe this is connected to the first point.
I would appreciate any help, explanations if my idea is completely wrong, and if my case is hopeless, I'd like to see a successful combination of ListView and ViewPager with transitions between each other.
Your activity already has R.layout.activity_main set as content view, which rightly displays the list view - that's what the responsibility of this activity is as you defined it. If we want to change what's shown on the screen, we should use a different instance of a building block (activity or fragment) to display the view pager images.
To say the least, imagine if you wanted to change the view to a third piece of functionality or UI, or a fourth... it would be a nightmare to maintain, extend and test as you're not separating functionality into manageable units. Fields that are needed in one view are mixed with those needed in another, your class file would grow larger and larger as each view brings its click listeners, callbacks, etc., you'd also have to override the back button so it does what you want - it's just not how the Android framework was designed to help you. And what if you wanted to re-use UI components in different contexts whilst tapping in to the framework's activity lifecycle callbacks? That's why fragments were introduced.
In your case, the list view could continue to run in your MainActivity and in your click listener, onItemClick you could start a new activity that will hold a viewPager:
Intent i = new Intent(MainActivity.this, MyLargePhotoActivityPager.class);
i.putExtra(KEY_POSITION, position);
// pass the data too
startActivityForResult(i, REQUEST_CODE);
Notice how you could pass the position to this activity as an int extra, in order for that second activity to nicely set the viewPager to the position that the user clicked on. I'll let you discover how to build the second activity and put the ViewPager there. You also get back button functionality assuming your launch modes are set accordingly, if needed. One thing to note is that when you do come back to the list View, you'd probably want to scroll to the position from the view pager, which is why you could supply that back as a result via a request code. The returned position can be supplied back to the list view.
Alternatively, you could use the same activity but have two fragments (see the link further above) and have an equivalent outcome. In fact, one of your fragments could store the list view, and the second fragment could be a fullscreen DialogFragment that stores a viewPager, like a photo gallery (some details here).
Hope this helps.
I've read that calling setContentView() for the second time in the
same class is pretty much a sin. Nobody explained me why.
Well, you kind of get an idea as to why.
When you use setContentView() to display another 'screen' you do no have a proper back stack.
You also keep references to Views (like mListView) that are not visible anymore and are therefore kind of 'useless' after you setContentView() for the second time.
Also keep in mind orientation changes or your app going to the background - you'll have to keep track of the state that your Activity was in which is way more complicated than it has to be if you have one Activity that does two different things.
You won't be arrested for doing things like you do right now, but it's just harder to debug and keep bug free.
I'd suggest using two different Activities for the two different things that you want to do, or use one Activity and two Fragments, swapping them back and forth.
If you insist on having it all in one Activity you need to override onBackPressed() (called when the user presses the back button) and restore the first state of your Activity (setContentView() again, pretty much starting all over).
I'm trying to build an application that will have list/detail panes built with fragments. List is created from the ContentProvider. When clicked on the list the details is populated or activity created. In action similar to gmail application. How the data should be shared/passed between fragments/activities?
Population of the list wasn't that hard, but how can I pass the selection to the details fragment (either in the same activity or another activity)? Should I query again and returned result used in details?
It needs to be like gmail app, so swipe left/right should then change the details accordingly to the same order as the list is either in the single pane layout or dual pane layout.
I think for this I need to share the Cursor returned by the CursorLoader to keep the same order. Then swipes would increase/decrease the index and would display correct item.
Also as I already loaded data, I wanted to reuse it without new queries.
Could someone point me to the right direction, what you would you do to achieve that (no code but algorithm/steps)?
At the moment I have 2 activities list and detail, the list has dual and single panel layout and list fragment with details fragment are used, detail has just single pane with details fragment. I think I could reduce it to be a single activity and juggle the fragments but don't know if it will be good.
Here is a way to pass data from one activity to another :
intent = new Intent(this, ProductListActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(PRODUCT_LIST, productList);
bundle.putString(KEY_WORD, keyWord);
intent.putExtras(bundle);
startActivity(intent);
If you're in an activity and want to pass data to a fragment in that activity, just use setters from that fragment
EDIT : Since last comment, implement a class to handle your object with the Serializable interface :
public class MyDBObject implements Serializable {
//Stuff
}
Then when you fetch from your DB, return or a MyDBObject, or a List<MyDBObject>
Finally, when you need to pass the data, just use
Intent intent = new Intent(SourceActivity.this, TargetActivity.class);
intent.putExtra("DB_OBJECTS", ArrayList<MyDBObject>mDBObject); // For a list
intent.putExtra("DB_OBJECT", mDBOject); //For a single object
What I did then was:
activity holding the fragment(s) will do:
implement LoaderManager.LoaderCallbacks<Cursor>
call the getSupportLoaderManager().initLoader(ALL_DATA_LOADER_ID, null, this);
pass arguments of the LoaderCallbacks to the fragments that also implements LoaderCallbacks
call the getSupportLoaderManager().restartLoader(ALL_DATA_LOADER_ID, null,
this); whenever data was changed outside of the ContentProvider means
This way I'm sharing the same cursor between fragments. Between activities I'm exchanging (via Intent) the data needed to request the same dataset and selection id if needed.
I have an Android app with a ListView. Every row is generated dinamically by SQLIte query results. When users click on a item, the app should refresh the list with the "content" of that item, generated by another SQLite query, and so on.
I tried to "refresh" the activity creating a new intent and sending it to the same activity. Activity name is ShopActivity
ListView list_content = ((ListView)findViewById(R.id.listforshop));
list_content.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// ID and text of selected item
long selected_id = id;
String selected_name = (String) ((TextView) view.findViewById(R.id.element)).getText();
// New intent
Intent intent = getIntent();
intent.setClassName(ShopActivity.this, ShopActivity.class.getName());
// Passing data and refreshing activity
intent.putExtra("id", selected_id);
intent.putExtra("name", selected_name);
intent.putExtra("type", "");
startActivity(intent);
}
});
In this way LogCat shows me a lot of warnings about Bundle. It seems that app cannot start activity.
Is there another way to "refresh" ListView? Is this implementation correct?
// New intent
Intent intent = getIntent();
intent.setClassName(ShopActivity.this, ShopActivity.class.getName());
This does not make a new Intent, this reuses the existing one... Re-using an Intent like this will throw a lot of warning and exception when you resume this Activity. In order to create a new Intent you need to use the keyword new.
But you don't really need to reload your entire Activity, simply fetch a new Cursor and use CursorAdapter#swapCursor() to refresh your ListView.
When trying to refresh your ListView you should think of using notifyDataSetChanged() of your adapter. this method tells your adapter that the provided data has changed and that it should update the list view.
So you should add the new data to your adapter and then call this method.
Sounds like you're viewing the details, don't use the same activity to view them. Add a new ShopDetailActivity and direct the user there on click, that way the user can press back to go to the original list (plus get the nice transition animation).
Another way of handling lists and details is to use Fragments. The advantage of this is that on large-screen devices, both the list and the detail can be visible at the same time.
Using one Activity to show both list and detail is messy. At the very least, use two Activities.
I have an activity which has four tab. first tab has list view and some list item . after clicking on list item i want to open an activity on the same tab (first tab).
I couldn't find any solution of that.
help me !! Thanks
There is a way to open a new activity, which is with an Intent, so you can do the following:
Intent intent=new Intent(Activity.this or this,Activity2.class);
//here you can add the flags you might need
startActivity(intent);
The activity Activity.this or this is the one that launches the new Activity, so the code must be inside the Activity that is showing the tab you are using.For example, if you need to change the title you can add the following:
#Override
public void onResume()
{
super.onResume();
this.getParent().setTitle("Your title");
}
I'm working on my first Android project, and I created a menu via the XML method. My activity is pretty basic, in that it loads the main layout (containing a ListView with my String array of options). Here's the code inside my Activity:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// allow stuff to happen when a list item is clicked
ListView ls = (ListView)findViewById(R.id.menu);
ls.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// #todo
}
});
}
Within the onItemClick callback handler, I'd like to check which item was clicked, and load a new menu based upon that.
Question 1: How do I go about figuring out which item was clicked? I can't find any straightforward examples on retrieving/testing the id value of the clicked item.
Question 2: Once I have the id value, I assume I can just call the setContentView method again to change to another layout containing my new menu. Is that correct?
I'm working on my first Android
project, and I created a menu via the
XML method.
Actually, Android has a separate concept of menus, so I'd be a bit wary about describing your UI in those terms.
How do I go about figuring out which
item was clicked?
If you are using an ArrayAdapter, the position parameter passed to onItemClick() is the index into your array.
I assume I can just call the
setContentView method again to change
to another layout containing my new
menu. Is that correct?
Yes, though there may be better approaches to the UI that will be more Android-y. Most Android applications do not start off with some sort of multi-layer navigation before you actually get to do something.