Am developing an app where i need to call multiple ListFragments on same activity. It contains main parent ListFragment with 10 rows in it.
By clicking each row i need to open new child ListView next to parent ListView as like this. And my coding is
public class FragmentListArray extends Activity {
static String[] TITLES =
{
"Henry IV (1)",
"Henry V",
"Henry VIII",
"Richard II",
"Richard III",
"Merchant of Venice",
"Othello",
"King Lear"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the list fragment and add it as our sole content.
if (getFragmentManager().findFragmentById(android.R.id.content) == null) {
ArrayListFragment list = new ArrayListFragment();
getFragmentManager().beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class ArrayListFragment extends ListFragment {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, FragmentListArray.TITLES));
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// here i need to achieve my childview click listener..
}
}
}
I don't know how to set onitem click listener. Help me in achieving the above. Thanks in advance.
You can use getActivity() and cast the result to your activity's class to get instance of the Activity, which holds the fragment.
Define some function that will accept the id of the item, depending on which you need to load data in the sectond list Fragment. Should look like this:
YourActivity activity = (YourActivity)getActivity();
activity.fillSecondFragment(clickedItemId);
What you are trying to achieve it's very similiar to android developers example about fragments, instead a normal fragment when list item click use your listfragmnet (which in fact is a fragment)
http://developer.android.com/guide/components/fragments.html
Related
I have pondered on this for days now, I need help. I have 2 fragments in a viewpager. They are both showing the same values despite feeding them with different data.
Link to image
Fragment A has a spinner dropdown of countries same as Fragment B. Fragment A is supposed to show list of Hospitals when country is selected, Fragment B is supposed to show list of Schools depending on country selected.
PROBLEM
When I select a country in Fragment A, I get the list of hospitals in fragment A. When I swipe to fragment B, I find the list of hospitals which are supposed to be in A displayed. When I select a country in B, the list refreshes and I get the list of schools as should be, but when I swipe back again to fragment A I find the same list of schools instead of list of hospitals previously selected. I am using dagger2 with databinding.
Below code depicts one scenario but they are basically the same just different adapters and also different layouts.
CODE
private void initRecyclerview() {
binding.rvSchools.setHasFixedSize(true);
adapter = new SchoolsAdapter(getContext());
binding.rvSchools.setLayoutManager(new LinearLayoutManager(getContext()));
binding.rvSchools.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
private void countries() {
viewModel.getCountries().removeObservers(getViewLifecycleOwner());
viewModel.getCountries().observe(getViewLifecycleOwner(), new Observer<Resource<List<Countries>>>() {
#Override
public void onChanged(Resource<List<Countries>> countriesList) {
switch (countriesList.status) {
case SUCCESS:
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(getApplicationContext,
R.layout.simple_spinner_item, countriesList);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
binding.spinner.setAdapter(spinnerAdapter);
spinnerAdapter.notifyDataSetChanged();
break;
}
}
});
binding.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String country = countriesList.get(position);
schools(country);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}
private void schools(String country) {
viewModel.getSchoolsHospitals(country, "School").removeObservers(getViewLifecycleOwner());
viewModel.getSchoolsHospitals(country, "School").observe(getViewLifecycleOwner(), new Observer<Resource<List<SchoolsHospitals>>>() {
#Override
public void onChanged(Resource<List<SchoolsHospitals>> schoolsList) {
switch (schoolsList.status) {
case SUCCESS:
binding.setSchools(schoolsList.data);
}
}
});
}
This is a rather odd behaviour considering how I wanted to re-use code. I was using the same viewModel class because the data is the same. After creating a separate viewModel class for Schools i.e a duplicate ViewModel just different class names, the respective contents were set as needed.
If there is a better approach, it will be much appreciated.
I am still stuck with this issue, can anyone help. It seems that my problem is that I cant update the data list. I have tried every solution that I've searched for on google etc.. but half the time i'm not even sure that I'm doing the correct thing.
I've used the onResume() to call notifyDataSetChanged, it didn't work. I've tried putting a refresh method into the adapter which i then called in OnResume(). Again it didn't work. Some people suggest clearing the adpater (adapter.clear();) in onResume and then using the addAll() function to relist the data but nothing works.
There has to be a simple solution to this. I have literally been stuck on this for 2 days now. very frustrated.
Here's my Fragment code again...
enter code here
public class SavedAppFragment extends ListFragment {
private static final String TAG = "AppClicked"; //DEBUGGER
private ArrayList<App> mSavedApps;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Populate the ArrayList
mSavedApps = SavedAppData.get(getActivity()).getApps();
AppAdapter adapter = new AppAdapter(mSavedApps);
setListAdapter(adapter);
}
//LIST ITEM CLICKED: /*Control what happens when list item is clicked: I.E. Load up a quiz while putting an EXTRA key containg the package name of the App to be launhced should the user get the question correct */ #Override public void onListItemClick(ListView l, View v, int position,long id) { //Return the crime for the list item that was clicked App c = ((AppAdapter) getListAdapter()).getItem(position); Log.d(TAG, "was clicked");
//Start the Activity that will list the detail of the app
Intent i = new Intent(getActivity(), Quiz_Activity.class);
String name = c.getPackage();
i.putExtra("packagename", name);
startActivity(i);
}
private class AppAdapter extends ArrayAdapter {
private ArrayList<App> mSavedApps;
public AppAdapter(ArrayList<App> apps) {
super(getActivity(), 0, apps);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//If we weren't given a view, inflate one
if (null == convertView) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_app, null);
//((AppAdapter) getListAdapter()).notifyDataSetChanged();
}
((AppAdapter) getListAdapter()).notifyDataSetChanged();
//Configure the view for this crime
App c = getItem(position);
TextView nameTextView = (TextView) convertView.findViewById(R.id.app_name);
nameTextView.setText(c.getName());
// nameTextView.setText(applicationInfo.loadLabel(packageManager));
TextView packageTextView = (TextView) convertView.findViewById(R.id.app_package);
packageTextView.setText(c.getPackage());
CheckBox appCheckBox = (CheckBox) convertView.findViewById(R.id.app_checked);
appCheckBox.setChecked(c.isChecked());
//Return the view object to the ListView
return convertView;
}
}
}
THANKS!!!
When you return to Activity B, the previous Activity B hasn't been destroyed. Thus, it skips the onCreate. Move all of the stuff you want to make sure happens every time into the onResume. I think you want to make your Adapter a class variable (I'll call it mAdapter) in onCreate, and add code that will get data from the list directly. If you need to do something, put a "refresh" function in the adapter. I'm assuming you have a custom Adapter, because I've never heard of AppAdapter. If you don't, then extend AppAdapter and add that functionality. Thus, your onCreate should look like this:
mAdapter = new AppAdapter(mSavedApps);
setListAdapter(mAdapter);
Your onRefresh could update the data contained in the adapter by some new update function, like so:
mAdapter.update(SavedAppData.get(getActivity()).getApps());
I have a layout with a ListView and ImageView. Initially, ImageView is invisible. I have a list, when an Item is clicked, it shows the Image of that item by setting ImageView and making it visible and listView is invisible, so far everything is ok. From there, onBackPressed() I want to see my listview again, I override onBackPressed(), to make my image view invisible and listview visible. However, when I select an item and see the image of it then press back, a blank activity comes, not my listView. I don't want to call the activity again, what should I do? What is wrong about listView? I tried to call invalidate() and invalidateViews(), setting adapter again, but they aren't woring.
Actually I'm filing adapter in the onResume of the activity, here is the code:
public class MyViewActivity extends Activity{
ListView imageList;
CustomImageListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_list_view);
//initialization of image array list etc
}
#Override
public void onResume(){
super.onResume();
imageList = (ListView) findViewById(R.id.listView);
adapter = new CustomImageListAdapter(this,R.layout.image_item, imageNames);
imageList.setAdapter(adapter);
imageList.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> adapter, View view, int i,
long l) {
// TODO Auto-generated method stub
if(imageNames.get(i) != null) {
onImageSelected(i);
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.image_list_view, menu);
return true;
}
public void onImageSelected(int position) {
...
}
#Override
public void onBackPressed() {
if (img.getVisibility() == ImageView.VISIBLE){
// img.setVisibility(ImageView.INVISIBLE);
// imageList.invalidateViews();
// imageList.setVisibility(ListView.VISIBLE);
// Here actually I want to use the upper part that I commented, but it didn't work, I have to call the same activity again to see my listview
Intent i = new Intent(MyViewActivity.this, MyViewActivity.class);
startActivity(i);
finish();
}
else {
....
}
return;
}
private class CustomImageListAdapter extends ArrayAdapter<String>{
...
}
As long as I can guess, the problem is caused by
img.setVisibility(ImageView.INVISIBLE);
You can try to use View.GONE instead.
The difference is clearly stated in android api's doc and I quoted:
/**
* This view is invisible, but it still takes up space for layout purposes.
*/
public static final int INVISIBLE = 0x00000004;
/**
* This view is invisible, and it doesn't take any space for layout
*/
public static final int GONE = 0x00000008;
By the way, I will recommend to use fragments to do your job. Specifically, a fragment A to present the listview, and when an item is clicked, switch to fragment B which contains the content. When Back is pressed, just let the backstack do its job.
Intent i = new Intent(MyViewActivity.this, MyViewActivity.class);
i.putExtra("currentObjectID",objectID);
startActivity(i);
finish();
Why are you traversing within the same activity? You should understand the use of intents ,If you want to stay within the same activity , Just set a flag for currentObjectID instead of put Extra..
I have a fragment which consists of a spinner and a button. You select one of four options with the spinner and then the button will take you to the next activity.
In order to implement the spinner I need to implement onItemSelectedListener on the Fragment but to use the button I need to implement onClickListener.
But I can't do both???
I would have expected this to be a really simple thing and the need to have multiple different Event listeners on a View must be common, so how do you implement this?
Here is the code that I am using:-
public class FragmentTypeSelect extends Fragment
implements OnItemSelectedListener
{
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState){
// set the view so that it can be referenced
View theView = inflater.inflate(R.layout.fragment_type_select,
container,false);
// set OnClickListener for the button
setUpClickListener(theView,R.id.but_select);
//===============================
// NEW TYPE SPINNER
//===============================
Spinner spinner = (Spinner) theView.findViewById(R.id.new_type_spinner);
spinner.setOnItemSelectedListener((OnItemSelectedListener) this);
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(),
R.array.types_array, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
return theView;
}
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id)
{
TextView headingText = (TextView)getView().findViewById(R.id.new_diet_type_text_heading);
TextView detailText = (TextView)getView().findViewById(R.id.new_diet_type_text_detail);
if (pos == 0)
{
headingText.setText(R.string.heading_type_1);
detailText.setText(R.string.detail_type_1);
}
if (pos == 1)
{
headingText.setText(R.string.heading_type_2);
detailText.setText(R.string.detail_type_2);
}
if (pos == 2)
{
headingText.setText(R.string.heading_type_3);
detailText.setText(R.string.detail_type_3);
}
if (pos == 3)
{
headingText.setText(R.string.heading_type_4);
detailText.setText(R.string.detail_type_4);
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
public void onClick(View view){
Toast.makeText(getActivity(), "Clicked", Toast.LENGTH_LONG).show();
}
private void setUpClickListener(View theView, int childViewID) {
View childView = theView.findViewById(childViewID);
childView.setOnClickListener((OnClickListener) this);
}
}
Originally I just had the spinner in and got this working fine. I then tried to put in the button function with the set OnClickListener in the onCreateView and adding the additional onClick and setUpClickListener methods.
This is exactly how I have done it elsewhere but in other cases I have not had other events to handle and have made the class implement the onClickListener. Java does not support multiple interface implements (as I understand it) and hence my question.
Hope you can help. I'm probably being a bit thick but I am still quite new to the whole OO as well as Android.
You can do:
public class FragmentTypeSelect extends Fragment
implements OnItemSelectedListener, OnClickListener {
public class Home extends AppCompatActivity implements ImageAdapter.OnItemClickListener ,Filterable {
then click on the red bulb and implement the method.
the implementation for nore than one interface can be done by seperating the interfaces with a comma.
I am trying to convert my entire project from using ActivityGroups to using Fragments.
Here is my old code :
SettingsActivityGroup
public class SettingsActivityGroup extends ActivityGroup
{
// Keep this in a static variable to make it accessible for all the nested activities, lets them manipulate the view
public static SettingsActivityGroup group;
// Need to keep track of the history if you want the back-button to work properly, don't use this if your activities requires a lot of memory.
private ArrayList<View> history;
// Window focus changed listener
public OnActivityGroupViewChanged activityGroupViewChangedListener = null;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Allocate history
this.history = new ArrayList<View>();
// Set group
group = this;
// Start root (first) activity
Intent myIntent = new Intent(this, SettingsActivity.class); // Change to the first activity of your ActivityGroup
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
ReplaceView("SettingsActivity", myIntent);
}
SettingsActivity
public class SettingsActivity extends Activity
{
String[] settingsLabels = {"Viderestilling", "Voicemail", "Vis nummer",
"Kø styring", "Optag samtaler", "Services" };
ListView lv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings);
lv = (ListView) findViewById(R.id.SettingsLV);
lv.setTextFilterEnabled(true);
populateListView();
}
private void populateListView()
{
lv.setAdapter(new ArrayAdapter<String>(this, R.layout.settings_items, R.id.settings_item_label, settingsLabels));
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id)
{
// SwitchActivity(position);
}
});
}
If I want to extend ListFragment instead of Activity - What do I need to change to make sure that everything still works ?
Have you looked at the Developer Guide article on Fragments? I think it very nearly describes your exact use case (an array-backed list in one fragment and the detail in another). And do check out the complete sample implementation in APIDemos. There's even a backward-compatible version in API 4+ Support Demos.