如果在片段和活动

时间:2016-03-14 13:47:30

标签: android android-6.0-marshmallow

我有一个片段,我在其中使用recyclerview适配器在recyclerview中使用recyclerview和设置数据。

现在,我在适配器的列表项中点击了一个按钮,我需要在android中检查android中的新权限模型的READ_EXTERNAL_STORAGE权限。

我在此适配器的片段中创建了一个新函数,以检查是否授予了权限,如果尚未授予权限,则请求权限。

我已将MyFragment.this作为适配器中的参数传递,并在适配器上单击按钮时调用片段方法。

我使用下面的代码在片段中调用requestPermission。

if(ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED)){
       requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                ConstantVariables.READ_EXTERNAL_STORAGE);
    }

我已使用以下代码覆盖了片段中的onRequestPermissionsResult方法:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case ConstantVariables.READ_EXTERNAL_STORAGE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, proceed to the normal flow.
                startImageUploading();
            } else {}

但它没有被调用,而是调用了Activity的onRequestPermissionsResult方法。

我已经在片段的父活动中定义了相同的onRequestPermissionsResult方法,并且它被调用。

我无法删除活动的onRequestPermissionsResult方法,但是当我从片段请求权限时,想要调用片段的onRequestPermissionsResult方法。 我怎样才能做到这一点?我在这里做错了什么,如果有人在这里有想法,请帮助我。

16 个答案:

答案 0 :(得分:270)

编辑答案以涵盖更广泛的问题

我认为你对片段和活动的方法感到困惑。上个月我的项目有类似的问题。请检查您是否最终获得以下内容:

  1. 在AppCompatActivity中使用方法 ActivityCompat.requestpermissions
  2. 在v4支持片段中,您应使用 requestpermissions
  3. Catch是您在片段中调用AppcompatActivity.requestpermissions然后回调将进入活动而不是片段
  4. 请务必从活动的super.onRequestPermissionsResult
  5. 中致电onRequestPermissionsResult

    看看它是否有帮助。

答案 1 :(得分:43)

我从一个片段中请求了位置权限,在这个片段中,我需要更改它:

            ActivityCompat.requestPermissions(getActivity(), new String[]{
                Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_REQ_CODE);

对此:

            requestPermissions(new String[]{
                Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_REQ_CODE);

然后在片段中调用onRequestPermissionsResult。

答案 2 :(得分:14)

更改此内容:

package logika;

/**
 *  Třída Hra - třída představující logiku adventury.
 * 
 *  Toto je hlavní třída  logiky aplikace.  Tato třída vytváří instanci třídy HerniPlan, která inicializuje mistnosti hry
 *  a vytváří seznam platných příkazů a instance tříd provádějící jednotlivé příkazy.
 *  Vypisuje uvítací a ukončovací text hry.
 *  Také vyhodnocuje jednotlivé příkazy zadané uživatelem.
 *
 *@author     Michael Kolling, Lubos Pavlicek, Jarmila Pavlickova, Jan Novotný
 *@version    pro školní rok 2016/2017, ZS 2019/2020
 */

public class Hra implements IHra {
    private SeznamPrikazu platnePrikazy;    // obsahuje seznam přípustných příkazů
    private HerniPlan herniPlan;
    private boolean konecHry = false;
    private Batoh batoh;

    /**
     *  Vytváří hru a inicializuje místnosti (prostřednictvím třídy HerniPlan) a seznam platných příkazů.
     */
    public Hra() {
        herniPlan = new HerniPlan();
        batoh = new Batoh();
        platnePrikazy = new SeznamPrikazu();
        platnePrikazy.vlozPrikaz(new PrikazNapoveda(platnePrikazy));
        platnePrikazy.vlozPrikaz(new PrikazJdi(herniPlan));
        platnePrikazy.vlozPrikaz(new PrikazSeber(herniPlan));
        platnePrikazy.vlozPrikaz(new PrikazKonec(this));
        platnePrikazy.vlozPrikaz(new PrikazBatoh(herniPlan));
        platnePrikazy.vlozPrikaz(new PrikazZahod(herniPlan));
        platnePrikazy.vlozPrikaz(new PrikazOdemkni(herniPlan));
        platnePrikazy.vlozPrikaz(new PrikazVybojuj(herniPlan));
    }

    /**
     *  Vrátí úvodní zprávu pro hráče.
     */
    public String vratUvitani() {
        return "Vítejte!\n" +
        "Hraješ za dobrodruha Jindřicha, který se nachází ve své lodi,\n" +
        "kterou připlul na tajemný ostrov.\n" +
        "Tvým cílem je najít prababiččin poklad ukrytý v hoře.\n" +
        "Aby jsi poklad získal, musíš nejprve najít meč, který je schovaný v jeskyni.\n" +
        "Klíč k tajné schránce v jeskyni najdeš u lesní víly.\n" +
        "K získání pokladu musíš mečem otevřít bránu k pokladu\n" + 
        "a zabít místního strážce.\n" + 
        "Napište 'nápověda', pokud si nevíte rady, jak hrát dál.\n" +
        "\n" +
        herniPlan.getAktualniProstor().dlouhyPopis();
    }

     /**
     *  Vrátí závěrečnou zprávu pro hráče.
     */
    public String vratEpilog() {
        return "Dík, že jste si zahráli. Brzy se zase vraťte! Ahoj.";
    }

    /** 
     * Vrací true, pokud hra skončila.
     */
    public boolean konecHry() {
        return konecHry;
    }

    /**
     *  Metoda zpracuje řetězec uvedený jako parametr, rozdělí ho na slovo příkazu a další parametry.
     *  Pak otestuje zda příkaz je klíčovým slovem  např. jdi.
     *  Pokud ano spustí samotné provádění příkazu.
     *
     *@param  radek  text, který zadal uživatel jako příkaz do hry.
     *@return          vrací se řetězec, který se má vypsat na obrazovku
     */
    public String zpracujPrikaz(String radek) {
        String [] slova = radek.split("[ \t]+");
        String slovoPrikazu = slova[0];
        String []parametry = new String[slova.length-1];
        for(int i=0 ;i<parametry.length;i++){
            parametry[i]= slova[i+1];   
        }
        String textKVypsani=" .... ";
        if (platnePrikazy.jePlatnyPrikaz(slovoPrikazu)) {
            IPrikaz prikaz = platnePrikazy.vratPrikaz(slovoPrikazu);
            textKVypsani = prikaz.provedPrikaz(parametry);
            if (herniPlan.jeVyhra()){
                konecHry = true;
                textKVypsani += "\n + výhra!"; //\n je odřádkování
            }
        }
        else {
            textKVypsani="Nevím co tím myslíš? Tento příkaz neznám! ";
        }
        return textKVypsani;
    }

    /**
     *  Nastaví, že je konec hry, metodu využívá třída PrikazKonec,
     *  mohou ji použít i další implementace rozhraní Prikaz.
     *  
     *  @param  konecHry  hodnota false= konec hry, true = hra pokračuje
     */
    void setKonecHry(boolean konecHry) {
        this.konecHry = konecHry;
    }

    /**
     *  Metoda vrátí odkaz na herní plán, je využita hlavně v testech,
     *  kde se jejím prostřednictvím získává aktualní místnost hry.
     *  
     *  @return     odkaz na herní plán
     */
    public HerniPlan getHerniPlan(){
        return herniPlan;
    }


    /**
     *  Metoda vrátí odkaz na batoh.
     *
     *
     *  @return     odkaz na batoh
     */
    public Batoh getBatoh(){
        return batoh;
    }
  }

对此:

ActivityCompat.requestPermissions(
    activity,
    arrayOf(Manifest.permission.READ_CONTACTS),
    PERMISSIONS_REQUEST_READ_CONTACTS
)

答案 3 :(得分:6)

Fragments上的requestPermissions方法要求API等级为23或更高 如果您的应用针对较低版本,则可以使用

FragmentCompat.requestPermissions(this,
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            ConstantVariables.READ_EXTERNAL_STORAGE);

首先,您需要添加support-v13依赖项:

implementation "com.android.support:support-v13:$supportLibVersion"

答案 4 :(得分:5)

这是人们在编写棉花糖时常犯的错误。

在AppCompatActivity中时,应使用ActivityCompat.requestPermissions; 在android.support.v4.app.Fragment中时,您应该只使用requestPermissions(这是android.support.v4.app.Fragment的实例方法) 如果您在片段中调用ActivityCompat.requestPermissions,则会在活动而非片段上调用onRequestPermissionsResult回调。

requestPermissions(permissions, PERMISSIONS_CODE);

如果您是从片段中调用此代码,则它具有自己的requestPermissions方法。

基本概念是,如果您处于“活动”中,请致电

ActivityCompat.requestPermissions(this,
                            new String[]{Manifest.permission.CAMERA},
                            MY_PERMISSIONS_REQUEST_CAMERA);

如果在片段中,只需调用

requestPermissions(new String[]{Manifest.permission.CAMERA},
                            MY_PERMISSIONS_REQUEST_CAMERA);

作为参考,我已从此链接https://www.coderzheaven.com/2016/10/12/onrequestpermissionsresult-not-called-on-fragments/获得了答案

答案 5 :(得分:4)

如果您想进入 Fragment 的 Fragment.requestPermission(),您必须调用 onPermissionResult

答案 6 :(得分:3)

当我们从片段中请求权限时,android 会在

中更改我们的 requestCode <块引用>

requestPermissionsFromFragment

这是来自 FragmetActivity 的代码:

 void requestPermissionsFromFragment(@NonNull Fragment fragment, @NonNull String[] permissions,
        int requestCode) {
    if (requestCode == -1) {
        ActivityCompat.requestPermissions(this, permissions, requestCode);
        return;
    }
    checkForValidRequestCode(requestCode);
    try {
        mRequestedPermissionsFromFragment = true;
        int requestIndex = allocateRequestIndex(fragment);
        ActivityCompat.requestPermissions(this, permissions,
                ((requestIndex + 1) << 16) + (requestCode & 0xffff));
    } finally {
        mRequestedPermissionsFromFragment = false;
    }
}

你可以看到 (requestIndex + 1) << 16) + (requestCode & 0xffff)

<块引用>

onRequestPermissionsResult

android 检查请求代码,如果它是从片段发送的,它将结果传递给片段,否则它不会将它传递给片段 这是来自 FragmentActivity 的代码:

enter code here@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    mFragments.noteStateNotSaved();
    int index = (requestCode >> 16) & 0xffff;
    if (index != 0) {
        index--;

        String who = mPendingFragmentActivityResults.get(index);
        mPendingFragmentActivityResults.remove(index);
        if (who == null) {
            Log.w(TAG, "Activity result delivered for unknown Fragment.");
            return;
        }
        Fragment frag = mFragments.findFragmentByWho(who);
        if (frag == null) {
            Log.w(TAG, "Activity result no fragment exists for who: " + who);
        } else {
            frag.onRequestPermissionsResult(requestCode & 0xffff, permissions, grantResults);
        }
    }
}

总结

因此,如果您调用 activity.requestPermission() 或 ActivityCompat.requestPermission 它将结果传递给您的 Activity 如果您调用 fragment.requestPermission() 它将结果传递给您的 Activity AND片段

答案 7 :(得分:2)

在片段中,您不应将ActivityCompat用于requestPermissions,而应仅使用requestPermissions并在方法中传递两个参数。

  1. 权限字符串
  2. RequestCode。

对于exp:

 requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);

答案 8 :(得分:1)

这个公认的答案对我不起作用,因此我找到了自己的解决方案,如下所述:

1。首先,我在片段中创建了一个方法:

public static void MyOnRequestPermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){
        if (requestCode == 1 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Permission: true");
        } else {
            Log.d(TAG, "permission: false");
        }
}

2。然后从其基础活动中对其进行调用:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(requestCode ==1){
        SignupFragment.MyOnRequestPermissionResult(requestCode, permissions, grantResults);
    }
}

它正在工作...

答案 9 :(得分:0)

确认PERMISSION_REQUEST_CODEonRequestPermissionsResult内的Fragment包含相同的值。

答案 10 :(得分:0)

对于tragetSDK 28,SDK检查(> 23)和来自片段的请求许可将起作用。 ActivityCompat.requestPermissions失败(如果将请求代码设置为65536以下,则会出现权限对话框,并且如果用户允许该权限,则会提供该权限,但不会发生回调。但是如果设置为65536以上,则ActivityCompat.requestPermissions将立即失败。我不知道此逻辑背后的原因。可能是错误或故意的。

工作代码:

  if (Build.VERSION.SDK_INT >= 23) {
                        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_ACCESS_REQUEST);
                    }

答案 11 :(得分:0)

如果您正在使用Kotlin,则应明确指定您正在调用片段方法,而不是活动

 fragment.requestPermissions(permissions, PERMISSIONS_CODE);

Android M Permissions: onRequestPermissionsResult() not being called

Request runtime permissions from v4.Fragment and have callback go to Fragment?

答案 12 :(得分:0)

我有同样的问题。您的片段可以从活动布局中初始化。 像这样:

main_activty.xml

<fragment
    android:id="@+id/fragment"
    android:name="com.exampe.SomeFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

当我改用FragmentTransaction时,这个问题为我解决了

答案 13 :(得分:0)

在低于23的API中,您可以在活动中创建一个接口,然后在子片段中实现该接口,当您获得权限请求结果时,该活动会将其传递到片段中的已实现接口。 这很简单:)

答案 14 :(得分:0)

您可以在下面调用Fragment方法

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case REQUEST_CODE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted. Continue the action or workflow
                // in your app.
                doActionBecauseNowYouCanBro();
            } else {
                // Explain to the user that the feature is unavailable because
                // the features requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
                showWhyRequestPermissionsAndDontBlockUserItsCalledManners();
            }
            return;
    }
    // Other 'case' lines to check for other
    // permissions this app might request.

}

答案 15 :(得分:-4)

此问题实际上是由NestedFragments引起的。基本上大多数片段我们扩展了一个HostedFragment,后者又扩展了CompatFragment。拥有这些嵌套的片段会导致最终由项目中的其他开发人员解决的问题。

他正在进行一些低级别的操作,例如位切换以使其工作,所以我不太确定实际的最终解决方案