Here is my scenario: In my application i have a Main activity, two fragments and a service that runs in background. I attach the fragments to my main activity using this piece of code:
Fragment f1;
f1=new loginfragment();
FragmentTransaction ft=getFragmentManager().beginTransaction();
ft.add(R.id.frame,f1);
ft.commit();
Which is working fine. one of these fragments contains a listview which is attached to an adapter.(i have verified that adapter is correctly attached to the listview and entries can be added to listview without any problems.
In order to be able to inflate a layout inside the listview adapter(which extends BaseAdapter) i created a constructor to feed Context to it.
background service checks a page periodically and sends the results to one of these fragments using an interface that the fragment implements(sending broadcasts didn't work for me).interface is defined like this:
interface resultInterface{
void receive(String s,Context con);
}
fragment implements the interface like this:
#Override
public void receive(String s,Context con){
String elements[]=s.split("<br>");
if(elements.length>1) {
if(elements[0].equals("REQUEST")) {
init_notification("REQUEST",detect(elements[1],elements[2]));// a function that shows a notification
item i = new item(elements[1], elements[2]);
orders.add(i);
adapter = new listview_adapter(orders,c);
list.setAdapter(adapter);}
}
}
orders is an Arraylist and c is the context that is being passed to the listview adapter. service calls this interface method like this:
resultInterface resultinterface=new servefragment();
resulstinterface.receive(s,this);
upon receiving data (which results in calling the interface method) the fragment method is supposed to split the data and add entries to the listview.(i have verified that data is being correctly passed to the interface method.
BUT, the view that is being shown as listview entries is not correct( look corrupted somehow). Here is how it is supposed to look(using dummy data):Like this but here is how they are actually added(1 item is received from server which is correct but the layout is not): Like this
If you need more information just comment and i'll add them
My guess is that the Context object your service is passing to you has a different theme than you're expecting. This can cause text colors, button colors, etc to all change.
In order to be able to inflate a layout inside the listview adapter(which extends BaseAdapter) i created a constructor to feed Context to it.
Unless you need the Context instance somewhere other than inside getView(), you don't have to pass a Context via a constructor. Here's the full signature of the getView() method:
public View getView(int position, View convertView, ViewGroup parent)
The parent argument is guaranteed to be non-null, and all View instances have a getContext() method, so you can always retrieve a Context by writing parent.getContext(). Additionally, this will be your Activity (as opposed to something like your Application), which has the added benefit of having the correct theme.
So delete all of the code that passes the Context into your adapter and just use parent.getContext() instead, and I bet the problem goes away.
Related
I've got an Application with a MainActivity with a Navigation Drawer MenĂ¹.
Inside the MainActivity View I've got a Frame layout which takes the whole space.
When the user select something from the menĂ¹ I call a method which handle the fragments transaction inside the Frame Layout.
My MainActivity is the Fragment manager and from here i can handle all the changes I want and i can handle the communications between the fragments.
Here's the problem:
In one of my Fragment i'd like to show 2 new fragments, one with a PieChart and one with the data.
I could have done only one Fragment with all inside its view but i'd like to use a modular managing way.
So, first of all i created 1 fragment, the Container one (we can call it A).
In its view i put the fragment B and fragment C, directly from Xml.
In fragment B i've got the PieChart, HERE i call the methods to download data from a database, and then i put this data inside the chart.
I wrote a simple Interface which contains a method which is called when the user interact wich the chart; it build an object whith the selected data.
My target is to send this data to Fragment A and then pass them to Fragment C, so that the user can see what is he selecting.
In Fragment A i've Implemented the Fragment B inteface, then i set up this code inside OnAttach of B:
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
Interface = (InterfaceB) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement InterfaceB");
}
}
Everithing seems to works, but in the moment tha Fragment A is created, OnAttach of B is called, and the context which arrives refers to MainActivity and not to Fragment A.
This causes a Crash.
Fragment is not an instance of Context, so it is impossible to pass it to onAttach(Context Context) anyway.
There are two ways how you can do what you want.
1) Use onAttachFragment(Fragment fragment) inside fragment A, and catch events when fragments B and C are attached;
2) Use getParentFragment() inside fragments B and C, to access A.
I have an application which has a main activity and several fragments which are navigated to via a navigation drawer.
I use two map fragments in my app, this seems to cause an issue if i go from fragment map A and then back to fragment map B . In frgamnet b i lose control of them map is generally just shows a snapshot of where fragmnet map A last was.
this seem to be a known issue see.
google maps api bug report with issue
My solution as sugested on abouve fourm is to minimive map A before loading map B this causes the issue not to happen as it will not take up the screen space.
public void hideStupidMaps() {
mMapView.getLayoutParams().height = 1;
mMapView.getLayoutParams().width = 1;
mMapView.invalidate();
mMapView.requestLayout();
}
The above method is in my Gmap fragment class. i want to call it from myMain Activity class. in the navagation drawer code. My question is how do i call a frgments method from the main activity. especally when altering that fragment view. i need to inflate the view and it to the above method?
You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle.
To return a layout from onCreateView(), you can inflate it from a layout resource defined in XML. To help you do so, onCreateView() provides a LayoutInflater object.
public static class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
Here's how you can replace one fragment with another, and preserve the previous state in the back stack:
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
I have an adapter class and calling startActivityForResult() and getting the result in my Activity where I am using the adapter.
I want to change the image view background on getting the result.And the change should effect only the particular position of the RecyclerView.
startActivityForResult() inside the adapter class:
pass the context to your adapter class and do this:
((Activity)context).startActivityForResult(...);
As far as updating the RecyclerView, you can get the position inside the onBindViewHolder() and just update the class object from the List or ArrayListfor the image and call notifyDataSetChanged() after that.
P.S. this is the best I can do to explain to you without any code.
Edit : to get the TextView from the adapter class inside the Activity class:
View viewItem = recycleView.getLayoutManager().findViewByPosition(position);
TextView textView = viewItem.findViewById(R.id.textView);
textView.setTextColor(getResources().getColor(R.color.yourColor));
So currently I have a application with different activities, and I use buttons to navigate between activities. I later decided that I should add the navigation drawer and use fragments instead. So one of my fragments has a bunch of fields that the user fills out that I need to pass onto the next fragment. So my question is, Do I keep all the work in activities and call the activity from the fragment? Or do I just include all he java in my activity in the java for the fragment? For the most part I am taking the fields from the first fragment, and I'd like to pass the values to the next fragment so it can handle some calculations.
final EditText FinalPriceText = (EditText) v.findViewById(R.id.editTextPrice);
final EditText TradeInPriceText = (EditText) v.findViewById(R.id.editTextTrade);
i.putExtra("FinalAutoPrice", FinalAutoPriceText.getText().toString());
i.putExtra("TradeInPrice", TradeInPriceText.getText().toString());
startActivity(i);
As far as calculations go, if you are going to use them a lot and they have nothing to do with the activity or android lifecycle I would separate them out into a different class and then you can call them from anywhere.
If they do rely on the activity you could still separate them out but pass a reference to the activity when doing your calculations. You can get the parent activity by calling this.getActivity() from any fragment
You can cast this.getActivity() to whatever the parent activity is and you can call the methods from that object as well. This works fine but your fragment will only work with the activity you specify and it can get sloppy if you are not careful.
Otherwise put them in the fragment where you need them. I would consider this least recommended if you need to use calculations anywhere else in the app. Duplicate code is just asking for bugs in the future.
As far as passing data, create a static instance method in fragment2 and pass it what you need there.
For example
public Fragment2 extends Fragment {
public static fragment2 newInstance(MyData myDataIPass) {
Fragment2 fragment = new Fragment2();
Bundle args = new Bundle();
args.putInt("someInt", myDataIPass.someInt);
fragment.setArguments(args);
return fragment;
}
}
Call this new instance method when creating your fragment transaction like this
FragmentManager fm = getActivity().getFragmentManager();
fm.beginTransaction()
.replace(R.id.container, Fragment2.newInstance(MyData myDataIPass))
.commit();
Well, you have mainly two options here:
use Intent.putExtra() with fragments. Just like Activities, you
can use this method with Fragments as well. See the following links
for the implementation in Fragments
this
this
The other option is to use SharedPreferences and store data as key value pairs from one fragment, and can be accessed from any other activity/fragments. See this nice tutorial to understand better!
You have a special callback in Fragment to get Activity.
It is called:
#Override
public void onAttach(Context context) {
super.onAttach(context);
YourActivity activity = (YourActivity) context;
}
I have a listview NoteList which contains a method doListRefresh() to select list contents from the sqlite note table, populates a cursor (which populates my array adapter), then calls adapter.notifyDataSetChanged(); to refresh the list. Upon (add, edit, deletes etc)
Inside my custom Array adapter i populate several elements on each row including a delete button. Inside the array adapter i have the delete button onClick handler etc. I need to call NoteList.doListRefresh() from within my Array adapter and i do this by using a setter inside my array adapter which is called from NoteList something like adapter.setNoteListObj(this);. This is working but i'm not sure its the best way?
I wanted to ask if this is "best practice" for doing something like this?
Thank you for any advice
Here is some of the sample code:
Within NoteList:
onCreate(Bundle savedInstanceState) {
thisObject = this;
}
// set custom ArrayAdapter to the data
adapter = new NoteArrayAdapter(activity, R.layout.channel_note_list_item, noteList);
adapter.setNoteList(thisObject);
...
within Adapter:
private NoteList callingNoteListObj;
...
// setter
protected void setNoteList(NoteList _callingNoteListObj) {
this.callingNoteListObj = _callingNoteListObj;
}
...
// within delete onclick handler (after delete)
// refresh local database
callingNoteListObj.doListRefresh();
I don't see why not. All you are doing is passing a reference to the instance (a "pointer" for those who have done more than Java). Personally, I'd pass this into the constructor for your adapter and store the reference locally. In fact, you probably already do if you pass in this as a Context object in order to construct an ArrayAdapter. Since its your custom adapter for your custom NoteList, you could very well just cast context (or this.getContext()) to NoteList and call it without needing to use a setter.