I am using deprecated method setTargetFragment() getTargetFragment() . Using setTargetFragment(target) lets the "called" fragment know where to send the result and calling onActivityResult() manually in this case. check caller fragment like this
if (getTargetFragment() instanceof FragmentA ){
// Some Code
getTargetFragment().onActivityResult(requestCode, Activity.RESULT_OK, returnIntent);
}
Starting new fragment like this
Media_Gallery gallery = new Media_Gallery();
gallery.setTargetFragment(AddMedia.this,104);
FragmentTransaction fragmentTrasaction=getParentFragmentManager().beginTransaction();
fragmentTrasaction.addToBackStack("Image");
fragmentTrasaction.replace(R.id.Main_Layout,gallery,"Image");
fragmentTrasaction.commit();
As i am targeting latest API (33) It's stop working for me. Trying to get logic from here but it's bit confusing to me. Can anyone help me understand how can i replace deprecated method to
Related
Looking to handle a deep link from the Google Assistant. As I only have an emulator at the moment I am having trouble testing it (from what I have read it requires a real device). That said, I was wondering if I am handling it the correct way. I am unfamiliar with Kotlin and my code was turning into Spaghetti trying to integrate, so I put this together in my existing launcher activity just to try and get it bootstrapped for now. The manifest and actions.xml were set up like the fitness app tutorial.
Am I doing this correctly?
if (mAuth.getCurrentUser() != null) {
data = this.getIntent().getData();
if (data != null && data.isHierarchical()) {
uriData = data.toString();
containsStart = containsIgnoreCase(uriData,"start");
containsRun = containsIgnoreCase(uriData,"run");
if(containsStart && containsRun) {
Intent intent = new Intent(getApplication(), RunActivity.class);
intent.putExtra("runStart", true);
startActivity(intent);
}
}
else {
checkUserAccType();
}
//Else, if there is no current user, start the Authentication activity
}
A few observations and recommendation about your code:
Instead of using containsIgnoreCase uses getPath() and match the path. See example.
Also, for the activity parameter use URL query param instead of containsIgnoreCase. See example
Starting the activity or fragment. I assume startActivity and checkUserAccType will handle that part. See example.
// Else... section should go one line below.
Authentication. It looks fine. And it seems you're using Firebase by the getCurrent method signature. See example
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.
Despite my efforts to prevent fragments from being added more than once, I continue to encounter java.lang.IllegalStateException: Fragment already added: VideoFragment.
I have an activity where VideoFragment is instantiated in onCreate only. In the only place I attempt to display the VideoFragment, I first check whether this fragment has been added already.
private VideoFragment videoFragment;
public void onCreate(Bundle savedInstanceState) {
...
videoFragment = new VideoFragment();
...
}
private void showVideoFragment() {
if (!videoFragment.isAdded()) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, videoFragment, "video").commit();
}
}
I have not been able to consistently reproduce this problem to examine in the debugger, but my runtime error reporting continues to report the exception java.lang.IllegalStateException: Fragment already added: VideoFragment for users, with stack traces composed of Android classes.
/FragmentManager.java:1133→ android.app.FragmentManagerImpl.addFragment
/BackStackRecord.java:648→ android.app.BackStackRecord.run
/FragmentManager.java:1453→ android.app.FragmentManagerImpl.execPendingActions
/FragmentManager.java:443→ android.app.FragmentManagerImpl$1.run
/Handler.java:733→ android.os.Handler.handleCallback
/Handler.java:95→ android.os.Handler.dispatchMessage
/Looper.java:146→ android.os.Looper.loop
/ActivityThread.java:5487→ android.app.ActivityThread.main
/Method.java:-2→ java.lang.reflect.Method.invokeNative
/Method.java:515→ java.lang.reflect.Method.invoke
/ZygoteInit.java:1283→ com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
/ZygoteInit.java:1099→ com.android.internal.os.ZygoteInit.main
/NativeStart.java:-2→ dalvik.system.NativeStart.main
Does the definition of added in isAdded() not match the one used to check fragment transactions?
Or is there some way the videoFragment reference in the activity is not the same? Is this something I need to explicitly handle when saving state http://developer.android.com/guide/components/activities.html#SavingActivityState?
Or is there a reliable alternative way of checking whether the fragment has already been added?
UPDATE
I have figured out how to semi-reliably produce the problem.
Start application
Navigate away from application, and run other programs for awhile. On my Galaxy Nexus (which is pretty slow these days), using Chrome to read a few news articles seems sufficient. When returning to the home screen, if it takes a few seconds to render then the application will likely throw the fragment exception.
Restart application and trigger fragment change
If I kill and simply run the application, everything appears to be fine. Or if I navigate away from the application and come back immediately, it works okay. It's only if the application is left in the background for a bit (enough to remove from memory?), that the fragment issue appears.
I also tried, to no effect, in onCreate
View v = findViewById(R.id.fragment_container);
if(v != null){
Log.d(TAG, "disabling save for fragment_container");
v.setSaveEnabled(false);
v.setSaveFromParentEnabled(false);
}
I also tried checking Fragment prior = getFragmentManager().findFragmentByTag("video"); and Fragment prior2 = getFragmentManager().findFragmentById(R.id.fragment_container); before running the replace fragment transaction, but these come up null.
My problem in fact looks very similar to
https://code.google.com/p/android/issues/detail?id=61247
though the time appears less an issue than memory/cache effects. It is completely unclear to me why that issue was closed.
I will try to produce a simple application that replicates this issue. My current one uses webrtc, and the logcat output is completely cluttered with webrtc messages.
I see a few things here:
Your problem occours propably when Activity is recreated by the system. You can simply simulate it by changing device orientation.
isAdded() returns false, because Activity was recreated so this method is called for new instatnce of VideoFragment which hasn't knowledge about previous add.
showVideoFragment() actually add fragment to Activity instead of just show it. I suggest you rename that method to somethink like "addVideoFragment" and move it to onCreate() method. If you do that you resolve the issue.
If you really want to show or hide fragment use methods from FragmentTransaction eg:
FragmentManager fm = getFragmentManager();
fm.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.show(somefrag) // or hide
.commit();
Hint:
When you a priori know that you fragment is always the VideoFragment you can simply use:
<fragment
android:name="com.example.VideoFragment"
android:id="#+id/video_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
find it:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
VideoFragment fragment = (VideoFragment) getFragmentManager().findFragmentById(R.id.video_fragmen);
}
and make whatever you want with the instance.
I think I have successfully fixed this error, by trying to reproduce this in a simpler example:
https://stackoverflow.com/a/30672516/4107809
I was making a mistake where multiple instances of a fragment (not the VideoFragment) were added in successive calls to onCreate caused by recreation of the Activity. This fragment addition did not trigger the java.lang.IllegalStateException: Fragment already added because apparently this happens only if you try to add the same fragment instance more than once, not multiple instances of the same fragment.
Upon calling the fragment replace method, the java.lang.IllegalStateException: Fragment already added is generated for the new VideoFragment, even though the VideoFragment is only added once using replace.
By ensuring the different fragment was added only once, the replace by the VideoFragment no longer generates java.lang.IllegalStateException: Fragment already added: VideoFragment, at least for the steps for reproducing I outlined above. The IllegalStateException appears to have nothing to do with adding/replacing the VideoFragment, but with the state of the fragments being replaced.
I am displeased by this resolution for two reasons:
The error message is misleading. It says the VideoFragment has already been added, and I have resolved this by making sure that a different fragment is not added more than once, which did not generate an exception.
The replace documentation is very misleading. Based on my reading, it should not matter what the state of the fragment container is prior to calling to replace; the end state should be determined solely by the fragment that is added from the replace argument. I think this discrepancy is most clear in the linked question, though the answerer in that question disagrees.
Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.
In MainActivity starts another activity via startActivityForResult
Intent intent = new Intent(MainActivity.this, AutorisationForm.class);
intent.putExtra("req", 1);
startActivityForResult(intent, 0);
Method onCreate executes successful, activity displays on the screen and then app crash. Eclipse returns "source not found" error.
How I can solve this problem?
P.S. All activities declared in manifest.
P.P.S All worked successfully before I add a lot of logic in MainActivity. This code and second class hasn't changed.
Problem solved. Mistake was in onDestroy() method in MainActivity. In this method app try to save unloaded file. Theme closed.
Undo all changes before adding "a lot of logic in MainActivity."
Add changes one at a time and test in between until you discover problem.
Problem discovered!
I'm currently working on an Android App and, almost every time I use it, I get a an error. Most of the time it doesn't crash the app, but it is still frustrating that I'm seeing this error. I thought I did a check for it, but I could be wrong. Thanks for the help! The relevant code is below. (It's relevant because the line outside the if statement is throwing the NullPointerException.)
Activity activity;
if(activity == null)
{
activity = new Activity();
}
Intent intent = new Intent(activity, Service.class);
You don't usually instantiate the Activity class in this manner. Please see the documentation on the Android Activity class here:
http://developer.android.com/reference/android/app/Activity.html
You should post some more of the surrounding code, but your problem is that creating new Intent requires a valid Context. Usually you create an Intent within an Activity (or Service or BroadcastReceiver) class so you can just do something like:
Intent intent = new Intent(this, Service.class);
Occasionally you'll create it somewhere else and pass it that valid Context, but you should pretty much never create an Activity by calling the constructor directly. There's a lot of other initialization necessary to make it useful.
As postet previously there is more to initiate for an activity than calling the constructor. Probably you get a null pointer exception deep within the Intent Constructer where it is trying to get some of the Activityinformation usually provided.
If you really want to create a Service, heres a link for starting a Service, but you should really read the whole article and probably some more of the activity lifecycle ressources.
http://developer.android.com/guide/topics/fundamentals/services.html#StartingAService