簡體   English   中英

未找到加載的動態功能的主要活動類

[英]Main activity class of loaded Dynamic feature is not found

我正在嘗試向我的應用程序添加動態功能支持,因此我創建了一個測試應用程序。

測試應用程序有一個主應用程序部分,用於加載動態功能並嘗試執行它。

功能模塊將 MainActivityCalled 作為主要活動。

我得到的是功能加載過程有效,因為我收到了成功的日志消息,並且我得到了已安裝模塊的列表。

請注意,該應用程序是在虛擬設備上運行的,並沒有發生真正的下載,我認為一切都是通過 AndroidStudio 的部署過程自動安裝的。

事實是,我在嘗試調用模塊的主要活動時遇到這種錯誤:

W/System.err: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.dynamicfeature1/MainActivityCalled}; have you declared this activity in your AndroidManifest.xml?
W/System.err:     at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1805)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523)
    at android.app.Activity.startActivityForResult(Activity.java:4225)
    at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767)
    at android.app.Activity.startActivityForResult(Activity.java:4183)
    at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754)
    at android.app.Activity.startActivity(Activity.java:4522)
    at android.app.Activity.startActivity(Activity.java:4490)
    at com.example.mymodules.MainActivity$2.onClick(MainActivity.java:227)
    at android.view.View.performClick(View.java:5637)
    at android.view.View$PerformClick.run(View.java:22429)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)

一切都按照https://developer.android.com/guide/app-bundle/playcore#java上的文檔完成,除了我猜測必須以意圖執行的對模塊活動的顯式調用(沒有示例上面鏈接的頁面)。

您在下面找到的代碼的重要部分是:

new OnSuccessListener<Integer>() {
                        @Override
                        public void onSuccess(Integer result) {
                            Log.d("request feature load","success "+result);
                            mySessionId=result;
                            Set<String> installedModules = splitInstallManager.getInstalledModules();
                            String[] modules = new String[installedModules.size()];

                            installedModules.toArray(modules);
                            for (int i=0;i<modules.length;i++)
                            {
                                Log.d("module",modules[i]);
                            }


                        }
                    })

那沒問題。

然后

Button button2 = findViewById(R.id.fab2);
    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {



            Log.d("feature1","called");
            Intent intent=new Intent();
            intent.setClassName("com.example.dynamicfeature1","MainActivityCalled");

            try{  startActivity(intent);}
            catch (Exception e){
                e.printStackTrace();
            }

        }
    });

所有主要活動都有這個覆蓋的方法

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this);
    Log.d("attachBaseContext",base.getPackageName().toString());
}

安裝時不會在動態功能模塊中調用。

我的代碼有什么問題?

這是應用程序的主要活動

package com.example.mymodules;

...imports...

public class MainActivity extends AppCompatActivity {
private static int MY_REQUEST_CODE=1;
Activity activity;
int mySessionId;

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this);
 Log.d("attachBaseContext",base.getPackageName().toString());

}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == MY_REQUEST_CODE) {
        // Handle the user's decision. For example, if the user selects "Cancel",
        // you may want to disable certain functionality that depends on the module.
    }
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    activity = this;
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    Button button1 = findViewById(R.id.button1);
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            // Creates an instance of SplitInstallManager.
            final SplitInstallManager splitInstallManager =
                    SplitInstallManagerFactory.create(activity);

// Creates a request to install a module.
            SplitInstallRequest request =
                    SplitInstallRequest
                            .newBuilder()
                            // You can download multiple on demand modules per
                            // request by invoking the following method for each
                            // module you want to install.
                            .addModule("dynamicfeature1")

                            .build();

// Creates a listener for request status updates.
            SplitInstallStateUpdatedListener listener =new SplitInstallStateUpdatedListener() {
                @Override
                public void onStateUpdate(SplitInstallSessionState state) {
                    if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
                        // Displays a dialog for the user to either “Download”
                        // or “Cancel” the request.
                        try {
                            splitInstallManager.startConfirmationDialogForResult(
                                    state,
                                    /* activity = */ activity,
                                    // You use this request code to later retrieve the user's decision.
                                    /* requestCode = */ MY_REQUEST_CODE);
                        } catch (IntentSender.SendIntentException e) {
                            e.printStackTrace();
                        }
                    }

                    if (state.sessionId() == mySessionId) {
                        switch (state.status()) {

                            case SplitInstallSessionStatus.INSTALLED:
                                Context tempNewContext=null;
                                try {
                                    tempNewContext = activity.createPackageContext(activity.getPackageName(), 0);
                                } catch (PackageManager.NameNotFoundException e) {

                                }
                                final Context newContext =tempNewContext;
                                // If you use AssetManager to access your app’s raw asset files, you’ll need
                                // to generate a new AssetManager instance from the updated context.
                                AssetManager am = newContext.getAssets();


                                if (BuildCompat.isAtLeastO()) {
                                    // Updates the app’s context with the code and resources of the
                                    // installed module.
                                    SplitInstallHelper.updateAppInfo(newContext);
                                    new Handler().post(new Runnable() {
                                        @Override public void run() {
                                            // Loads contents from the module using AssetManager
                                            AssetManager am = newContext.getAssets();

                                        }
                                    });
                                } else
                                {SplitInstallHelper.updateAppInfo(newContext);}

                        }
                    }
                }

            } ;
            splitInstallManager.registerListener(listener);
            splitInstallManager
                    // Submits the request to install the module through the
                    // asynchronous startInstall() task. Your app needs to be
                    // in the foreground to submit the request.
                    .startInstall(request)
                    // You should also be able to gracefully handle
                    // request state changes and errors. To learn more, go to
                    // the section about how to Monitor the request state.
                    .addOnSuccessListener(new OnSuccessListener<Integer>() {
                        @Override
                        public void onSuccess(Integer result) {
                            Log.d("request feature load","success "+result);
                            mySessionId=result;
                            Set<String> installedModules = splitInstallManager.getInstalledModules();
                            String[] modules = new String[installedModules.size()];

                            installedModules.toArray(modules);
                            for (int i=0;i<modules.length;i++)
                            {
                                Log.d("module",modules[i]);
                            }


                        }
                    })
                    .addOnFailureListener(new OnFailureListener() {
                        void checkForActiveDownloads() {
                            splitInstallManager
                                    // Returns a SplitInstallSessionState object for each active session as a List.
                                    .getSessionStates()
                                    .addOnCompleteListener(
                                            new OnCompleteListener<List<SplitInstallSessionState>>() {
                                                @Override
                                                public void onComplete(Task<List<SplitInstallSessionState>> task) {
                                                    if (task.isSuccessful()) {
                                                        // Check for active sessions.
                                                        for (SplitInstallSessionState state : task.getResult()) {
                                                            if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {
                                                                // Cancel the request, or request a deferred installation.
                                                            }
                                                        }
                                                    }
                                                }


                                            });
                        }

                        @Override
                        public void onFailure(Exception e) {
Log.d("request feature load","failure "+e.getMessage());
                            switch (((SplitInstallException) e).getErrorCode()) {
                                case SplitInstallErrorCode.NETWORK_ERROR:
                                    // Display a message that requests the user to establish a
                                    // network connection.
                                    break;
                                case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED:
                                    checkForActiveDownloads();
                            }

                        }
                    });




        }
    });
   Button button2 = findViewById(R.id.button2);
    button2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d("feature1","called");
 Intent intent=new Intent();
            intent.setClassName("com.example.dynamicfeature1","MainActivityCalled");

            try{  startActivity(intent);}
            catch (Exception e){
                e.printStackTrace();
            }

        }
    });
   Button button3 = findViewById(R.id.button3);
    button3.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.d("feature2","called");
        }
    });
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}



@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

這是主應用程序清單

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.example.mymodules">

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:name="com.google.android.play.core.splitcompat.SplitCompatApplication"
android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

</application>
</manifest>

然后是動態特征模塊的MainActivity

package com.example.dynamicfeature1;

...imports...

public class MainActivityCalled extends AppCompatActivity {
@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this);
    Log.d("attachBaseContext",base.getPackageName().toString());
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "1-Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });
}

}

和模塊清單

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.example.dynamicfeature1">

<dist:module
    dist:instant="false"
    dist:title="@string/title_dynamicfeature1">
    <dist:delivery>
        <dist:on-demand />
    </dist:delivery>

    <dist:fusing dist:include="false" />
</dist:module>

<application>
    <activity
        android:name=".MainActivityCalled"
        android:label="@string/title_activity_main"
        android:theme="@style/AppTheme.NoActionBar"></activity>
</application>

</manifest>

調用活動的正確指令是

intent. setClassName(BuildConfig.APPLICATION_ID, "com.example.dynamicfeature.MainActivityCalled");

它有效,活動被調用。

請注意 BuildConfig.APPLICATION_ID 是

com.example.mymodules

如果此字符串也用於動態模塊中,則可以進行交叉調用:

- 從一個模塊到另一個模塊

- 從一個模塊到主應用程序

但是你不想在模塊中使用 BuildConfig.APPLICATION_ID 因為它有一個不同的值,所以主字符串值必須放入一個變量中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM