Using Google Maps v2 in subclass activity with navigation drawer - android

I need to work back to API level 8. I have multiple activities and am using a navigation drawer to move between them as well as an action bar (with AppCompat v7). I have created a base abstract class that has all the navigation drawer setup and handling and that descends from ActionBarActivity.
File BaseNavActivity.java
abstract class BaseNavActivity extends ActionBarActivity {
}
All my activities subclass BaseNavActivity, and they all work fine.
public class MainActivity extends BaseNavActivity {
}
Before I added the navigation drawer feature I had a map working fine when descending from FragmentActivity. However, I cannot do that anymore because I need to descend from my BaseNavActivity. Even though the docs say ActionBarActivity descends from FragmentActivity I get an error when trying to use this XML.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background" >
<!-- The main content view -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background"
android:orientation="vertical"
>
<include layout="#layout/common_toolbar" />
<fragment
android:id="#+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="3dip"
/>
<include layout="#layout/common_footer" />
</LinearLayout>
<!-- The navigation drawer -->
<include layout="#layout/nav_menu" />
</android.support.v4.widget.DrawerLayout>
I get an InflateException: Binary XML file line #19: Error inflating class fragment.
I have tried other solutions such as having a separate XML file with just the and opening it as a fragment and adding it to the above in place of the . That approach always returned a null when I tried to point to the map (smf was always null):
SupportMapFragment smf = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
I also tried to have a
public class MapFragment extends FragmentActivity {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View myFragmentView = inflater.inflate(R.layout.location_map, container, false);
return myFragmentView;
}
}
but I couldn't add the fragment using
MapFragment mapFragment = new MapFragment();
fragmentTransaction.add(R.id.map_container, mapFragment);
fragmentTransaction.commit();
The add() function needed to have parameters of (int, Fragment).
Any help will be appreciated. If you need more code I can add it but didn't want to make this post too long. I have spent a couple of days searching and trying various approaches and nothing seems to get everything working together.
Basically I would like to know how to have a <fragment> inside the XML when descending from a custom subclass that descends from ActionBarActivity. My 2nd choice would be to know how to add a fragment that holds the map and works with the support libraries.
Thanks!

I finally found my issue. I took a different approach for searching and found this gem: Android Google Maps V2 Caused by: java.lang.ClassCastException: com.google.android.gms.maps.SupportMapFragment cannot be cast to android.app.Fragment
Basically my issue was that I had the custom base class call setContentView before calling the super.onCreate. That meant that fragments weren't understood because it was a couple of supers up that knew about them. This caught me because 1) I needed to specify a theme that appcompat could use and had my setContentView next to it when I copied things to the base class, and 2) everything else worked up to this point so I didn't realize it was incorrect.
So the fix is in my base class that all my activities inherit from (abbreviated):
abstract class BaseNavActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState, int resLayout) {
// need to set the theme first
setTheme(R.style.AppTheme2);
// then call super before setting the content view
super.onCreate(savedInstanceState);
setContentView(resLayout);
}
}

Related

findViewById Attribute in Fragment from the activity xml Not work [duplicate]

This question already has answers here:
findViewById in Fragment
(37 answers)
Closed 2 years ago.
How to access an attribute in the activity xml?
I want to use it in fragment.
for example : this is my activity xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:fab="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
fab:layout_constraintTop_toTopOf="parent"
fab:layout_constraintLeft_toLeftOf="parent"
fab:layout_constraintRight_toRightOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/layTitle"
android:layoutDirection="rtl"
android:background="#color/colorPrimary"
android:padding="#dimen/paddingTitle"
android:elevation="#dimen/elevationActivityTitle"
android:layout_alignParentTop="true">
<ImageView
fab:layout_constraintLeft_toLeftOf="parent"
fab:layout_constraintTop_toTopOf="parent"
fab:layout_constraintBottom_toBottomOf="parent"
android:layout_width="#dimen/imgActivityTitle"
android:layout_height="#dimen/imgActivityTitle"
android:id="#+id/btn_back"
android:src="#drawable/ic_back"
android:elevation="5dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<FrameLayout
android:id="#+id/frag"
android:layout_width="0dp"
android:layout_height="0dp"
fab:layout_constraintBottom_toBottomOf="parent"
fab:layout_constraintTop_toBottomOf="#+id/layTitle"
fab:layout_constraintLeft_toLeftOf="parent"
fab:layout_constraintRight_toRightOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
I want findViewByid ImageView in fragment
When I was searching for solution I got the following one:
TextView btn_back= (TextView) getView().findViewById(R.id.btn_back)
But, unfortunately it was not working for me.
You can use the interface to do it :
Create an interface names IBtnClick with one void method: "void onBtnClicked();"
use interface in activity like this:
IBtnClick iBtnClick= (IBtnClick)getActivity();
here getAtivity is our context, if it doesn't work use another scope context.
and use your method in button click listener like this
iBtnClick.onBtnClicked();
Now in your fragment you have to implements interface and
you can add any action you want in Overrided method.
Use either viewModel or interfaces to talk between activity and fragment. don't try to send the button to fragment but trigger it from there. That will prevent any leaks or null pointers.
Ok. You have some options.
Firstly, you can access these variables to directly in fragment like that.
MainActivity.java
TextView backButton;
backButton = findViewById(R.id.btn_back);
Fragment.java
((MainActivity) getActivity()).backButton
You can get current activity with getActivity() but Java compiler cannot understand which activity so have to cast to MainActivity.
Secondly, you can pass your activity instance to fragment. You can use constructors and newInstance() function. You can read that post Best practice for instantiating a new Android Fragment
In my opinion, I prefer second option because you guarantee these variables that include activity class. Some devices occur errors at first option. But second option uses more ram because you are passing your variables to another class.
The choice is yours
Try This code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.recharge_plane_fragment, container, false);
alertdialog_Listview=view.findViewById(R.id.alertdialog_Listview);
return view;
}
You can declare your TextView btn_back as static in activity
public static TextView btn_back;
btn_back = (TextView) findViewById(R.id.btn_back);
and get it in fragment
TextView btn_back = ((MainActivity)getActivity()).btn_back;

What's the correct way to use Fragments?

What is the correct way to use fragments? Should i use only one FragmentActivity per interface or use a unique FragmentActivity for all interfaces?
My app is quite simple: it has 4 distinct interfaces, a fixed options menu on top and i only show contextual menu in a interface called 'actions'.
I was thinking to use only one FragmentActivity with an area where i could switch between fragments. Is it a good practice or should i keep one FragmentActivity per interface?
By now, i'm using one FragmentActivity per interface but when i change ( start ) FragmentActivity, it looks like that is creating a new object and my app blinks before open the new activity.
Thank in advance.
edit:
Here is a drawing of my app: http://postimg.org/image/mvxyk2527/
It's a lot of personal preference and requirement really. I'm not a big believer of the "correct way" concept, if you achieve your goal then it's not wrong, but there may be a nicer way to do it.
For me it would depend on how many nested fragments each FragmentActivity handles. If you have a tree of nested fragments you can get into a mess with nested fragment stacks, etc.
http://developer.android.com/training/implementing-navigation/temporal.html
Personally, if I'm writing an application with lots of fragments I tend to have a single Activity which makes navigation a bit more manageable with a single Fragment stack as using multiple FragmentActivity instances will use multiple fragment stacks.
http://developer.android.com/training/implementing-navigation/index.html
You could consider the ViewPager approach which is great if you want to use a tabular and swiping navigation. Although if you have heavy scrollable content views I would be hesitant as for some individuals multi-directional gesture interfaces can be quite frustrating.
http://developer.android.com/training/implementing-navigation/lateral.html
If your code is clean, manageable and not leaking references then I would probably stick with what you have and wouldn't waste your time re-factoring it.
I will try to explain it properly. In your case, you must use one FragmentActivity that includes fragments. You must create one fragment per interface and commit (exchange) when the user clicks on the menu. This may be an example of the structure of the project:
Java Classes:
MainActivity.class (extends FragmentActivity)
Interface1Fragment.class (extends Fragment)
Interface2Fragment.class (extends Fragment)
Interface3Fragment.class (extends Fragment)
Interface4Fragment.class (extends Fragment)
Layouts:
act_main.xml, frg_inter1, frg_inter2, frg_inter3 and frg_inter4.
In MainActivity and act_main.xml, you must create a tabhost o navigationDrawer for the menu and implement a method that allows to switch between fragments. Later, in each fragment you must implement the interface functionality.
Some code:
MainActivity:
public class ActMain extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_main);
}
private void createMenu() {
//you can create a menu with tabhost or navigation drawer
}
// replace a fragment
public void replaceFragment(Fragment launchFragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(android.R.id.tabcontent, launchFragment).commit();
}
}
A Fragment:
public class Interface1Fragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.frg_inicio, container, false);
return rootView;
}
}
MainActivity.xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:facebook="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Main content -->
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0" />
<!-- Left Navigation Drawer -->
<LinearLayout
android:id="#+id/left_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/black_actionbar"
android:choiceMode="singleChoice"
android:onClick="emptyOnClick"
android:orientation="vertical" >
/LinearLayout>
</android.support.v4.widget.DrawerLayout>
In fragments xml files you must design your interfaces.
Yeah, you should just change fragments, not restart the fragment activity if that part is gonna stay the same and work the same.
You should just switch between fragments like this:
getFragmentManager().beginTransaction().replace(R.id.container, new MyFragment()).addToBackStack(null).commit();
or like this if you are supporting API < 14
getSupportFragmentManager().beginTransaction().replace(R.id.container, new MyFragment()).addToBackStack(null).commit();
Note : remove addToBackStack(null) if you dont want to go back to previously loaded fragment onBackPressed

implement mapview version 1 inside fragment?

Is there a way to implement mapview version 1 inside fragment?
I tried sth like:
MainActivity:
public class MainActivity extends FragmentActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
Then, I want 2 fragments . One that has the mapview and second which will have a textview in which the location will be shown.
I can't implement the first fragment.I can't figure how to implement the map.I mean , for the mapview to work it needs "extends MapActivity" but I need "extends fragment".
Also , in main.xml how to do it?I tried :
<fragment
class="com.google.android.maps.MapView"
android:name="com.example.....MapClass" //is this right?but it is necessary for fragment?
android:id="#+id/fragment1"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent"
android:apiKey="mykey" />
<fragment
class="com.example...getloclass"
android:id="#+id/fragment2"
android:layout_weight="1"
android:layout_width="0px"
android:layout_height="match_parent" />
From here https://developers.google.com/maps/documentation/android/v1/hello-mapview, you can see that
Version 1 of the Google Maps Android API as been officially deprecated
as of December 3rd, 2012
So you shouldn't use MapView anymore. I suggest you use a MapFragment instead. See the excellent documentation for it here: https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/MapFragment

Using FragmentActivity throws InflateException

Common Fragment to be used in 2 Activity's
public class Ads extends Fragment {
private View rootView ;
private MoPubView adView ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.ads, container, true) ;
adView = (MoPubView) rootView.findViewById(R.id.adView) ;
adView.setAdUnitId(LogoQuizUtil.MOPUB_AD_UNIT);
adView.loadAd();
return rootView;
}
}
Fragment layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ad_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="bottom" >
<com.mopub.mobileads.MoPubView
android:id="#+id/adView"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:gravity="bottom" />
</LinearLayout>
Other Layout where I include this fragment
<fragment
android:id="#+id/ads"
android:name="myPackage.Ads"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="bottom" />
I get a dont get a exception when I call setContentView (R.layout.ads) the first time, when the second activity calls the fragementactivity (Ads) I get a exception at setContentView (R.id.ads).
Exception I get is
08-07 09:38:30.359: W/System.err(975): java.lang.RuntimeException: Unable to start activity ComponentInfo{mypackage/mypackage.SecondActivity}: android.view.InflateException: Binary XML file line #263: Error inflating class fragment
Lets start at the beginning. An activity is not a fragment and a fragment is not an activity.
You need an activity to contain/control fragments. To do that you extend Activity (for Honeycomb+ development) or use the support library and extend FragmentActivity. In this class you would use setContentView to set the layout that will contain the fragment(s).
You then, from that class, call the fragment manager (getFragmentManager or getSupportFragmentManager depending on which class you have extended). The fragment manager is then used to create, attach and detach the fragments.
The fragment, not being an activity, is coded differently. It should have an onCreateView method that inflates the layout for the fragment and returns it to the fragment manager from the activity.
Then it is typical to use onActivityCreated for the rest of your code (or whatever else is needed).
Making the changes to use fragments properly may or may not solve all of your problems, as I see you are using some kind of custom widget in your layout and the issue could be there too.

Two fragments hold by another fragment - findViewById returns null

I need help for my first Android application. I have a single activity with an Action Bar at the top and Navigation Tabs. Because of these navigation tabs I had to convert my Activities into Fragments.
So one of those Activities (which is now a Fragment) held two fragments, one ListFragment on the Left and a DetailFragment on the right, so that the user is able to select an item from the list and directly sees details on the right.
But now as the Activity has been transformed into the Fragment, it's the Fragment that holds the List- and the DetailFragment. This works fine until I want to change the DetailsFragment.
First of all, here is the code of the Fragment holding the other two:
public class BlackboardFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
return inflater.inflate(R.layout.fragment_layout, container, false);
}
}
Here is the fragment_layout.xml file (saved in layout-land):
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<fragment
android:id="#+id/interfaces"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_marginRight="20dp"
android:layout_weight="0.60"
class="org.fawkesrobotics.app.InterfaceFragment" />
<FrameLayout
android:id="#+id/viewer"
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
So, the ListFragment is named InterfaceFragment, here is the code:
public class InterfaceFragment extends ListFragment {
boolean mDualPane;
// some other code
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
create_list();
View viewerFrame = getActivity().findViewById(R.id.viewer);
mDualPane = viewerFrame != null
&& viewerFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
}
// some other code
}
This is, where it doesn't work. The Fragment actually shows the list (that is created in create_list() where the ListAdapter and everything else is set), but my problem is, that viewerFrame is null. I declared the id viewer in the xml file above, so I don't understand why he cannot find the id. Does it "belong" to the BlackBoardFragment or to my overall activity? Because in BlackboardFragment I also tried it with getActivity().findViewById and it worked. Why is InterfaceFragment not able to find it?
I also tested, if he really uses the fragment_layout.xml in layout-land and he does. So he should know the id viewer, but obviously doesn't.
If you need more code or the code from the DetailsFragment, I can post it.
Thank you in advance for your help! :)
use FragmentManager to get Fragment......
ExampleFragment fragment = (ExampleFragment) getActivity().getFragmentManager().findFragmentById(R.id.example_fragment);
Nested Fragments are not supported by the Android SDK. That is, you can't have a "fragment within a fragment" in your Android application. Sorry.
EDIT:
Nested Fragments are now part of the official Android 4.2 SDK! Yay!

Categories

Resources