Categories
discuss

Is it safe to commit a FragmentTransaction inside onActivityResult()?

Years ago, I ran into a problem in one of my apps when I tried to commit a FragmentTransaction inside my onActivityResult() callback. Googling around, I found this question and answer, which say

At the time that onActivityResult() is called, the activity/fragment’s state may not yet have been restored, and therefore any transactions that happen during this time will be lost as a result.

I wound up adapting the solution recommended in the same answer for my app, and life was good. However, recent experimentation shows that perhaps things have changed, and it may now be safe to commit a FragmentTransaction from inside onActivityResult().

The documentation for (support v4) FragmentManager.beginTransaction() defines the safe window for transactions as:

Note: A fragment transaction can only be created/committed prior to an activity saving its state. If you try to commit a transaction after FragmentActivity.onSaveInstanceState() (and prior to a following FragmentActivity.onStart or FragmentActivity.onResume(), you will get an error.

Reading the documentation for onActivityResult(), I see

You will receive this call immediately before onResume() when your activity is re-starting.

This leads me to believe that it should be safe to execute these transactions in onActivityResult(), as onStart() will have already been called, putting me inside the safe window.

I made an app to test this out, and I’m successfully seeing dialog fragments that I create and commit inside onActivityResult(). I had the same app also log the activity lifecycle callbacks so I could inspect their order, and I see onStart(), then onRestoreInstanceState(), and then onActivityResult() every time.

Am I missing something? Or has the framework changed and onActivityResult() is now guaranteed to be a safe place for fragment transactions? Does this behavior vary by API level?

I found another question and answer that seems to read the documentation the same way I have, but both are over a year old and neither specifically refers to onActivityResult() as a safe place for transactions.

Answer

A little dive into sources

There is a boolean variable inside FragmentManager class, called mStatedSaved. This variable keeps track of the saved state depending on the activity’s lifecycle callbacks. Here’s the method, that throws well-known exception:


    private void checkStateLoss() {
        if (mStateSaved) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        ...
    }

This means, that as soon as this variable is changed to false, then fragment transactions are free to be executed. This variable would become true, when the state of the activity is being saved, i.e. onSaveInstanceState().


Back to the question

You said, that previously you had problems commiting a transaction from onActivityResult(). That should mean, that previously mStateSaved was not being assigned false and currently it is. In deed it is so.

Here’s onActivityResult() implementation from O release:


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        mFragments.noteStateNotSaved();
        ...
    }

Where, noteStateNotSaved() would do following:


    public void noteStateNotSaved() {
        ...
        mStateSaved = false;
        ...
    }

On the contrary, you can see the implementation of onActivityResult() of Jelly Bean release:


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        int index = requestCode>>16;
        if (index != 0) {
            index--;
            if (mFragments.mActive == null || index = mFragments.mActive.size()) {
                Log.w(TAG, "Activity result fragment index out of range: 0x"
                        + Integer.toHexString(requestCode));
                return;
            }
            Fragment frag = mFragments.mActive.get(index);
            if (frag == null) {
                Log.w(TAG, "Activity result no fragment exists for index: 0x"
                        + Integer.toHexString(requestCode));
            } else {
                frag.onActivityResult(requestCode&0xffff, resultCode, data);
            }
            return;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

Nothing would change the value of mStateSaved field, which would make an exception to be thrown if a transaction is committed.

In fact, the line mFragments.noteStateNotSaved() was introduced in Kit-Kat release. As you can see by the commit’s comment made by Dianne Hackborn:

ActivityFragment should clear the flag that state is saved when it
receives onNewIntent(). This can happen before the activity is
resumed, so we may not have cleared it yet. Also need to do the same
thing for onActivityResult().

Sum up

Is onActivityResult() now guaranteed to be a safe place for fragment transactions?

Assuming you are using sources that include commit 4ccc001, which was made in October 2012 – yes, it is a safe place for fragment transactions.

Categories
discuss

Pass eslint html-has-for with htmlFor in React

I have a stateless React component that looks like this:

const propTypes = exact({
  fieldId: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired,
});

function Label({ fieldId, text }) {
  return (
    <label htmlFor={fieldId}>{text}</label>
  );
}

Label.propTypes = propTypes;

I am using eslint extended with the airbnb config. My eslint looks like this:

{
  "extends": "airbnb"
}

My React code throws this error:

error  Form label must have associated control  jsx-a11y/label-has-for

I have clearly set an htmlFor attribute with a valid unique id string (which matches the id on an input elsewhere). Surely this is enough to pass this rule?

Answer

In addition to setting an htmlFor attribute and an id the input element has to be nested inside the label. You can, however, turn off the nesting requirement if you want. Something like this:

{
  "extends": "airbnb",
  "rules": {
    "jsx-a11y/label-has-for": [ 2, {
      "required": {
          "every": [ "id" ]
      }
  }]
  }
}

Issue related to your problem: https://github.com/evcohen/eslint-plugin-jsx-a11y/issues/314

Docs: https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md

Categories
discuss

what does “::” mean in kotlin?

I’m new to Kotlin
I used this code for opening another activity:

startActivity(Intent(this,IntroAndLang::class.java))

current activity and target activity are written in Kotlin

I cant understand why there is not single : instead of :: at IntroAndLang::class.java

Answer

As stated in the docs this is a class reference:

Class References: The most basic reflection feature is getting the runtime reference to a Kotlin class. To obtain the reference to a statically known Kotlin class, you can use the class literal syntax:

val c = MyClass::class
//The reference is a value of type KClass.

Note that a Kotlin class reference is not the same as a Java class reference. To obtain a Java class reference, use the .java property on a KClass instance.

It’s also the syntax for method references as in this simple example:

list.forEach(::println)

It refers to println defined in Kotlin Standard library.

Categories
discuss

Requesting READ_PROFILE permission at runtime

According to the Android documentation (https://developer.android.com/reference/android/provider/ContactsContract.Profile.html), I need to request the android.permission.READ_PROFILE permission to read the user’s profile information.

However, when I attempt to create runtime permission request, there is no Manifest.permission.READ_PROFILE I can use. Do I just use the Manifest.permission.READ_CONTACTS permission instead?

Note: The AndroidManifest.xml file can find the permission just fine:

<uses-permission android:name="android.permission.READ_PROFILE" />

Answer

READ_PROFILE permission was removed on API 23 as you can see here

https://developer.android.com/sdk/api_diff/23/changes.html

You should ask for GET_ACCOUNTS, or any of the permissions belonging to the CONTACTS group

https://developer.android.com/guide/topics/permissions/requesting.html#perm-groups

Categories
discuss

Spark: get number of cluster cores programmatically

I run my spark application in yarn cluster. In my code I use number available cores of queue for creating partitions on my dataset:

Dataset ds = ...
ds.coalesce(config.getNumberOfCores());

My question: how can I get number available cores of queue by programmatically way and not by configuration?

Answer

There are ways to get both the number of executors and the number of cores in a cluster from Spark. Here is a bit of Scala utility code that I’ve used in the past. You should easily be able to adapt it to Java. There are two key ideas:

  1. The number of workers is the number of executors minus one or sc.getExecutorStorageStatus.length - 1.

  2. The number of cores per worker can be obtained by executing java.lang.Runtime.getRuntime.availableProcessors on a worker.

The rest of the code is boilerplate for adding convenience methods to SparkContext using Scala implicits. I wrote the code for 1.x years ago, which is why it is not using SparkSession.

One final point: it is often a good idea to coalesce to a multiple of your cores as this can improve performance in the case of skewed data. In practice, I use anywhere between 1.5x and 4x, depending on the size of data and whether the job is running on a shared cluster or not.

import org.apache.spark.SparkContext

import scala.language.implicitConversions


class RichSparkContext(val sc: SparkContext) {

  def executorCount: Int =
    sc.getExecutorStorageStatus.length - 1 // one is the driver

  def coresPerExecutor: Int =
    RichSparkContext.coresPerExecutor(sc)

  def coreCount: Int =
    executorCount * coresPerExecutor

  def coreCount(coresPerExecutor: Int): Int =
    executorCount * coresPerExecutor

}


object RichSparkContext {

  trait Enrichment {
    implicit def enrichMetadata(sc: SparkContext): RichSparkContext =
      new RichSparkContext(sc)
  }

  object implicits extends Enrichment

  private var _coresPerExecutor: Int = 0

  def coresPerExecutor(sc: SparkContext): Int =
    synchronized {
      if (_coresPerExecutor == 0)
        sc.range(0, 1).map(_ => java.lang.Runtime.getRuntime.availableProcessors).collect.head
      else _coresPerExecutor
    }

}

Update

Recently, getExecutorStorageStatus has been removed. We have switched to using SparkEnv‘s blockManager.master.getStorageStatus.length - 1 (the minus one is for the driver again). The normal way to get to it, via env of SparkContext is not accessible outside of the org.apache.spark package. Therefore, we use an encapsulation violation pattern:

package org.apache.spark

object EncapsulationViolator {
  def sparkEnv(sc: SparkContext): SparkEnv = sc.env
}
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..