Android - 使用自定义布局时,带有NullPointerException的getListView和setListAdapter错误

时间:2011-03-01 19:06:32

标签: android listview android-layout listactivity

我有这样的布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:orientation="vertical"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:background="#ffffff">

    <com.ftni.core.ui.ActionBar
        android:id="@+id/actionbar"
        style="@style/ActionBar"/>

    <TextView android:id="@+id/list_title"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:text="Title"
         android:textStyle="bold"
         android:textColor="#000000"
         android:textSize="18sp"
         android:padding="3px"/>

     <ListView android:id="@id/android:list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_weight="1"
         android:drawSelectorOnTop="false"/>
</LinearLayout>

并在我的listview中(在更改布局之前工作的代码)

private void buildListView()
{
    ListView lv = getListView();

    registerForContextMenu(lv);

    lv.setTextFilterEnabled(true);

    lv.clearChoices();

    setListAdapter(new UserListAdapter(SuspendedUsersActivity.this, R.layout.useritem, users));

    lv.setOnItemClickListener(clickListener);
}

我首先尝试将调用移到setListAdapter,但我仍然得到NullPointerException。这是logcat

FATAL EXCEPTION: main
java.lang.NullPointerException
at android.app.ListActivity.setListAdapter(ListActivity.java:267)
at com.myapp.backoffice.users.SuspendedUsersActivity.buildListView(SuspendedUsersActivity.java:140)
at com.myapp.backoffice.users.SuspendedUsersActivity.access$0(SuspendedUsersActivity.java:138)
at com.myapp.backoffice.users.SuspendedUsersActivity$2.handleMessage(SuspendedUsersActivity.java:194)
at android.os.Handler.dispatchMessage(Handler.java:99)

我感觉发生的事情是我告知的默认ID是正确的(@id/android:list)对于默认列表视图是不正确的。

编辑:

以下是有关我如何设置的详细信息。

首先,我有一个继承的活动,以确保用户通过身份验证。当我直接从这个类继承时,一切正常。

public class ProtectedListActivity extends ListActivityBase {
    boolean isAuthenticated = false;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Thread validationThread = new Thread()
        {
            @Override
            public void run() 
            {
                try
                {
                    isAuthenticated = UserService.ValidateToken();
                }
                catch (FTNIServiceException e)
                {
                    //eat it
                }
                finally 
                {
                    if (!isAuthenticated)
                    {
                        startActivity(new Intent(ProtectedListActivity.this, SignInActivity.class));
                        finish();
                    }
                }
            }
        };

        validationThread.start();
    }
}

然后,我进一步扩展了将默认操作栏设置包装到基类中。

public class ListWithActionBarActivity extends ProtectedListActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onContentChanged()
    {
        ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);
        if (actionBar != null)
        {
            actionBar.setOnTitleClickListener(new OnClickListener() {
                public void onClick(View v) {
                    startActivity(new Intent(ListWithActionBarActivity.this, SelectSiteActivity.class));
                    finish();
                }
            });

            SiteModel site = PreferencesHelper.getSite();

            actionBar.setTitle(site.Name + " (" + site.Abbreviation + ")");
            actionBar.addAction(new IntentAction(ListWithActionBarActivity.this, 
                    new Intent(ListWithActionBarActivity.this, MainMenuActivity.class), 
                    R.drawable.ic_title_home_default));
        }
    }

    public static Intent createIntent(Context context) {
        Intent i = new Intent(context, MainMenuActivity.class);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        return i;
    }

    protected Intent createShareIntent() {
        final Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT, "Shared from the ActionBar widget.");
        return Intent.createChooser(intent, "Share");
    }
}

然后,因为我有两个按状态分隔的用户列表(暂停或活动),我试图在基类中包含一个添加到操作栏。

public class UserBase extends ListWithActionBarActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        //setContentView(R.layout.queue);
        super.onCreate(savedInstanceState);

        ActionBar actionBar = (ActionBar)findViewById(R.id.actionbar);

        actionBar.addAction(new UserStatusSelectorAction(UserBase.this));

    }
}

最后,我们有了自己的活动。我省略了一些代码,但是我离开了大部分代码,这样你就可以看到在显示加载屏幕时如何通过另一个线程检索数据,然后构建listview。

public class SuspendedUsersActivity extends ListWithActionBarActivity implements Runnable{
    ProgressDialog progress;
    ArrayList<UserModel> users;
    int position;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.queue);
        super.onCreate(savedInstanceState);

        TextView title = (TextView)findViewById(R.id.list_title);
        title.setText("Suspended Users");

        progress = ProgressDialog.show(SuspendedUsersActivity.this, "", "Loading...", true);

        Thread thread = new Thread(SuspendedUsersActivity.this);
        thread.start();
    }

    private void buildListView()
    {
        ListView lv = getListView();

        //registerForContextMenu(lv);

        lv.setTextFilterEnabled(true);

        lv.clearChoices();

        setListAdapter(new UserListAdapter(SuspendedUsersActivity.this, R.layout.useritem, users));

        lv.setOnItemClickListener(clickListener);
    }

    private OnItemClickListener clickListener = new OnItemClickListener()
    {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            UserModel user = users.get(position);

            SuspendedUserAction action = new SuspendedUserAction(SuspendedUsersActivity.this, user.UserId);
            action.performAction(view);
        }
    };

    @Override
    public void run() {
        // TODO Auto-generated method stub
        SiteModel site = PreferencesHelper.getSite();

        try 
        {
            users = UserService.GetSuspendedUsers(site.SiteId);
        } 
        catch (FTNIServiceException e) 
        {
            // TODO Auto-generated catch block
            Message message = new Message();
            message.what = ActivityBase.RESULT_ERROR;
            message.obj = e.getMessage();

            handler.sendMessage(message);
            return;
        }

        handler.sendEmptyMessage(ActivityBase.RESULT_DONE);
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what)
            {
                case ActivityBase.RESULT_SUCCESS:
                    progress.dismiss();
                    startActivity(new Intent(SuspendedUsersActivity.this, SelectSiteActivity.class));
                    finish();
                    break;
                case ActivityBase.RESULT_DONE:
                    buildListView();
                    ApplicationController app = (ApplicationController)getApplication();
                    app.setSuspendedUsersChanged(false);
                    progress.dismiss();
                    break;
                case ActivityBase.RESULT_ERROR:
                    progress.dismiss();
                    new AlertDialog.Builder(SuspendedUsersActivity.this)
                    .setMessage(msg.obj.toString())
                    .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface arg0, int arg1) {
                            //do nothing
                            arg0.dismiss();
                        }
                    })
                    .show();
                    break;
            }
        }
    };
}

当我没有设置内容视图时,它可以与ProtectedListActivity一起使用,但是当它设置内容视图并注释掉动作栏的东西时,它都会失败。

5 个答案:

答案 0 :(得分:0)

可能您没有将值设置为ListView全局变量。

发布getListView()代码以获得更多帮助。

答案 1 :(得分:0)

NPE被抛弃

setListAdapter(new UserListAdapter(SuspendedUsersActivity.this, R.layout.useritem, 
    users));

所以users变量很可能是null。

答案 2 :(得分:0)

在第ListView lv = getListView();

之后设置断点

这可能会给你一个空值。

老实说,我会尝试使用常规活动,只需手动配置ListView。这并不难,似乎是支持在一个Activity中拥有两个列表的更好方法。

答案 3 :(得分:0)

我更改了listview,明确地给它一个像这样的id

 <ListView android:id="@+id/list_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_weight="1"
     android:drawSelectorOnTop="false"/>

然后我将代码更改为

private void buildListView()
{
    ListView lv = (ListView)findViewById(R.id.list_view);

    lv.setTextFilterEnabled(true);

    lv.clearChoices();

    lv.setAdapter(new UserListAdapter(SuspendedUsersActivity.this, R.layout.useritem, users));

    lv.setOnItemClickListener(clickListener);
}

现在它有效。由于某种原因,listview的默认ID不起作用。

答案 4 :(得分:0)

您必须将if(textbox.stringValue.isEmpty) { // some code } else { //some code } 延伸至MainActivity

ListActivity