简体   繁体   English

Android-使用自定义布局时出现NullPointerException的getListView和setListAdapter错误

[英]Android - getListView and setListAdapter error with NullPointerException when using custom layout

I have a layout like this 我有这样的布局

<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>

and in my listview (code that was working before I changed the layout) 并在我的列表视图中(更改布局之前有效的代码)

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);
}

I tried moving the call to setListAdapter first, but I still get the NullPointerException. 我尝试先将调用移到setListAdapter ,但仍然收到NullPointerException。 Here's the logcat 这是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)

I have a feeling that what is happening is that the default ID I was told is correct ( @id/android:list ) is not correct for the default list view. 我感觉正在发生的事情是,我被告知的默认ID是正确的( @id/android:list )对于默认列表视图而言是不正确的。

EDIT: 编辑:

Here are more details about how I have this set up. 以下是有关如何进行此设置的更多详细信息。

First, I have an inherited activity to ensure the user is authenticated. 首先,我有一个继承的活动,以确保对用户进行身份验证。 When I inherit directly from this class, all works fine. 当我直接从此类继承时,一切正常。

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();
    }
}

Then, I extend that one step further to wrap my default action bar setup into a base class. 然后,我将这一步骤进一步扩展到将我的默认操作栏设置包装到基类中。

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");
    }
}

Then, because I have 2 lists of users separated by status (suspended or active) I was attempting to wrap an addition to the action bar in a base class. 然后,因为我有2个按状态(挂起或活动)分开的用户列表,所以我试图将附加的操作包装到基类中。

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));

    }
}

and finally, we have my activity. 最后,我们有我的活动。 I've omitted a little code, but I left most of it so you could see how the data is retrieved through another thread while a loading screen is shown, and then the listview is built. 我省略了一些代码,但是我保留了大部分代码,因此您可以看到在显示加载屏幕时如何通过另一个线程检索数据,然后构建了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;
            }
        }
    };
}

It works with ProtectedListActivity when I do not set a content view, but everything else it fails on, whether or not I set the content view and comment out the actionbar stuff. 当我未设置内容视图时,它可以与ProtectedListActivity一起使用,但是无论是否设置内容视图并注释掉操作栏内容,它都会失败。

your must extends MainActivity to ListActivity . 您必须将MainActivity扩展到ListActivity

public class MainActivity extends ListActivity {
}

Probably you are not setting the value to the ListView global variable. 可能您没有将值设置为ListView全局变量。

Post getListView() code to more help. 发布getListView()代码以获取更多帮助。

The NPE is thrown on NPE被抛出

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

so the users variable is most likely null. 因此users变量很可能为null。

Set a breakpoint right after the line ListView lv = getListView(); ListView lv = getListView();行后立即设置一个断点ListView lv = getListView();

Chances are this is giving you a null value. 可能这会给您一个空值。

Honestly I would try to go with a regular activity and just configure the ListView manually. 老实说,我会尝试进行常规活动,而只是手动配置ListView。 It isn't hard and it seems like a better way to support having two lists in one Activity. 这并不难,并且似乎是在一个Activity中支持两个列表的更好方法。

I changed the listview to explicitly give it an id like this 我将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"/>

And then I changed my code to this 然后我将代码更改为此

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);
}

And now it works. 现在就可以了。 For some reason that default ID for the listview doesn't work. 由于某种原因,列表视图的默认ID不起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM