Maison > Questions et réponses > le corps du texte
Débutants. Aujourd'hui, j'ai écrit un code pour passer d'une activité à l'autre, en utilisant une intention explicite, mais j'ai défini une variable membre d'intention dans la classe, et lorsque je l'ai utilisée dans la méthode, le programme s'est écrasé. Pourquoi ?
public class MusicPlay extends Activity{
//下面这一句初始化出了错误
public Intent intent=intent=new Intent(this,MusicServer.class);
....
Le code est comme ci-dessus, mais le message d'erreur est :
Causé par : java.lang.NullPointerException : tentative d'invocation de la méthode virtuelle 'java.lang.String android.content.Context.getPackageName()' sur une référence d'objet nulle
On dit qu'une erreur s'est produite lors de l'appel de la méthode virtuelle getPackageName() sur une "référence d'objet nulle".
Au début, je pensais que c'était vide et que c'était la cause du problème, j'ai donc modifié le code :
public class MusicPlay extends Activity{
Intent intent;
public MusicPlay(){
super();
if(this!=null){
intent=new Intent(this,MusicServer.class);
}
}
....
Mais l'erreur persiste et le message d'erreur est toujours le même. Grâce à un jugement conditionnel, je sais que ce n'est pas vide, alors pourquoi est-il encore considéré comme une référence nulle ?
phpcn_u15822017-05-16 13:37:09
Avant de faire cela, vous devez d'abord comprendre la relation entre
Activity
etContext
: Bien queActivity
hérite deContext
> , mais ce n'est pas la vraie classe d'implémentation. La vraie implémentation peut être la classe correspondant à l'objet renvoyéActivity
与Context
之间的关系: 虽然Activity
继承了Context
, 但是它却不是真正的实现类, 真正的实现可能是ContextWrapper#getBaseContext()
返回对象所对应的类.
Activity
是ContextWrapper
的子类, 所以我们先找到并打开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
est une sous-classe de ContextWrapper
, nous trouvons donc et ouvrons d'abord le code source de ContextWrapper.java
Le code clé est le suivant : 🎜
rrreee
🎜Les appels ContextWrapper
basés sur Context
utilisent directement mBase
pour implémenter l'appel indirectement. Ensuite, ce mBase
est quand. attribué ? Recherchez et ouvrez ActivityThread.java
, et vous pourrez trouver la partie du code où il a été attribué. Le code clé est le suivant : 🎜
rrreee
🎜D'après ce qui précède, on peut voir que : lors de l'instanciation de Activity
, ContextWrapper#getBaseContext()
renvoie null Par conséquent, il ne peut pas être appelé directement dans le constructeur ou lors de la construction. variables membres avec Instanciation de toutes les fonctions et classes liées au Contexte
Si nécessaire, appelez-le dans sa fonction de cycle de vie.🎜.伊谢尔伦2017-05-16 13:37:09
Votre classe hérite de la classe Activity, elle a donc un cycle de vie, et toute la logique est exécutée dans ces cycles de vie. En d'autres termes, votre code logique doit être écrit dans les méthodes de ces cycles de vie. méthode onCreate et écrivez des sauts de page là-bas. Le nom de l'identifiant de votre méthode n'est pas non plus standardisé
.