为什么我会为一个sceanrio而不是类似的sceanrio获得空指针异常?

时间:2016-03-02 23:38:24

标签: java android listview

我发现令人困惑的问题是两种类似的情况,可以描述为: -

在具有ListView的活动中,我单击一个项目,该项目启动另一个活动来编辑该项目。在辅助活动中,在编辑项目并将更改保存到数据库之后,我需要通过交换光标来刷新ListView。

在一个我使用以下(这没有空指针): -

    Cursor csr = shopperdb.getProductsperAisle(aisleid);
    View v = findViewById(R.id.aapts_layout);
    ListView lv = (ListView) v.findViewById(R.id.aaptslv100);
    ProductsPerAisleCursorAdapter adapter = (ProductsPerAisleCursorAdapter) lv.getAdapter();
    adapter.swapCursor(csr);
    finish();
  • 上面的代码位于名为 ProductUsageEdit 的活动中,该活动使用 activity_productusage_edit.xml 并将其设置为ContentView。

  • ListView aaptslv100 位于 activity_shop_add.xml中定义的 aapts_layout 活动 AddProductToShopActivity 将aapts_layout设置为内容查看。当点击ListView aaptslv100 中的项目时,此活动将启动 ProductUsageEdit 活动。

  • R.id.aapts_layout 是主要布局的ID, R.id.aaptslv100 是该布局中ListView的ID。此代码通过按钮的OnClickListener调用。

另一种情况,如果使用等效的,即从布局ID获取初始活动的视图,然后通过该V获取ListView的ID;发出一个nullpointer异常(仍导致ListView被刷新),即使用: -

    View v = findViewById(R.id.aslbc_layout);
    ListView callerListView = (ListView) v.findViewById(R.id.aslbclv01);
    ....

而是在第二个sceanrio中,为了得不到空指针异常我编码: -

    Cursor csr = shopperdb.getShopsAsCursor();
    ListView callerListView = (ListView) findViewById(R.id.aslbclv01);
    ShopsCursorAdapter calleradapter = (ShopsCursorAdapter)callerListView.getAdapter();
    calleradapter.changeCursor(csr);
  • 上面的代码位于 ShopAddActivity ,使用来自 asListb 的活动 ShopListByCursorActivity 中的ListView aslbclv01 来自 aslbc_layout > activity_shop_list_by_cursor.xml 即可。

(显然,Listview与使用的适配器和获得的游标不同,ps finish()稍后在此代码所在的If子句之外编码。)

如果我在第一个场景中尝试使用相同的东西,那么我会得到一个空指针异常(然后再次刷新ListView)。

我喜欢的是一种适用于其他类似情况的标准方法。我也非常理解为什么我似乎需要在基本相同的场景中使用不同的方法。

(添加)

考虑到这一点,两种情况之间存在差异;

第一个被称为次要活动的sceanrio具有更复杂的布局。因为它是一个带有嵌套LinearLayouts的LinearLayout,然后是Text / EditViews。

第二个场景使用RelativeLayout,视图全部驻留在RelativeLayout之下。

这可能是需要获取原始布局ID吗?

但是,如果是这种情况,它仍然会让我思考为什么View v = findViewById(<orginatingLayout>)在不太复杂的第二种情况下将v设置为null。也许findByView对viewtype敏感?

2 个答案:

答案 0 :(得分:1)

要按ID成功查找视图实例,首先必须确保为Activity / Fragment实例设置了正确的布局。活动的findViewById(),AFAIK,查找与给定id具有相同id的顶级父节点的子视图。它不会以嵌套ViewGroup递归查找视图。 ViewGroup是View的后代,充当一个或多个视图的容器。 LinearLayoutRelativeLayout是ViewGroup的几个示例。

因此,如果您有以下布局:

RES /布局/ activity_main.xml中

<RelativeLayout 
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
     tools:context="com.juhara.demo.intent1.MainActivity" >

   <Button
       android:id="@+id/btn_start"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/str_btn1" />
</RelativeLayout>

在活动的OnCreate()内,您可以调用

setContentView(R.layout.activity_main);

然后您可以通过调用Activity的Button来成功获取findViewById()实例

Button abutton = (Button) findViewById(R.id.btn_start);

但是,如果您有嵌套布局,例如

RES /布局/ activity_main2.xml

<RelativeLayout 
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:paddingBottom="@dimen/activity_vertical_margin"
     android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin" >

    <RelativeLayout 
       android:id="@+id/button_container"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:paddingBottom="@dimen/activity_vertical_margin"
       android:paddingLeft="@dimen/activity_horizontal_margin"
       android:paddingRight="@dimen/activity_horizontal_margin"
       android:paddingTop="@dimen/activity_vertical_margin" >
        <Button
           android:id="@+id/btn_start"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@string/str_btn1" />
     </RelativeLayout>
</RelativeLayout>

然后代码将abutton设置为null。

setContentView(R.layout.activity_main2);
Button abutton = (Button) findViewById(R.id.btn_start);

要正确获取Button实例,您必须首先找到Button的父节点,然后使用它来查找视图。

setContentView(R.layout.activity_main2);
View button_container = findViewById(R.id.button_container);
Button abutton = (Button) button_container.findViewById(R.id.btn_start);

答案 1 :(得分:0)

经过多次尝试获取ListView的适配器(swapCursor()changeCursor()notifyDataSetChanged()所需)。这包括尝试通过Intent传递对象(序列化问题)。我尝试了 onResume ,并带有一个标志,指示应该触发onResume的原因。所以现在,至少,试图检索另一个活动的布局元素对我的经验水平来说太难了。

对于第一种情况(将会看第二种情况)。

我的最终代码,至少其中很大一部分,我认为可以被我自己采纳/改编为标准: -

在更新数据的辅助活动中根本没有代码(关于交换错误)。

在调用第二个活动的主要活动中: -

public final static int RESUMESTATE_NOTHING = 0;
public final static int RESUMESTATE_PRODUCTUSAGEEDIT = 1;
public final static String[] RESUMESTATE_DESCRIPTIONS = {"Nothing","ProductUsageEdit"};

public int resume_state = RESUMESTATE_NOTHING;
public long currentshopid = -1;
public long currentaisleid = -1;
public ProductsPerAisleCursorAdapter currentppaca;

protected void onResume() {
    super.onResume();
    Log.i(Constants.LOG," onResume invoked in " + THIS_ACTIVITY + "-  Current State=" + resume_state + "-"+RESUMESTATE_DESCRIPTIONS[resume_state]);
    switch (resume_state) {
        case RESUMESTATE_NOTHING: {
            break;
        }
        case RESUMESTATE_PRODUCTUSAGEEDIT: {
            Cursor csr = shopperdb.getProductsperAisle(currentaisleid);
            currentppaca.swapCursor(csr);
            resume_state = RESUMESTATE_NOTHING;
            break;
        }
    }
}

在调用第二个活动的相应onClickListener中使用以下内容: -

resume_state = RESUMESTATE_PRODUCTUSAGEEDIT;
currentppaca = adapterpl;
currentaisleid = aisleid;
currentshopid = shopid;