自定义适配器在 ArrayList 准备好之前启动
Custom Adapter starts before ArrayList is ready
我正在制作一个链接列表,为此我制作了一个自定义适配器,但是当适配器启动时该列表还没有准备好,所以我收到以下错误:
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
这是因为当适配器启动时列表是空的,并且在列表被填满后片刻但为时已晚这里是我的代码:
更新: 代码已更改,所以现在我没有收到错误,但适配器中没有 运行 getView:
public class Controller extends Activity {
private String TAG = Controller.class.getSimpleName();
private String http;
CustomAdapter adapter;
public Controller con = null;
private ListView lv;
private static String url;
ArrayList<Selfservice> linkList = new ArrayList<Selfservice>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
con = this;
http = this.getString(R.string.http);
url = this.getString(R.string.path1);
new GetLinks().execute();
lv = (ListView)findViewById(R.id.list);
//Resources res = getResources();
//adapter = new CustomAdapter(con, linkList, res);
//lv.setAdapter(adapter);
}
private class GetLinks extends AsyncTask<Void, Void, List<Selfservice>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected List<Selfservice> doInBackground(Void... arg0) {
Document doc;
Elements links;
List<Selfservice> returnList = null;
try {
doc = Jsoup.connect(url).timeout(0).get();
links = doc.getElementsByClass("processlink");
returnList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return returnList;
}
@Override
protected void onPostExecute(final List<Selfservice> result) {
super.onPostExecute(result);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//setSupportActionBar(toolbar);
//getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("");
toolbar.setSubtitle("");
Resources res = getResources();
Log.e(TAG, linkList.toString());
linkList = (ArrayList<Selfservice>) result;
adapter = new CustomAdapter(con, result, res);
adapter.notifyDataSetChanged();
lv.setAdapter(adapter);
}
});
}
}
和我的适配器:
public class CustomAdapter extends BaseAdapter implements OnClickListener {
private String TAG = CustomAdapter.class.getSimpleName();
Context context;
List<Selfservice> data;
private Activity activity;
public Resources res;
Selfservice self = null;
private static LayoutInflater inflater;
int layoutResourceId = 0;
public CustomAdapter(Activity act, List<Selfservice> dataList, Resources resources) {
res = resources;
activity = act;
data = dataList;
}
private class Holder {
TextView title;
TextView link;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int pos) {
return pos;
}
@Override
public long getItemId(int pos) {
return pos;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = convertView;
Holder holder;
if(rowView == null){
rowView = inflater.inflate(R.layout.list_item, null);
holder = new Holder();
holder.title = (TextView) rowView.findViewById(R.id.title);
holder.link = (TextView) rowView.findViewById(R.id.link);
rowView.setTag(holder);
}else{
holder = (Holder)rowView.getTag();
}
if(data.size()<=0){
holder.title.setText("did not work");
}else{
self = null;
self = (Selfservice) data.get(position);
holder.title.setText(self.getTitle());
holder.link.setText(self.getLink());
Log.i(TAG, "adapter");
rowView.setOnClickListener(new OnItemClickListener(position));
}
return rowView;
}
@Override
public void onClick(View v){
Log.v("CustomAdapter", "row clicked");
}
private class OnItemClickListener implements OnClickListener{
private int mPos;
OnItemClickListener(int position){
mPos = position;
}
@Override
public void onClick(View arg0){
Controller con = (Controller)activity;
con.onItemClick(mPos);
}
}
}
那么如何让适配器等待列表已满?
您可以在 onPostExecute 中创建适配器;
将异步任务更改为:
private class GetLinks extends AsyncTask<Void, Void, List<Selfservice>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... arg0) {
Document doc;
Elements links;
List<Selfservice> returnList
try {
doc = Jsoup.connect(url).timeout(10000).get();
links = doc.getElementsByClass("processlink");
returnList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return returnList;
}
@Override
protected void onPostExecute(List<Selfservice> result) {
super.onPostExecute(result);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//setSupportActionBar(toolbar);
//getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("");
toolbar.setSubtitle("");
linkList = result
adapter = new CustomAdapter(con, result, res);
lv.setAdapter(adapter);
}
});
}
这样您将仅在列表准备就绪时创建适配器。
编辑:
您没有在适配器内部创建变量 context 。将您的构造函数更改为:
public CustomAdapter(Context context, Activity act, List<Selfservice> dataList, Resources resources) {
res = resources;
activity = act;
data = dataList;
this.context = context;
}
你将不再看到 NullPointerExecption
首先使用ArrayAdapter<Selfservice>
代替BaseAdapter
使用构造函数
public CustomAdapter(Context context, int resource, List<Selfservice> objects) {
super(context, resource, objects);
data = objects;
}
然后只覆盖两个方法
public int getCount()
public View getView(int position, View convertView, ViewGroup parent)
然后 return list.size()
在 getCount()
在 getView() 方法中
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.list_item, null);
}
在 try 块中的 doInBackground() 方法中
而不是 linkList = ParseHTML(links);
做 linkList.addAll(ParseHTML(links));
并在 onPostExcecute() 方法中
adapter.notifyDatasetChanged();
在 ui 线程中
我正在制作一个链接列表,为此我制作了一个自定义适配器,但是当适配器启动时该列表还没有准备好,所以我收到以下错误:
java.lang.RuntimeException: Unable to start activity ComponentInfo{}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
这是因为当适配器启动时列表是空的,并且在列表被填满后片刻但为时已晚这里是我的代码:
更新: 代码已更改,所以现在我没有收到错误,但适配器中没有 运行 getView:
public class Controller extends Activity {
private String TAG = Controller.class.getSimpleName();
private String http;
CustomAdapter adapter;
public Controller con = null;
private ListView lv;
private static String url;
ArrayList<Selfservice> linkList = new ArrayList<Selfservice>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
con = this;
http = this.getString(R.string.http);
url = this.getString(R.string.path1);
new GetLinks().execute();
lv = (ListView)findViewById(R.id.list);
//Resources res = getResources();
//adapter = new CustomAdapter(con, linkList, res);
//lv.setAdapter(adapter);
}
private class GetLinks extends AsyncTask<Void, Void, List<Selfservice>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected List<Selfservice> doInBackground(Void... arg0) {
Document doc;
Elements links;
List<Selfservice> returnList = null;
try {
doc = Jsoup.connect(url).timeout(0).get();
links = doc.getElementsByClass("processlink");
returnList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return returnList;
}
@Override
protected void onPostExecute(final List<Selfservice> result) {
super.onPostExecute(result);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//setSupportActionBar(toolbar);
//getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("");
toolbar.setSubtitle("");
Resources res = getResources();
Log.e(TAG, linkList.toString());
linkList = (ArrayList<Selfservice>) result;
adapter = new CustomAdapter(con, result, res);
adapter.notifyDataSetChanged();
lv.setAdapter(adapter);
}
});
}
}
和我的适配器:
public class CustomAdapter extends BaseAdapter implements OnClickListener {
private String TAG = CustomAdapter.class.getSimpleName();
Context context;
List<Selfservice> data;
private Activity activity;
public Resources res;
Selfservice self = null;
private static LayoutInflater inflater;
int layoutResourceId = 0;
public CustomAdapter(Activity act, List<Selfservice> dataList, Resources resources) {
res = resources;
activity = act;
data = dataList;
}
private class Holder {
TextView title;
TextView link;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int pos) {
return pos;
}
@Override
public long getItemId(int pos) {
return pos;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = convertView;
Holder holder;
if(rowView == null){
rowView = inflater.inflate(R.layout.list_item, null);
holder = new Holder();
holder.title = (TextView) rowView.findViewById(R.id.title);
holder.link = (TextView) rowView.findViewById(R.id.link);
rowView.setTag(holder);
}else{
holder = (Holder)rowView.getTag();
}
if(data.size()<=0){
holder.title.setText("did not work");
}else{
self = null;
self = (Selfservice) data.get(position);
holder.title.setText(self.getTitle());
holder.link.setText(self.getLink());
Log.i(TAG, "adapter");
rowView.setOnClickListener(new OnItemClickListener(position));
}
return rowView;
}
@Override
public void onClick(View v){
Log.v("CustomAdapter", "row clicked");
}
private class OnItemClickListener implements OnClickListener{
private int mPos;
OnItemClickListener(int position){
mPos = position;
}
@Override
public void onClick(View arg0){
Controller con = (Controller)activity;
con.onItemClick(mPos);
}
}
}
那么如何让适配器等待列表已满?
您可以在 onPostExecute 中创建适配器;
将异步任务更改为:
private class GetLinks extends AsyncTask<Void, Void, List<Selfservice>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... arg0) {
Document doc;
Elements links;
List<Selfservice> returnList
try {
doc = Jsoup.connect(url).timeout(10000).get();
links = doc.getElementsByClass("processlink");
returnList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return returnList;
}
@Override
protected void onPostExecute(List<Selfservice> result) {
super.onPostExecute(result);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//setSupportActionBar(toolbar);
//getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("");
toolbar.setSubtitle("");
linkList = result
adapter = new CustomAdapter(con, result, res);
lv.setAdapter(adapter);
}
});
}
这样您将仅在列表准备就绪时创建适配器。
编辑: 您没有在适配器内部创建变量 context 。将您的构造函数更改为:
public CustomAdapter(Context context, Activity act, List<Selfservice> dataList, Resources resources) {
res = resources;
activity = act;
data = dataList;
this.context = context;
}
你将不再看到 NullPointerExecption
首先使用ArrayAdapter<Selfservice>
代替BaseAdapter
使用构造函数
public CustomAdapter(Context context, int resource, List<Selfservice> objects) {
super(context, resource, objects);
data = objects;
}
然后只覆盖两个方法
public int getCount()
public View getView(int position, View convertView, ViewGroup parent)
然后 return list.size()
在 getCount()
在 getView() 方法中
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.list_item, null);
}
在 try 块中的 doInBackground() 方法中
而不是 linkList = ParseHTML(links);
做 linkList.addAll(ParseHTML(links));
并在 onPostExcecute() 方法中
adapter.notifyDatasetChanged();
在 ui 线程中