Pepijat Android - Dalam Android, mengapakah permulaan niat tidak boleh ditulis di luar kaedah?
伊谢尔伦
伊谢尔伦 2017-05-16 13:35:09
0
3
938

Pemula. Hari ini saya menulis kod untuk melompat antara aktiviti, menggunakan niat eksplisit, tetapi saya mentakrifkan pembolehubah ahli niat dalam kelas, dan apabila saya menggunakannya dalam kaedah, program itu ranap Mengapa ini?

public class MusicPlay extends Activity{
    //下面这一句初始化出了错误
    public Intent intent=intent=new Intent(this,MusicServer.class);
    ....

Kod adalah seperti di atas, tetapi mesej ralat ialah:

Disebabkan oleh: java.lang.NullPointerException: Percubaan untuk menggunakan kaedah maya 'java.lang.String android.content.Context.getPackageName()' pada rujukan objek nol

Dikatakan bahawa ralat berlaku semasa memanggil kaedah maya getPackageName() pada "rujukan objek nol".

Pada mulanya, saya fikir ini kosong dan menyebabkan masalah, jadi saya mengubah suai kod:


public class MusicPlay extends Activity{
    Intent intent;
    public MusicPlay(){
        super();
        if(this!=null){
            intent=new Intent(this,MusicServer.class);
        }
    }
    ....

Tetapi ralat masih berlaku dan mesej ralat masih sama. Melalui penghakiman bersyarat, saya tahu bahawa ini tidak kosong, jadi mengapa ia masih dikatakan sebagai rujukan batal?

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

membalas semua(3)
phpcn_u1582

Sebelum melakukan ini, anda mesti terlebih dahulu memahami hubungan antara Aktiviti dan Context: Walaupun Aktiviti mewarisi Context > , tetapi ia bukan kelas pelaksanaan sebenar Pelaksanaan sebenar mungkin kelas yang sepadan dengan objek yang dikembalikan ActivityContext之间的关系: 虽然Activity继承了Context, 但是它却不是真正的实现类, 真正的实现可能是ContextWrapper#getBaseContext()返回对象所对应的类.

ActivityContextWrapper的子类, 所以我们先找到并打开ContextWrapper.java源码, 关键代码如下:

public class ContextWrapper extends Context {
    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    
    ... ...
    
    /**
     * @return the base context as set by the constructor or setBaseContext
     */
    public Context getBaseContext() {
        return mBase;
    }

    @Override
    public AssetManager getAssets() {
        return mBase.getAssets();
    }

    @Override
    public Resources getResources() {
        return mBase.getResources();
    }

    ... ...

ContextWrapper里基于Context的调用都是直接使用mBase来间接实现调用的. 那么这个mBase是什么时候被赋值的呢? 找到并打开ActivityThread.java, 就能找到它被赋值的代码部分, 关键代码如下:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

    ... ...

    // -------------------------------------------------------------------
    // 创建Activity实例
    // -------------------------------------------------------------------
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());

        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            
            // -------------------------------------------------------------------
            // 设置 appContext 为Activity 的 BaseContext
            // -------------------------------------------------------------------
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window);

以上, 可知: 实例化Activity时, ContextWrapper#getBaseContext()返回的是null, 因此, 不能在构造函数或者构造成员变量时直接调用与Context

Aktiviti ialah subkelas ContextWrapper, jadi kami mula-mula mencari dan membuka kod sumber ContextWrapper.java Kod utama adalah seperti berikut: 🎜 rrreee 🎜ContextWrapper panggilan berdasarkan Context terus menggunakan mBase untuk melaksanakan panggilan secara tidak langsung Kemudian mBase ini ialah Bilakah ia ditugaskan? Cari dan buka ActivityThread.java, dan anda boleh mencari bahagian kod di mana ia ditetapkan Kod kunci adalah seperti berikut: 🎜 rrreee 🎜Daripada perkara di atas, dapat dilihat bahawa: apabila menginstant Aktiviti, ContextWrapper#getBaseContext() mengembalikan nol Oleh itu, ia tidak boleh dipanggil secara langsung dalam pembina atau semasa membina pembolehubah ahli dengan Instansiasi mana-mana fungsi dan kelas yang berkaitan denganKonteks Jika perlu, panggilnya dalam fungsi kitaran hayatnya.🎜
伊谢尔伦

Kelas anda mewarisi kelas Aktiviti, kemudian ia mempunyai kitaran hayat, dan semua logik dijalankan dalam kitaran hayat ini, dengan kata lain, kod logik anda mesti ditulis dalam kaedah kitaran hayat tersebut onCreate kaedah dan tulis lompat halaman di sana Penamaan pengecam kaedah anda juga tidak diseragamkan

Peter_Zhu

Anda perlu mengatasi kaedah onCreate()

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan