I have 2 fragment hosted on an activity with a frame layout, I want to implement fragment communication.I have tried some of the codes, but my requirements are not met. Thanks in advance.!
First fragment: It contains a list .
public class ListWithSearch extends Fragment{
String[] cityName;
String[] cityFact;
int[] cityPic;
ListView list;
ListViewAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.city_list_fragment, container,
false);
// Generate sample data
cityName = new String[] { "Delhi", "Chandigarh", "Mumbai", "Bangalore", "Chennai" };
cityFact = new String[] { "China", "India", "United States",
"Indonesia", "Brazil" };
cityPic = new int[] { R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher };
list = (ListView) rootView.findViewById(R.id.listView);
adapter = new ListViewAdapter(getActivity(), cityName,cityPic);
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//To implement
}
});
return rootView;
}
}
Second Fragment: That will be inflated on item click of the list in the first fragment.
public class ResultFragment extends Fragment {
TextView resCityName;
TextView resFact;
ImageView resPic;
String[] cityName;
String[] cityFact;
int[] cityPic;
int position;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
Requirements:
1. ImageView in second fragment to have the same image of the item image in the list.
2. TextViews in second fragment to have data from the list item itself.
In other words, the second fragment is details of the item clicked in the list.
Add the below code to ListWithSearch fragment:
OnListItemSelectListener mCallback;
// Your MainActivity must implement this interface so that ResultFragment can use it
public interface OnListItemSelectListener {
public void onItemSelected(int position, int imageId);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnListItemSelectListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnListItemSelectListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
// You can pass the image id to below method. Modify the code as required.
mCallback.onItemSelected(position, imageId);
}
Google provide a great tutorial for this situation here
There plenty of ways to achieve this but take a look on EventBus, it might simplify the job
Related
I am using nav drawer. So i need from Fragment start Activity in which i start another Activity where i have ListView,clicking on which i must save data.
After save i need to return to Fragment where saved Data must be showing.
So here is my Fragment
public class ArmoryFragment extends Fragment {
public ArmoryFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_armory, container, false);
Button button = (Button) rootView.findViewById(R.id.button_rifles);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), Rifles.class);
startActivity(intent);
}
});
return rootView;
}
}
and here is my activivty from where i need to return
public class Rifles extends Activity implements View.OnClickListener, OnItemSelectedListener {
DatabaseHelper db;
String BrandModel;
private RifleDAO rifleDAO;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rifles);
initList();
this.rifleDAO = new RifleDAO(this);
ListView listView = (ListView) findViewById(R.id.listView1);
SimpleAdapter simpleAdapter = new SimpleAdapter(this, riflesList, android.R.layout.simple_list_item_1, new String[] {"rifle"}, new int[] {android.R.id.text1});
listView.setAdapter(simpleAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String item = ((TextView)view).getText().toString();
Toast.makeText(getBaseContext(), item, Toast.LENGTH_LONG).show();
BrandModel= ((TextView)view).getText().toString();
String[] parts=BrandModel.split(" ");
String Brand=parts[0];
String Model = parts[1];
// need to return from somewhere here
}
});
} next is parser code... supose it is not needed
So how can I return from Activity to Fragment?
Well if you want to save data, I prefer adding the data to a table in your database (obviously you have a databaseHelper class so make you own table) and when you are back from your activity put extra a position you want and call :
selectItem(mCurrentSelectedPosition);
so mCurrentSelectedPosition is the position of the fragment that you want to be selected.
I have MainActivity activity which has 3 fragments. Those 3 fragments use same arrayadapter class MessageListAdapter. When i populate listView in my fragments using different ArrayLists using MessageListAdapter it combines all those ArrayLists and displays in each fragment. I want each fragment to display its own list.
MessageListAdapter:
public class MessageListAdapter extends ArrayAdapter<Message>{
Context context;
public MessageListAdapter(Context c, int resourceId, ArrayList<Message> list) {
super(c, resourceId, list);
this.context = c;
}
//...
}
HomeFragment:
public class HomeFragment extends Fragment {
View view;
ListView listView1;
ArrayList<Message> contactMessages;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.home_layout, container, false);
TextView welcomeMessage = (TextView) view.findViewById(R.id.welcomeMessage);
Account acc = new Account();
welcomeMessage.setText("Welcome " + acc.getName() + "!");
contactMessages = new Message().getContactMessages();
listView1 = (ListView) view.findViewById(R.id.homeList);
MessageListAdapter adapter = new MessageListAdapter(this.getActivity(), R.layout.activity_message, contactMessages);
listView1.setAdapter(adapter);
listView1.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
}
});
return view;
}
}
ProfileFragment:
public class ProfileFragment extends Fragment implements View.OnClickListener, OnItemClickListener {
View view;
Intent intent;
ListView listView2;
ArrayList<Message> personalMessages;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.profile_layout, container, false);
Button button = (Button) view.findViewById(R.id.addMessage);
button.setOnClickListener(this);
Button addFriendButton = (Button) view.findViewById(R.id.addFriend);
addFriendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
intent = new Intent(getActivity(), AddFriendActivity.class);
startActivity(intent);
}
});
personalMessages = new Message().getPersonalMessages();
// Log.i("Personal messages ArrayList: ", personalMessages.toString());
listView2 = (ListView) view.findViewById(R.id.profileList);
MessageListAdapter adapter = new MessageListAdapter(this.getActivity(), R.layout.activity_message, personalMessages);
listView2.setAdapter(adapter);
listView2.setOnItemClickListener(this);
return view;
}
}
Also have 3rd fragment which will use this same MessageListAdapter, but i have not implemented it yet due to running into this problem.
I made screenshots to make it easier to understand:
Items with orange pictures are supposed to be shown only in ProfileFragment and item with blue picture is supposed to be shown only in HomeFragment
Problem lies in using static ArrayList inside Message class. addPersonalMessage adds Message object into personalMessages list and addContactMessage adds Message object into contactMessages list. After i built all the messages according to their type and put them inside lists separately, for some reason application combines those 2 lists. This is why i end up with similar content in both listviews in fragments. Solved problem by using SQLite database instead of using static variables.
Message:
public class Message {
private String author;
private String messageTitle;
private Bitmap messageImage;
private static ArrayList<Message> personalMessages = new ArrayList<Message>();
private static ArrayList<Message> contactMessages = new ArrayList<Message>();
public Message() {
}
public Message(String a, String t, Bitmap b) {
this.author = a;
this.messageTitle = t;
this.messageImage = b;
}
public void addPersonalMessage() {
personalMessages.add(this);
}
public void addContactMessage() {
contactMessages.add(this);
}
}
I have this piece of code I want to show this dummy data in a static list but I get error in extends fragment and also in get activity, how can I solve them? Do I need to change any part of it?
public class AgendaFragment extends Fragment{
private ArrayAdapter<String> magendaAdapter;
public AgendaFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String[] data = {
"Monday going to restaurant at 14",
"Monday going to restaurant at 1",
"Monday going to restaurant at 1",
};
List<String> weekForecast = new ArrayList<String>(Arrays.asList(data));
magendaAdapter =
new ArrayAdapter<String>(
getActivity(), // The current context (this activity)
R.layout.list_item_agenda, // The name of the layout ID.
R.id.list_item_agenda_textview, // The ID of the textview to populate.
weekForecast);
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
// Get a reference to the ListView, and attach this adapter to it.
ListView listView = (ListView) rootView.findViewById(R.id.listview_agenda);
listView.setAdapter(magendaAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
String forecast = magendaAdapter.getItem(position);
Toast.makeText(getActivity(), forecast, Toast.LENGTH_SHORT).show();
}
});
return rootView;
}
}
Add
import android.app.Fragment;
at the beginning of your code file.
(or android.support.v4.app.Fragment if you are using Android support library)
I developed an app which fills a list. It works fine in the way I did it but I'm not conviced that I solved the problem in a recommended way. I read that you should override onActivityCreated in a Fragment and fill the list there instead of doing this in onCreateView. onCreateView should only be used to inflate static views. Is this true? If yes, how should these two methods look like in the end?
This is my Fragment class:
public class FragmentMain extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
List<MyItem> items = createListItems();
ListView listView = (ListView) view.findViewById(R.id.list);
MyListAdapter adapter = new MyListAdapter(view.getContext(), items);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(view.getContext(),
"Clicked " + position, Toast.LENGTH_LONG)
.show();
}
});
return view;
}
.
.
.
}
My MainActivity just adds the fragment:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentMain fm = new FragmentMain();
getFragmentManager().beginTransaction()
.add(R.id.fragment_main_container, fm).commit();
}
.
.
.
}
That is true to a certain extend only because onCreateView happens on the UI thread and you don't want anything slowing that down otherwise your UI will be slow and choppy. For example, in your fragment class you have a call to a method "createListItems()". I don't know how many items you're making but if it's a lot it could slow down your UI (especially if youre accessing a database and querying objects and so on). So you could do it in onActivityCreated but you could also use an AsyncTask. So your code would become something like this:
public class LoadListObjectsTask extend AsyncTask<Void, List<MyItem>, Void> {
private MyListAdapter myListAdapter;
private Context mContext;
public LoadListObjectsTask(Context context) {
this.mContext = context;
}
#Override
public void doInBackground(Void...params) {
//create your list objects here instead of on UI thread. This will run on a separate thread.
myListAdapter = new MyListAdapter(mContext, items);
return items; //return list of MyItems
}
//This is called when doInBackground is done. THIS WILL RUN ON THE UI THREAD So don't do
//anything slow here
#Override
public void onPostExecute(List<MyItem>...params //don't really need the list here//) {
listView.setAdapter(myListAdapter);
}
}
then in your fragment
public class FragmentMain extends Fragment {
private ListView listView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
List<MyItem> items = new ArrayList<MyItem>();
listView = (ListView) view.findViewById(R.id.list);
//new code
new LoadListObjectsTask(getActivity()).execute();
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(view.getContext(),
"Clicked " + position, Toast.LENGTH_LONG)
.show();
}
});
return view;
}
public void onResume()... {
//also add the task here so your content is reloaded on resume..
new LoadListObjectsTask(getActivity()).execute();
}
.
.
.
}
If you don't want to do this just make your List of MyItems a private field and move
List<MyItem> items = createListItems();
to onActivityCreated().
Hope that helps!
In general most of the time I work with Intent rather than Fragment because I found It somehow complex. I have a class with ListView to show some data from an array and I want to convert it in Fragment also want to pass the extras in a new fragmented class.
ListView Class:
public class MainActivity extends Activity {
ListView list;
String[] web = { "Google", "Twitter", "Windows", "Bing", "Itunes",
"Wordpress", "Drupal" };
Integer[] imageId = { R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomList adapter = new CustomList(MainActivity.this, web, imageId);
list = (ListView) findViewById(R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(MainActivity.this,
"You Clicked at " + web[+position], Toast.LENGTH_SHORT)
.show();
Intent i = new Intent(MainActivity.this, intent.class);
i.putExtra("name", web[+position]);
startActivity(i);
}
});
}
}
CustomList Class:
public class CustomList extends ArrayAdapter<String> {
private final Activity context;
private final String[] web;
private final Integer[] imageId;
public CustomList(Activity context, String[] web, Integer[] imageId) {
super(context, R.layout.list_single, web);
this.context = context;
this.web = web;
this.imageId = imageId;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView = inflater.inflate(R.layout.list_single, null, true);
TextView txtTitle = (TextView) rowView.findViewById(R.id.txt);
ImageView imageView = (ImageView) rowView.findViewById(R.id.img);
txtTitle.setText(web[position]);
imageView.setImageResource(imageId[position]);
return rowView;
}
}
I got a main class with three tabs created using fragment and in this class I would like to add the ListView!
public class LayoutOne extends Fragment {
public static Fragment newInstance(Context context) {
LayoutOne f = new LayoutOne();
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.layout_one, null);
return root;
}
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
}
What I want to do is to show the listview in the fragment class and when a list item will be click I want to launch the New Intent to show which Item was clicked!
If you want to pass parameters into a Fragment, common practice is to create a static method that produces an instance of your Fragment with certain parameters. You already have the newInstance method, now you just need to add parameters to the arguments and return the Fragment. You should check for the arguments in your onCreateView The following is an example of how you would write one.
public class LayoutOne extends Fragment
{
public static Fragment newInstance(int someInt, String someString)
{
LayoutOne f = new LayoutOne();
Bundle args = new Bundle();
args.putInt("someInt", someInt);
args.putString("someString", someString);
f.setArguments(args);
return f;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.layout_one, null);
Bundle args = getArguments();
//From here you would check to see if your arguments are present
//proceed accordingly
return root;
}
}
For your specific case, you could pass along the String array and add it as an argument.
Hope this helps. Good luck!
Edit
The problem you're facing is that you're instantiating a ListView in your Activity when in reality you should be doing it in your Fragment. Intents aren't needed here, you just need to make sure that there is a ListView attribute to get from the layout you attach to your Fragment. The following is a small example of how that should work.
Note, this method goes in your LayoutOne class
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.layout_one, null);
//Be sure to use the actual id of your list view
ListView lv = (ListView) root.findViewById(R.id.list_view_id);
//Make sure that you retrieve the values for 'web' and 'imageId' from
//the activity using the "newInstance" method.
CustomList adapter = new CustomList(getActivity(), web, imageId);
lv.setAdapter(adapter);
//From here, set your onClickListener and stuff as you did in your Activity
return root;
}
As a note, Fragments don't have the findViewById method. You have to call it on the View that you are inflating to be its layout, so in this case you inflated root and then you would call root.findViewById(R.id.some_id) to get a view.