Android-Fehler – Warum kann in Android die Intent-Initialisierung nicht außerhalb der Methode geschrieben werden?
伊谢尔伦
伊谢尔伦 2017-05-16 13:35:09
0
3
916

Anfänger. Heute habe ich einen Code geschrieben, um mit expliziter Absicht zwischen Aktivitäten zu springen, aber ich habe eine Absichts-Mitgliedsvariable in der Klasse definiert, und als ich sie in der Methode verwendet habe, ist das Programm abgestürzt. Warum ist das so?

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

Der Code ist wie oben, aber die Fehlermeldung lautet:

Verursacht durch: java.lang.NullPointerException: Versuch, die virtuelle Methode „java.lang.String android.content.Context.getPackageName()“ aufzurufen auf einer Nullobjektreferenz

Es wird gesagt, dass beim Aufruf der virtuellen Methode getPackageName() für eine „Null-Objektreferenz“ ein Fehler aufgetreten ist.

Zuerst dachte ich, dass dies leer sei und das Problem verursachte, also habe ich den Code geändert:


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

Aber der Fehler tritt immer noch auf und die Fehlermeldung ist immer noch dieselbe. Durch bedingte Beurteilung weiß ich, dass dies nicht leer ist. Warum wird es dann immer noch als Nullreferenz bezeichnet?

伊谢尔伦
伊谢尔伦

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

Antworte allen(3)
phpcn_u1582

这么做之前, 先要了解清楚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相关的任何函数和类的实例化. 如果需要, 则在其生命周期函数中去调用.

伊谢尔伦

你的类继承了Activity类,那么它就有生命周期,所有逻辑都在这几个生命周期里面进行,换而言之,你的逻辑代码都要写在那几个生命周期的方法里面.一般来说,都是重写onCreate的方法,在那里面写页面跳转.你的方法的标识符命名也不规范

Peter_Zhu

要重写onCreate()方法啊

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage