I have migrated my application to Android O in Android Studio 3
Running on an Android O emulator all my dialogFragments now fail with :-
java.lang.IllegalStateException: Fragment MyDialogFragment{43ccf50 #2 MyDialogFragment} declared target fragment SettingsFragment{ceed549 #0 id=0x7f0f0142 android:switcher:2131689794:0} that does not belong to this FragmentManager!
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1316)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1624)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1689)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:794)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2470)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2260)
at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2213)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2122)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:746)
at android.os.Handler.handleCallback(Handler.java:769)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6535)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
I have made no code changes whatsoever.
What has changed in Android O that previously working DialogFragments now fail display?
Android Studio 3.0 Canary 1
Build #AI-171.4010489, built on May 15, 2017
JRE: 1.8.0_112-release-b736 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Mac OS X 10.11.6
compileSdkVersion 'android-O'
buildToolsVersion "26.0.0-rc2"
AndroidManifest.xml
defaultConfig {
minSdkVersion 16
targetSdkVersion 'O'
}
compile 'com.android.support:appcompat-v7:26.0.0-beta1'
compile 'com.android.support:cardview-v7:26.0.0-beta1'
compile 'com.android.support:design:26.0.0-beta1'
compile 'com.android.support:percent:26.0.0-beta1'
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha1'
}
For me this was not only an issue on Android O but also on older versions.
The oldest version I tested was API Level 16.
I was instantiating my fragments using this code:
MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getActivity().getSupportFragmentManager(), null);
Where ParentFragment.this is a custom class extending android.support.v4.app.Fragment, MyFragment also extends this class and is a child fragment of the ParentFragment fragment (hence it's name).
I thought that I had to use a SupportFragmentManager (the getSupportFragmentManager() method) because I am using a fragment of the support package so I tried to call getActivity().getSupportFragmentManager() to get an activity reference that supported this method.
This does not seem to be the correct way though.
I changed those calls to:
MyFragment myFragment = MyFragment.newInstance();
myFragment.setTargetFragment(ParentFragment.this, 0);
myFragment.show(getFragmentManager(), null);
so the fragment decides on it's own which FragmentManager to use and the error is gone now.
Hope this helps someone.
I had the same problem, definitely an android bug. It happens when you are showing a fragment from another fragment using it as target. As workaround you can use:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
getActivity().getFragmentManager().beginTransaction().add(dialogFrag, "dialog").commit();
else
getChildFragmentManager().beginTransaction().add(dialogFrag,"dialog").commit();
I just faced the same issues in the project that I am currently working on when we moved to Android Studio 3 and upgraded the support library to version 26. All of a sudden, without changing the code, we got tons of this exception. In the end I found out the following:
Google added a new "sanity check" in the sources of the v4 Fragment Manager in January this year (not sure into what release that went) that refuses to add a fragment using a Fragment Manager, if it has a target fragment set and the target fragment cannot be found in the active fragments of the same Fragment Manager. The patch is described in detail here
Ealier versions seem to not have cared about that. Took me a few days to update all the areas in our code where fragments that were added using the Support Fragment Manager used the Child Fragment Manager for their subfragments with the parent fragment as target. Well, late penalty for writing bad code.
I had the same case as Markus Ressel but I was using getChildFragmentManager(). I replaced that with getFragmentManager() and it resolved the issue.
UPDATE: I've now been working with childFragmentManager and have some feedback.
When dealing with inner fragments that are hosted by a fragment (so a fragment within a fragment) use the childFragmentManager. This fragment manager differs from the activities getSupportFragmentManager. The two are not the same. It's a separation of concerns.
So I've made a rule that fragments hosting child fragments will always use the childFragmentManager and things not inside host fragments can use getSupportfragmentManager.
Recently, my app experienced the same issue when I targeted it for Android O. As a solution, use:
myDialogFragment.show(SettingsFragment.this.getFragmentManager(), TAG);
instead of:
myDialogFragment.show(getFragmentManager(), TAG);
// or
myDialogFragment.show(getSupportFragmentManager(), TAG);
// or
myDialogFragment.show(getChildFragmentManager(), TAG);
while working on an app, I encountered the same problem and I solved it by (in kotlin)
chooseRegionFragment.setTargetFragment(this#ParentFragment, REQUEST_CODE_CHOOSE_REGION)
chooseRegionFragment.show(this#ParentFragment.parentFragmentManager, TAG)
it translates to
chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION);
chooseRegionFragment.show(ParentFragment.this.getParentFragmentManager, TAG);
in java
my app work well until upgrade target version to 27 then i face same issue when call setTargetFragment (Fragment fragment,
int requestCode)
example:
chooseRegionFragment.setTargetFragment(ParentFragment.this, REQUEST_CODE_CHOOSE_REGION);
just change to:
chooseRegionFragment.setTargetFragment(getRootParentFragment(this), REQUEST_CODE_CHOOSE_REGION);
getRootParentFragment(this) this method will find root parent of fragments for you
/**
* find root parent of fragment
*/
public static Fragment getRootParentFragment(Fragment fragment) {
Fragment parent = fragment.getParentFragment();
if(parent == null)
return fragment;
else
return getRootParentFragment(parent);
}
Use below solution and you do not need to worry about which fragment managers you are dealing with,
Assuming that you must have used a BaseFragment.
First create an interface:
public interface OnRequestUpdateListener {
void onRequestUpdate(final int requestCode, final Intent data);
void setRequestFragment(final BaseFragment requestFragment, int requestCode);
BaseFragment getRequestFragment();
int getRequestCode();
}
Implement that interface in your BaseFragment
public class BaseFragment extends Fragment implements OnRequestUpdateListener {
private BaseFragment requestFragment;
private int requestCode;
#Override
public void onRequestUpdate(int requestCode, Intent data) {
// you can implement your logic the same way you do in onActivityResult
}
#Override
public void setRequestFragment(BaseFragment requestFragment, int requestCode) {
this.requestFragment = requestFragment;
this.requestCode = requestCode;
}
#Override
public BaseFragment getRequestFragment() {
return requestFragment;
}
#Override
public int getRequestCode() {
return requestCode;
}
}
Then, replace the setTargetFragment with setRequestFragment and replace getTargetFragment with getRequestFragment.
Here, you could also user onRequestUpdate in place of onActivityResult.
This is a custom solution without bothering about the which fragment manager you are using.
Using getFragmentManager() instead of getChildFragmentManager() would also work but it affects getParentFragment(). If you do not use a getChildFragmentManager() for nested fragment then you will not be able the get the parent fragment by using getParentFragment() in child/nested fragment.
How to show a created dialog for API version 10? I have changed my MainActivity's extension to FragmentActivity and getFragmentManager() to getSupportFragmentManager().
But then in my code snippet-
DuplicateColMessage duplicate_dialog =new DuplicateColMessage();
message="Column "+refinedcol[index].toUpperCase()+" already has data";
duplicate_dialog.show(getSupportFragmentManager(), DROPBOX_SERVICE);
The duplicate_dialog.show() method complains about getSupportFragmentManager. How do I overcome this?
I try to use Robolectric to run tests for my Android application, which is using the android-support package. In my onCreate() method I call
getSupportLoaderManager().initLoader(0, null, this);
Unfortunately, getSupportLoaderManager() returns null here. Do I have to prepare anything to make the compatiblity classes available to robolectric?
I have the android.jar (android-8) and the android-support-v4.jar in the classpath in my test project, along with robolectric-1.2 snapshot version.
Test class:
#RunWith(RobolectricTestRunner.class)
public class HoebAppActivityTest {
#Test
public void shouldStartActivity() {
final MyActivity activity = new MyActivity();
System.out.println(activity.getSupportLoaderManager()); // return null
activity.onCreate(null);
}
}
Edit:
System.out.println(Robolectric.directlyOnFullStack(activity)
.getSupportLoaderManager());
outputs android.support.v4.app.LoaderManagerImpl#9a90b9 so I guess, I just need to feed this back to the activity? Seems like I am getting closer here.
Edit2: I tried to bind my own ShadowFragmentActivity:
#Implements(FragmentActivity.class)
public class ShadowFragmentActivity extends
com.xtremelabs.robolectric.shadows.ShadowFragmentActivity {
#RealObject
private FragmentActivity realActivity;
#Implementation
public LoaderManager getSupportLoaderManager() {
return Robolectric.directlyOnFullStack(realActivity)
.getSupportLoaderManager();
}
}
bound with
Robolectric.bindShadowClass(ShadowFragmentActivity.class);
This appears to work for the moment. I will have to try further to see if it does what I want. No idea if this is in any way the correct way to go or not.
Robolectric 1.x had poor support for the Android support library. Robolectric 2.0 is significantly better, and has full support for fragments. An alpha was just released today:
<dependency>
<groupId>org.robolectric</groupId>
<artifactId>robolectric</artifactId>
<version>2.0-alpha-1</version>
<dependency>
I downloaded the ActionBarSherlock version 4.1.0.0, and added a the Android Project library into Eclipse 4.2 on my Win7 java 1.6 update 24 machine. I used an Eclipse Project Build Target of Android 4.1 in Project | Properties | Project Build Target. I want to incorporate the ActionBar functionality into an existing app that has minSdkVersion="7". I noted the code from the ActionBarSherlock library appears to have some deprecated methods, and an error:
Example 1: ActionBarContainer.java, ActionBarContextView.java, ScrollingTabContainerView.java - uses setBackgroundDrawable - The method setBackgroundDrawable(Drawable) from the type View is deprecated
public ActionBarContainer(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundDrawable(null);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SherlockActionBar);
mBackground = a.getDrawable(R.styleable.SherlockActionBar_background);
mStackedBackground = a.getDrawable(
R.styleable.SherlockActionBar_backgroundStacked);
if (getId() == R.id.abs__split_action_bar) {
mIsSplit = true;
mSplitBackground = a.getDrawable(
R.styleable.SherlockActionBar_backgroundSplit);
}
a.recycle();
setWillNotDraw(mIsSplit ? mSplitBackground == null :
mBackground == null && mStackedBackground == null);
}
Quick fix shows as Add #SupressWarnings 'deprecation' for ActionBarContainer
Example 2:
IcsProgressBar.java uses animationResolution which shows as deprecated, same quick fix as above
private static final int[] ProgressBar = new int[] {
...
android.R.attr.animationResolution
Also, I have an error in ActivityChooserView.java:
private static class SetActivated {
public static void invoke(View view, boolean activated) {
view.setActivated(activated);
}
}
Error is on SetActivated - Call requires API 11 (current min is 7). This makes sense based on the manifest:
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15"/>
Shouldn't API 7 be fine, since Action Bar Sherlock should work at at Andriod 2.x? Have others experienced this, and if so, what is the recommended action? Supress/ignore the deprecation? What about the error on SetActivated? I reviewed the readme and did some net searches but did not come up with anything on this. Thanks for any suggestions.
Thanks!
It is just fine. The code is 2.x compatible and even some methods are deprecated as of 4.x, they are still there. It also do not mean on 4.x these deprecated methods will be used. The source is 2.x-4.x so there's no other way (not to mention reflection, but that'd hurt performance, and is for now not necessary). So it is safe to just ignore this. It would probably be better to turn depreciation off for certain files but it is not there. So do not worry.
This is doesn't really answer the question but I ran into the same issue when I had to have a minSdkVersion 9 and I wanted to have ActionBarSherlock but I was getting the same error of the actionBar requires minSdkVersion 11.
Apparently in ADT 21.1 you make a values-v11/styles.xml and put the actionBar in there.
https://code.google.com/p/android/issues/detail?id=48283
I'm trying to use the function setOffscreenPageLimit() in ViewPager, but Eclipse says The function setOffscreenPageLimit() is undefined for the type ViewPager
However, I see it in the docs and in many examples. ViewPager
Here's my code:
import android.support.v4.view.ViewPager;
public class MyView {
private final ViewPager viewPager;
MyView (ViewPager viewPager) {
this.viewPager = viewPager;
viewPager.setOffscreenPageLimit(2); //<-- can't find it
}
}
I think it must be some strange problems with the library. My minSdk is 7 and target is 13. I've pressed "check for updates" many times and even tried manually re-importing the compatibility library but this function still doesn't show up. Any ideas? I really need this function!
I think that .setOffscreenPageLimit() was a recent addition to the android support library. You should update your support library to the newest (currently v9) using Android SDK Manager. Cheers
I was having a similar problem and the solution was to add the jar file to the libs directory AND add it to the build path in the projects properties. Do not add the file as an external jar, click "add jar".
Hope this helps.