I just ran into this issue where I'm trying to test if a fragment is displayed, but for some reason I can't test based on the fragment's root ID. Here's the code:
MainActivity.java:
package com.gregspitz.simplefragmenttesttest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.gregspitz.simplefragmenttesttest.MainActivity">
<fragment
android:id="#+id/main_fragment_holder"
android:name="com.gregspitz.simplefragmenttesttest.BasicFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
BasicFragment.java:
package com.gregspitz.simplefragmenttesttest;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class BasicFragment extends Fragment {
public BasicFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_basic, container, false);
}
}
fragment_basic.xml:
<LinearLayout 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"
android:orientation="vertical"
android:id="#+id/basic_fragment"
tools:context="com.gregspitz.simplefragmenttesttest.BasicFragment">
<TextView
android:id="#+id/simple_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_blank_fragment"/>
</LinearLayout>
MainActivityTest.java:
package com.gregspitz.simplefragmenttesttest;
import android.support.test.rule.ActivityTestRule;
import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.*;
/**
* Created by gregs on 2/6/2018.
*/
public class MainActivityTest {
#Rule
public ActivityTestRule<MainActivity> mActivityTestRule =
new ActivityTestRule<MainActivity>(MainActivity.class);
#Test
public void mainActivity_basicFragmentIsDisplayedAtStart() {
onView(withId(R.id.basic_fragment)).check(matches(isDisplayed()));
}
#Test
public void mainActivity_basicFragmentInnerIdIsFound() {
onView(withId(R.id.simple_text)).check(matches(isDisplayed()));
}
}
The second test works where I'm looking for an ID within the layout, but the first test doesn't find the layout's root ID. I just don't understand why that doesn't work and what should I do instead? Thanks for the help.
When the fragment gets inflated on the view, the Android framework replaces the root ID of the fragment's layout to the ID of the fragment itself.
The LinearLayout will have the ID changed to the ID of the fragment.
#Test
public void mainActivity_basicFragmentIsDisplayedAtStart() {
onView(withId(R.id.main_fragment_holder)).check(matches(isDisplayed()));
}
Related
I have a TabLayout on a activity and when user clicks on any tab then a fragment is loaded. One of those fragments contains a NavigationView running inside a DrawerLayout. Now the problem is I have to implement MVVM for the whole app and so for the fragments too, I have done this for Activities but I am having trouble while implementing this for Fragments and how to deal with ItemSelected with MVVM and what to bind and how? I am unable to find a proper working sample of the same. Here's the code:
MoreFragment.java:
package com.abc.Fragments;
import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.abc.MainActivity;
import com.abc.MoreFragmentViewModel;
import com.abc.R;
public class MoreFragment extends Fragment {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ViewModel viewModel;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(MoreFragmentViewModel.class);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragView = inflater.inflate(R.layout.fragment_more, container, false);
return fragView;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mDrawerLayout = getView().findViewById(R.id.drawer_layout);
mDrawerLayout.openDrawer(Gravity.END);
}
}
fragment_more.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="#color/grey"
app:navigationItemSelectedListener="#{()-> viewModel.onMyItemSelected()}"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
MoreFragmentViewModel.java:
package com.abc;
import android.arch.lifecycle.ViewModel;
import android.databinding.BaseObservable;
public class MoreFragmentViewModel extends ViewModel {
public void onMyItemSelected(){
System.out.print("Item Clicked");
}
}
Please do any possible help.
Use:
DataBindingUtil.inflate(inflater, layoutId(), container, false)
To inflate your layout.
And don't forget to add:
<data>
<variable
name="model"
type="MoreFragmentViewModel"/>
</data>
To your fragment layout.
I have already looked at the other answers but none of them help me.
I made sure to use import android.support.v4.app.Fragment; so that's not the problem.
MainActivity.java
package com.example.nirvan.fragmentsexample2;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myFragment myfragment=new myFragment();
FragmentTransaction fragmentTransaction=getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.fragmentContainer,myfragment);
fragmentTransaction.commit();
}
}
Error :
Error:(20, 28) error: no suitable method found for add(int,myFragment)
method FragmentTransaction.add(Fragment,String) is not applicable
(argument mismatch; int cannot be converted to Fragment)
method FragmentTransaction.add(int,Fragment) is not applicable
(argument mismatch; myFragment cannot be converted to Fragment)
Why am I getting this?
In activity_main.xml I have a FrameLayout
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff0000"
android:id="#+id/fragmentContainer">
</FrameLayout>
myFragment.java
package com.example.nirvan.fragmentsexample2;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class myFragment extends Fragment
{
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState)
{
return inflater.inflate(R.layout.fragment,container,false);
}
public myFragment(){}
}
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:paddingLeft="145dp"
android:text="fragment One"/>
</RelativeLayout>
Sloppy mistake . You should call v4.app.Fragment instead of app.Fragment .
Open myFragment.java
Don't
import android.app.Fragment;
Do
import android.support.v4.app.Fragment;
Change this
import android.app.Fragment;
to
import android.support.v4.app.Fragment;
in myFragment class
Also i would suggest to have proper naming convention for your fragment.
No need for android:orientation="vertical" in relative layout.
Here is the class of fragment
package com.hfad.chapter7;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class WorkoutDetailFragment extends Fragment {
private long workoutID;
public WorkoutDetailFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_workout_detail, container, false);
}
public void setWorkoutID(long workoutID) {
this.workoutID = workoutID;
}
}
And the layout it's using is:
<FrameLayout 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"
tools:context="com.hfad.chapter7.WorkoutDetailFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_blank_fragment" />
</FrameLayout>
My MainActivity is:
package com.hfad.chapter7;
import android.app.Activity;
import android.app.Fragment;
import android.provider.UserDictionary;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WokoutDetailFragment workoutDetailFragment;
workoutDetailFragment = (WorkoutDetailFragment)this.getFragmentManager().findFragmentById(R.id.myFirstFragment);
}
}
And layout of MainActivity is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.hfad.chapter7.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
<fragment
class="com.hfad.chapter7.WorkoutDetailFragment"
android:id="#+id/myFirstFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
Problem is when I use this.getFragmentManager().findFragmentById(R.id.myFirstFragment) in onCreate of AppCompatActivity I get Fragment though I should get WorkoutDetailFragment as stated here in a similar example.
UPDATE:
Also I am unable to cast Fragment to WorkDetailFragment
#user4913383,
Change this line:
workoutDetailFragment = (WorkoutDetailFragment)this.getFragmentManager().findFragmentById(R.id.myFirstFragment);
to
workoutDetailFragment = (WorkoutDetailFragment)this.getSupportFragmentManager().findFragmentById(R.id.myFirstFragment);
What's the problem of getting a fragment? The getFragmentManager().findFragmentById() method returns a Fragment and you have to cast it. Since you are casting the Fragment to a WorkoutDetailFragment you should be able to do what you want with it.
I think it has to be <fragment android:name="com.hfad.chapter7.WorkoutDetailFragment"... instead of class.
=> http://developer.android.com/training/basics/fragments/creating.html#AddInLayout
pardon me if this is a stupid error. there are two fragments in my activity layout (xml) and in order to let them communicate i am trying to get the instance of one fragment inside my main activity. i have done it earlier but this time it throws erro (required videolisting fragment but found fragment) i am not sure what i have given wrong. might be just a silly mistake. can you please assist. Thanks in advance.
below is code snippet:
public class VideoListingActivity extends ActionBarActivity implements FilterFragment.OnFilterItemSelectedListener{
public VideoListFragment videoListFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_listing);
videoListFragment =(VideoListFragment) getSupportFragmentManager().findFragmentById(R.id.frg_video_listing_video_listing_fragment);
}
below is the layout:
<RelativeLayout 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"
tools:context="my activity context">
<fragment
android:layout_width="match_parent"
android:layout_height="#dimen/filter_fragment_height"
android:name="com.text1.text2.text3.pkg.FilterFragment"
android:id="#+id/frg_video_listing_filter_fragment"
></fragment>
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.text1.text2.text3.pkg.VideoListFragment"
android:id="#+id/frg_video_listing_video_listing_fragment"
></fragment>
</RelativeLayout>
Below is fragment class code
package com.rrdtech.vidyavaan.android.Fragments;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.rrdtech.vidyavaan.android.R;
public class VideoListFragment extends ListFragment {
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.video_list_fragment,container,false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
}
}
Below is stack trace
Error:(22, 91) error: inconvertible types
required: VideoListFragment
found: Fragment
Maybe you need to add the class attribute in XML.
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.text1.text2.text3.pkg.VideoListFragment"
class="com.text1.text2.text3.pkg.VideoListFragment"
android:id="#+id/frg_video_listing_video_listing_fragment"/>
You Need to know
You are using support library for Fragment using
getSupportFragmentManager(), In this case you should always use support package classes.
VideoListFragment extending android.app.ListFragment; instead of android.support.v4.app.ListFragment; (this thing causes the error). And make sure fragment layout has ListView with "#android:id/list" id.
I am hardly trying to create a simple application with a top menu and a changeable view below (by pressing the buttons in the menu fragment we change the view of the fragment below).
So, I have 2 fragments inside the main view but when trying to run the application in the emulator I get an error like:
Cause by android.app (bla bla bla, piece of crap Eclipse doesn't even allow copying the errors):
Trying to instantiate a class com.example.android.topmenu that is not a fragment
So, these are my XML layouts:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<fragment
android:id="#+id/menuFragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:name="com.example.android.topmenu" >
</fragment>
<fragment
android:id="#+id/contentFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:name="com.example.android.bottomcontent" >
</fragment>
</LinearLayout>
topmenu.xml
<?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" >
<Button
android:id="#+id/Button1"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>
bottom_content.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#+string/content_text" />
</LinearLayout>
and these are the classes for the main activity and the fragments
main_activity
package com.example.android;
import com.example.android.R;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
public class OLife extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
// The activity is being created
super.onCreate(savedInstanceState);
// Set view
setContentView(R.layout.main);
}
#Override
protected void onDestroy() {
super.onDestroy();
// The activity is about to be destroyed.
super.onDestroy();
// Stop method tracing that the activity started during onCreate()
android.os.Debug.stopMethodTracing();
}
}
topmenu
package com.example.android;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class OLifeMenu extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.topmenu, container, false);
return view;
}
}
bottomcontent
package com.example.android;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class OLifeMain extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_content, container, false);
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
}
You should be using FragmentActivity instead of Activity that is because you are using support Fragments and multiple Fragments in your activity main
Edit
You can now use the Appcompat support library and extends AppCompatActivity to support toolbar and fragment for lower api.
In my case it turned out, I was doing stuff in onCreate in the wrong order:
setContentView(R.layout.activity_qr_code_scan);
super.onCreate(savedInstanceState);
instead of
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qr_code_scan);
As you are using fragments in your layout and I suggest you to extend your class from fragment or fragment activity.