Rumah > Soal Jawab > teks badan
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?
phpcn_u15822017-05-16 13:37:09
Sebelum melakukan ini, anda mesti terlebih dahulu memahami hubungan antara
Aktiviti
danContext
: WalaupunAktiviti
mewarisiContext
> , tetapi ia bukan kelas pelaksanaan sebenar Pelaksanaan sebenar mungkin kelas yang sepadan dengan objek yang dikembalikanActivity
与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
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 伊谢尔伦2017-05-16 13:37:09
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