タイトルとは異なり、できるだけ明確、簡潔、そして要点を明確にするように努めます (これが TL;DR ではないことを願っています)。スタック トレースまたはデバッグ モード (Eclipse の実行中) で追跡できない NPE があります。スタック トレースは行を指していますが、何を変更しても、NPE をスローしないと実行できないようです (後で特定の行を指摘します)。つまり、Activity、SQLiteOpenHelper、および Service があります。これら 3 つのクラスに加えて、4 番目のクラスである Splash クラスのスニペットを含めます。前述のサービスは、このコードを使用して Splash クラスを介して開始されます (これを含めた理由については後で説明します)。
startService(new Intent(getApplicationContext(), MyService.class));
先に進む前に、MyService.class の変数 "ID" が別のアクティビティによって設定されていることを指摘しておくことが重要です。これについてはここでは説明しません。変数が正しく設定されること、ユーザーが変更すると正しく変更されること、そしてコードのさまざまなポイントに Log.I(TAG, TEXT) ステートメントを配置して、それが機能し、データが全体を通して一貫性を保ちます。また、サービスが正しく開始されていることも確認したので、これも問題ではありません。先に進みます。後で参照する SQLiteOpenHelper クラスのメソッドを次に示します (関連する情報のみを含めるように、コードを可能な限り削減しました)。
public class DBHandler extends SQLiteOpenHelper {
private static final String _ID = "_id";
private final String KEY_NAME = "name";
public String getData(String ID, int pos) {
String clause = _ID + " = " + ID;
Cursor cr = null;
String result = "";
cr = getReadableDatabase().query(DB_T, columns1, clause, null, null, null, null);
if (cr != null) {
cr.moveToFirst();
result = cr.getString(pos);
}
close();
return result;
}
}
コード内の他の多くのポイントから問題なく呼び出すことができるため、データベース ハンドラーが正しく動作することを確認しました。この特定の方法も毎回機能します (実際、クラス全体が確実に機能します...この NPE がポップアップする場合を除きます)。テーブル内のデータは、省略した DB クラスの一部で初期化されます。そのすべてが同様に機能することを確認しました。したがって、先に進むには、アプリケーションのすべてのポイントでデータベース クラスが問題なく動作すると想定してください。ただし、後で説明する行を除きます。次に、次のようなサービス クラスがあります (問題のある行はここにあります。すぐに指摘します)。
public class MyService extends Service {
DBHandler dbHelper = new DBHandler(this);
public static String ID = "1";
String name = "";
@Override
public void onCreate() {
super.onCreate();
init();
}
public void init() {
name = dbHelper.getData(ID, 1);
}
}
メソッド「public void init()」では、NPE は「name = dbHelper.getData(ID, 1);」を指しています。この EXACT コード行は、アプリケーションの他の場所で使用でき、問題なく動作しますが、ここでは何度も何度も失敗します。最後に、このデータを取得するためにサービスを呼び出すアクティビティがあります。以下では、MyService.init() を呼び出しますが、ここでグレムリンが出てきます。私が何をしても、これを機能させることはできません。何らかの理由で name = dbHelper.getData(ID, 1); を使用しています。このようにして、ガスケットを吹き飛ばします。
public class ActivityInteract extends Activity implements OnClickListener {
MyService fooService = new MyService();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyService.init();
interactInit();
}
private void interactInit() {
setContentView(R.layout.g_interact);
nameText.setText(fooService.name);
}
}
基本的に、これは私を非常識にしています。目が充血するまで Android ドキュメントを読みました。グーグルを磨いた。頭の中のライトをクリックして、「ああ、それは私が間違っていることです」と言っている場所は何もありませんまた(以前にこの質問をしましたが、データを裏付けずに尋ねたので閉じられました)知りたいです新しい変数として宣言することによるサービスのインスタンス化 (MyService fooService = new MyService() を宣言することによって上記のアクティビティで行ったように) と、スプラッシュ クラスで行ったようにサービスを開始することの違い (ある場合)この質問の最初の意図。
それらの違いはありますか?サービスを呼び出すだけの場合 (つまり、すぐ上のアクティビティで fooService.name の代わりに MyService.name を使用する場合)、「name」変数を static に設定する必要があるため、インスタンス化しています。 「dbHelper」を静的に設定する必要があります... SQLiteHelperはまったく同意しません(sqliteopenhelperで非静的メソッドへの静的参照を作成できません)。
これで十分な情報だと思います。必要に応じて、スタック トレースにペーストビンを含めることができますが、警告する必要があります。上記のコードは、収まるようにかなり削除し、クラスと変数の名前を変更して、より多くの情報を作成できるようにしました。この限られた文脈での意味。Nutt シェルでは、スタック トレースは上記のアクティビティをポイントし、次に MyService.init() 行をポイントし、それは (最終的に) サービスの name = DbHelper(ID, 1) 行をポイントします。助けてくれてありがとう!!!
編集:ナットシェルでは、問題はコンテキストを渡すことと、渡すコンテキストの種類にあります。これを読んでいて、同じまたは同様の問題を抱えている人へ: SQLiteOpenHelper に渡すコンテキストを変更してみてください。