I'm attempting to make an ultimate TicTacToe game, which requires running 9 instances of the same fragment at the same time. I house them Inside another fragment that'll control each. While performing other tasks.
I am trying to figure out a way to manage each fragment, have them talk to each other, and know who they are. (basically store its row and col and maybe allow the big layout run some methods) Is there a way to do that? I don't have much experience with fragment managers, but I'm not swapping anything out and It would seem like a lot of work for such a simple task.
Big Fragment
<LinearLayout
android:id="#+id/ll_Big_Row_0"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:baselineAligned="false" >
<fragment
android:id="#+id/board_0x0"
android:name="com.example.tictactectoe.Fragment_Small_Board"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:layout_weight="1" />
<fragment
android:id="#+id/board_0x1"
android:name="com.example.tictactectoe.Fragment_Small_Board"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:layout_weight="1" />
....
<LinearLayout/>
....
<LinearLayout/>
smallFragment.java
public class Fragment_Small_Board extends Fragment {
private int thisRow = 0;
private int thisCol = 0;
private ImageButton square0x0;
private ImageButton square0x1;
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.small_board, container, false);
setUpButtons(view);
buttonOnclickListeners();
return view;
}
public void setUpButtons(View view){
square0x0 = (ImageButton) view.findViewById(R.id.small_0_0);
square0x1 = (ImageButton) view.findViewById(R.id.small_0_1);
....
}
public void buttonOnclickListeners(){
square0x0.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
validateMove();
square0x0.setBackgroundResource(backgroundID);
square0x0.setImageResource(pictureID);
}
});
....
}
Don't put 9 fragments inside parent fragment because in your case, it doesn't look necessary. So what you can do is add these nine fragments inside your activity.and provide each fragment with communicator(interface) so that they can communicate via activity to each other.
To add fragments do something like this
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fragment =new MyFragment();
ft.add(android.R.id.content,fragment,"myFragmentTag");
ft.commit();
and according to your functionalities keep on replacing fragments .
This link will give you brief idea about how to set up communicator inside fragment and extend it in your activity
Related
I have a ViewPager with 12 fragments. I need to get data from API and update the fragments when scrolling. How do I update the contents of fragment, with only one fragment updating for 12 pages?
My fragment layout fragment_item:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/surface">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/khaire"
android:gravity="center"
android:text="Overal Working Hour"
android:textColor="#color/colorPrimary"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:gravity="center"
android:padding="15dp"
android:text="January"
android:textColor="#color/white"
android:textSize="20sp"
android:textStyle="bold" />
My main activity code:
public class MainActivity extends AppCompatActivity {
private static final int num_pages = 12;
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPager = findViewById(R.id.pager);
mPagerAdapter = new ScreenAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
private class ScreenAdapter extends FragmentStatePagerAdapter {
public ScreenAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return new SliderFragment();
}
#Override
public int getCount() {
return num_pages;
}
}
My SlideFragment class:
public class SliderFragment extends Fragment {
Toolbar toolbar;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_item,container,false);
return rootView;
}
Now I want to have same fragment while scrolling the page but with diff texts how could I do that... And if possible use RecyclerView also.
You could create a new Class (UpdatingFragment) with public abstract updateView(); that extends Fragment.
Create your SliderFragment by extending UpdatingFragment instead of Fragment
In the SliderFragment in onCreateView() at the end call updateView().
Write an overwrite method in your SliderFragment for what you need to update (anything you want to show on the UI)
Adjust your screenAdapter to return and take UpdatingFragment’s instead of Fragments.
Now whenever your fragments onCreateView gets called all their UI data gets updated, and if you create a list of SliderFragments and pass that into your adapter instead of creating new ones, you can just run a for loop over that list and call updateView() for each fragment.
Hello i have fragment and inside it viewpager with 2 tabs i need when i press button in the parent fragment refresh the child fragment inside viewpage
i used this for refresh the same fragment and it's working fine
FragmentTransaction ft1 = getFragmentManager().beginTransaction();
ft1.detach(this).attach(this).commit();
i tried the same and instead of this i put the childfragment.newInstance() put still not refreshed so any suggestion ??
Create a interface in your child fragment.
RefreshInterface
create a method in child fragment to assign a object to RefreshInterface.
intialiseRefreshInterface(RefreshInterface refreshInterface)
call the interface method inside the refresh click.
implement the child fragment Interface in Parent fragment and override the method.
before commit() the child fragment from parent fragment
1. create a object to child object
2. call the intialiseRefreshInterface(RefreshInterface refreshInterface)
3. commit() the child fragment.
your child fragment will refresh [ child fragment will be popBackStack() and re-create.
Below example code will help you in achieve your requirement
Parent Fragment
parentFragment.java
public class OneFragment extends Fragment implements TwoFragment.RefreshInterface {
TwoFragment child;
Button launch;
FrameLayout containerLayout;
// child fragment interface object
TwoFragment.RefreshInterface refreshInterface;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
launch = view.findViewById(R.id.fragment_launch);
containerLayout = view.findViewById(R.id.fragment_container);
// RefreshInterface. this is mandatory
refreshInterface = this;
launch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
launchChildFragment();
}
});
return view;
}
#Override
public void refresh_fragment() {
// as we added the child fragment to backstack. we will remove the fragment from backstack and add again
if (getActivity().getSupportFragmentManager().getBackStackEntryCount() > 0){
getActivity().getSupportFragmentManager().popBackStack();
}
launchChildFragment();
}
private void launchChildFragment(){
// creating the object for child fragment
child = new TwoFragment();
// intialising the RefreshInterface object
child.intialiseRefreshInterface(refreshInterface);
// calling the child fragment
getActivity().getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, child).addToBackStack(null).commit();
}
}
fragment_parent.xml
<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="com.myapplication.OneFragment">
<Button
android:layout_centerHorizontal="true"
android:id="#+id/fragment_launch"
android:text="Launch child fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<FrameLayout
android:id="#+id/fragment_container"
android:layout_below="#id/fragment_launch"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
childFragment
public class TwoFragment extends Fragment {
Button refershBtn;
RefreshInterface refreshInterface;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_two, container, false);
refershBtn = view.findViewById(R.id.btn_refersh);
refershBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
refreshInterface.refresh_fragment();
}
});
return view;
}
public void intialiseRefreshInterface(RefreshInterface refreshInterface){
this.refreshInterface = refreshInterface;
}
public interface RefreshInterface {
void refresh_fragment();
}
}
fragment_child.xml
<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="com.outthinking.myapplication.TwoFragment">
<!-- TODO: Update blank fragment layout -->
<EditText
android:id="#+id/refersh_tv"
android:textSize="24sp"
android:textAlignment="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="REFRESH DATA" />
<Button
android:id="#+id/btn_refersh"
android:text="refersh"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
I have read all the other topics related to this issue and none seem to be helping me solve the problem.
I am doing some background task in an asynctask that needs to persist on orientation change (configChanges). I have gotten the data to persist I believe by using fragments and setRetainInstance(true), but my buttons (Im assuming any views really) are being set to null on recreation of the fragment on orientation change. This is causing a null pointer error when I try to operate on the buttons reference after orientation has change (fragment has been recreated).
I have tried wrapping the button and calls on the button in a statement to check if the bundle is null. This stops the crash but does not allow for the button to be used again on recreation of the fragment.
The following class extends Fragment.
#Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setRetainInstance(true);
currentActivity = super.getActivity();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onActivityCreated(Bundle)");
super.onActivityCreated(savedInstanceState);
simpleForecastIntent = new Intent(currentActivity, SimpleForecastActivity.class);
Button fetchDataButton = (Button) currentActivity.findViewById(R.id.fetchDataButton);
if (savedInstanceState == null) {
fetchDataButton.setOnClickListener(fetchDataButtonListener);
fetchDataButton.setTransformationMethod(null);
}
locationManager = (LocationManager)
currentActivity.getSystemService(Context.LOCATION_SERVICE);
if (isTaskRunning) {
progressDialog = ProgressDialog.show(currentActivity, "Fetching data", "Please wait...");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreateView(LayoutInflater, ViewGroup, Bundle)");
return inflater.inflate(R.layout.main_menu, container, false);
}
main_menu.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="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activities.MainActivity">
<include layout="#layout/toolbar" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<Button
android:id="#+id/fetchDataButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/locationField"
android:text="#string/fetch_weather_data"
android:layout_centerHorizontal="true" />
<EditText
android:id="#+id/locationField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="#string/enter_location"
android:layout_alignEnd="#+id/fetchDataButton"
android:layout_alignLeft="#+id/fetchDataButton"
android:layout_alignRight="#+id/fetchDataButton"
android:layout_alignStart="#+id/fetchDataButton"
android:inputType="textPostalAddress" />
<ListView
android:id="#+id/previousLocationsList"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/fetchDataButton"
android:layout_centerHorizontal="true" />
</RelativeLayout>
</LinearLayout>
I have spent far too many hours on something so trivial and really need a bump in the correct direction. How can I get the button to not be null on recreation of fragment?
EDIT SOLVED:
I was using the disposed of activity's context to find the view of the button. Instead of the new activities view context.
#Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setRetainInstance(true);
currentActivity = super.getActivity();
}
The problem is that you are referencing your button in onActivityCreated instead of onCreateView. On orientation change, the view gets torn down and then recreated. You should override onCreateView and maintain the reference to your button from there.
UPDATE:
I see how your code is working, but in my opinion it's following a bad design pattern. You are still instantiating your view references inside of onActivityCreated, instead of immediately after they are inflated in onCreateView.
I would switch it to something like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreateView(LayoutInflater, ViewGroup, Bundle)");
View root = inflater.inflate(R.layout.main_menu, container, false);
Button fetchDataButton = (Button) root.findViewById(R.id.fetchDataButton);
...
return root;
}
I'm new to android development and having some issues with replacing a fragment with another fragment.
In my MainFragment.java, the first thing I do in onCreate is check for internet connectivity, and if there is not, I replace that fragment with the InternetCheckFragment. However, in InternetCheckFragment.java, when I try to inflate my check_internet.xml, the app closes, but there is no error.
activity_main.xml:
<fragment 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:id="#+id/main_browse_fragment"
android:name="com.ui.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.ui.MainActivity"
tools:deviceIds="tv"
tools:ignore="MergeRootFrame" />
MainActivity.java:
public class MainActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
MainFragment.java:
public class MainFragment extends VerticalGridFragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (isConnectedToInternet() == true)
{
// DO stuff
}
else
{
showInternetError();
}
}
public void showInternetError()
{
getFragmentManager().beginTransaction().replace(R.id.show_internet_error , new InternetCheckFragment())
.commit();
}
....
}
InternetCheckFragment.java:
public class InternetCheckFragment extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.check_internet, parent, false);
}
}
check_internet.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/show_internet_error"
android:background="#color/black_transparent">
<Button android:id="#+id/btn_retry"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="RETRY"
android:layout_centerInParent="true"/>
</RelativeLayout>
However, I'm getting the error No view found for id.
I'm sure I'm not setting something correctly? Can someone point me in the right direction?
Thanks!
You are inflating a Fragment in a Fragment using the Fragment's FragmentManager.
This FragmentManager cannot handle this.
Try using the SupportFragmentManager with AppCompatActivity.getSupportFragmentManager() and the support Fragments from android.support.v4.app.Fragment
Ugh!..it was a stupid mistake, I replaced R.id.show_internet_error within getFragmentManager().beginTransaction().replace(R.id.show_internet_error , new InternetCheckFragment()).commit(); with R.id.main_browse_fragment and now it works.
I'm working on upgrading an Android application (1.6 compatibility) which uses a TabHost to show 3 different tabs with nested activities.
At the time I used the ActivityGroup trick to show nested activities in a tab but I'm very unhappy with this method since it's a real pain to handle some features.
I heard about the Fragments API compatibility package for 1.6 and a Fragment looks perfect for what I want to do (show nested views / features within a tab with transition effects and stuff) but I can't make it work with a TabHost (It was meant to work with an Action Bar but it's not available in the compatibility package).
Did any of you guys found a way to create such a structure in your applications?
My error here is :
ERROR/AndroidRuntime(955): Caused by: java.lang.RuntimeException: Unable
to start activity
ComponentInfo{com.XXX}:
java.lang.IllegalArgumentException: No
view found for id 0x1020011 for
fragment MyFragment
CODE
main.xml
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_weight="1" />
<TabWidget
android:id="#android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0" />
</LinearLayout>
</TabHost>
MainActivity.java
public class MainActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources();
final TabHost tabs = getTabHost();
TabHost.TabSpec spec;
Intent i;
i = new Intent(this, MyActivity.class);
spec = tabs.newTabSpec("MyActivity").setIndicator("MyActivity",res.getDrawable(R.drawable.tab)).setContent(i);
tabs.addTab(spec);
}
}
MyActivity.class
public class MyActivity extends FragmentActivity {
private static String TAG = "MyActivity";
private static FragmentManager fragmentManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ListeResultatFragment fragment = MyFragment.newInstance();
fragmentTransaction.add(android.R.id.tabcontent, fragment, "MyFragment");
fragmentTransaction.commit();
}
}
MyFragment.java
public class MyFragment extends Fragment {
public static MyFragment newInstance() {
MyFragment instance = new MyFragment();
return instance;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
}
The problem is that your MyActivity tries to reach out to the enclosing MainActivity by using android.R.id.tabcontent as a container id. This is not possible. Instead, MyActivity needs to have its own layout (e.g. a FrameLayout) which can be used as the parent for the Fragment. In this layout, there must exist a view that can be referenced by id.
Let's say you have a layout called activity_layout.xml which contains a FrameLayout with the id 'framelayout'. You can then modify the onCreate method in MyActivity to something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View parent = getLayoutInflater().inflate(R.layout.activity_layout, null);
setContentView(parent);
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment fragment = MyFragment.newInstance();
fragmentTransaction.add(R.id.framelayout, fragment, "MyFragment");
fragmentTransaction.commit();
}
In other words, MyActivity needs to be able to work on its own. Try to make it work first, and then embed MyActivity in the MainActivity containing the TabHost.
Why don't you create your own tabbar. It's verry easy to build. Just add a LinearLayout with some buttons in it and set the onClickListener to switch fragments by using the FragmentManager. The Fragment manager can be obtained from a FragmentActivity.
FragmentManager fragmentManager = getSupportFragmentManager();
In the onClick handler you just do a transaction to the switch to the correct fragments.