Android测试API应用启动崩溃排查求助(新手开发者)
问题:API测试应用启动崩溃排查
我是一名新手开发者,当前出现问题的是一款API测试应用,基于GitHub上jkutner的教程实现。此前我曾三次使用完全相同的代码且均能正常运行,但现在应用一启动就崩溃。以下是相关代码及Logcat信息,恳请协助排查问题!
MainActivity代码
package com.example.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import java.util.List; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class MainActivity extends AppCompatActivity { final EditText isbnInput = (EditText) findViewById(R.id.isbnInput); final TextView textView = (TextView) findViewById(R.id.textView); final Button button = (Button) findViewById(R.id.button); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://venusdove.herokuapp.com") .addConverterFactory(GsonConverterFactory.create()) .build(); final BookService service = retrofit.create(BookService.class); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Book book = new Book(isbnInput.getText().toString()); Call<Book> createCall = service.create(book); createCall.enqueue(new Callback<Book>() { @Override public void onResponse(Call<Book> _, Response<Book> resp) { Book newBook = resp.body(); textView.setText("Created Book with ISBN: " + newBook.isbn); } @Override public void onFailure(Call<Book> _, Throwable t) { t.printStackTrace(); textView.setText(t.getMessage()); } }); } }); } }
Book类代码
package com.example.myapplication; import com.google.gson.annotations.SerializedName; public class Book { @SerializedName("id") int id; @SerializedName("isbn") String isbn; public Book(int id, String isbn) { this.id = id; this.isbn = isbn; } public Book(String isbn) { this.isbn = isbn; } }
BookService接口代码
package com.example.myapplication; import java.util.List; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Path; public interface BookService { @GET("books") Call<List<Book>> all(); @GET("books/{isbn}") Call<Book> get(@Path("isbn") String isbn); @POST("books/new") Call<Book> create(@Body Book book); }
Logcat错误信息
2022-10-19 08:56:03.651 8041-8041/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.myapplication, PID: 8041 java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.myapplication/com.example.myapplication.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2679) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:152) at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:157) at android.content.Context.obtainStyledAttributes(Context.java:655) at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:852) at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:819) at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:640) at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:261) at com.example.myapplication.MainActivity.<init>(MainActivity.java:22) at java.lang.Class.newInstance(Native Method) at android.app.Instrumentation.newActivity(Instrumentation.java:1174) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2669) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
问题分析与修复
崩溃原因
错误日志明确显示,findViewById调用在MainActivity的构造阶段执行,此时Activity的上下文还未初始化,调用findViewById会触发空指针异常。
在Android Activity生命周期中,findViewById必须在setContentView之后调用——只有加载布局文件后,视图控件才会被实例化,才能通过ID找到对应的控件。你之前把控件初始化放在类成员变量的位置,这会在Activity对象创建时就执行,早于onCreate里的setContentView,所以必然崩溃。
修改后的MainActivity代码
package com.example.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class MainActivity extends AppCompatActivity { // 仅声明控件变量,不初始化 EditText isbnInput; TextView textView; Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 在setContentView之后初始化所有控件 isbnInput = findViewById(R.id.isbnInput); textView = findViewById(R.id.textView); button = findViewById(R.id.button); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://venusdove.herokuapp.com") .addConverterFactory(GsonConverterFactory.create()) .build(); final BookService service = retrofit.create(BookService.class); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Book book = new Book(isbnInput.getText().toString()); Call<Book> createCall = service.create(book); createCall.enqueue(new Callback<Book>() { @Override public void onResponse(Call<Book> _, Response<Book> resp) { Book newBook = resp.body(); // 增加空判断,避免服务器返回空响应时崩溃 if (newBook != null) { textView.setText("Created Book with ISBN: " + newBook.isbn); } else { textView.setText("Failed to retrieve book data"); } } @Override public void onFailure(Call<Book> _, Throwable t) { t.printStackTrace(); textView.setText(t.getMessage()); } }); } }); } }
额外优化说明
- 移除控件变量的
final修饰符:在onCreate中初始化后,后续使用不会有问题,去掉final更灵活。 - 添加
resp.body()空判断:网络请求成功时,服务器可能返回空响应,直接访问newBook.isbn会触发新的空指针异常,添加判断提升应用稳定性。
内容的提问来源于stack exchange,提问作者Laurão etc
相关产品推荐
相关产品推荐

