NPE在引用服务中存在的变量时,由数据库初始化,以在活动中使用

时间:2012-03-06 17:50:48

标签: android service android-activity nullpointerexception sqliteopenhelper

与标题不同,我会尽量清楚,简明,尽可能地(希望这不是TL; DR)我知道标题很难理解,所以希望我的问题不会是。我有一个NPE,我无法在堆栈跟踪或调试模式(运行eclipse)中跟踪。堆栈跟踪指向一条线,但无论我改变什么,我似乎无法在不抛出NPE的情况下运行(我稍后会指出具体的线路)。所以我有一个Activity,一个SQLiteOpenHelper和一个Service。除了这三个类,我还将包含第四个类的片段,我的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(),这就是gremlins出现的地方。无论我做什么,我都无法让它发挥作用。出于某种原因使用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);
}

}

基本上,这让我想起了INSANE。我已经通过Android Docs阅读,直到我的眼睛流血。搜索谷歌。什么都没有点击我头脑中的灯光说“噢,那就是我做错了”同样(我之前问过这个问题,但它已经关闭了,因为我没有支持数据就问了)我想知道实例化我的服务之间的区别(如果有的话),将它声明为一个新变量(正如我在上面的活动中通过声明MyService fooService = new MyService())而不是像我在我的splash类中使用在这个问题的最开始意图。

他们有区别吗?我正在实例化它,因为如果我只是调用服务(即直接在我的Activity上面使用MyService.name而不是fooService.name)那么我必须将'name'变量设置为static ...这反过来意味着我必须将'dbHelper'设置为静态...哪个SQLiteHelper完全不同意(不能对sqliteopenhelper中的非静态方法进行静态引用)。

我希望这是足够的信息。如果需要,我可以在堆栈跟踪中包含一个pastebin,但是我必须警告你,我已经修改了上面的代码以使其适应,并更改了类和变量上的名称,以便它可以使更多在这种有限的背景下感觉。在一个nutt shell中,堆栈跟踪指向上述活动,然后指向MyService.init()行,然后指向(最终)服务中的name = DbHelper(ID,1)行。谢谢你的帮助!!!

编辑:在一个nutt-shell中,问题在于传递一个上下文以及你传递的是什么样的上下文。对于阅读此内容并且具有相同或类似问题的任何人:尝试更改传递给SQLiteOpenHelper的上下文。

1 个答案:

答案 0 :(得分:0)

修改

在进一步阅读后,我可能错了,因为服务是用上下文调用的?如果是这种情况,则很可能是您从不同的活动中调用您的服务,因此,当您从不同的活动中调用init()时,使用不同的活动的上下文。如果是这种情况,试试这个,

public class MyService extends Service {
    DBHandler dbHelper;

    public void init() {
        dbHelper = new DBHandler(this);
        dbHelper.getData(ID, 1);
    }
}

与我的其他答案相同,没有传递上下文


上下文 null ,因为未引用活动上下文

public class MyService extends Service {
    DBHandler dbHelper = new DBHandler(this);
}

尝试传递上下文:

public class MyService extends Service {
    DBHandler dbHelper;

    public void init(Context context)
    {
        dbHelper = new DBHandler(context);
        dbHelper.getData(ID, 1);
    }
}