为啥我不能在 AsyncTask 中为另一个类的 ListView 设置适配器?
Posted
技术标签:
【中文标题】为啥我不能在 AsyncTask 中为另一个类的 ListView 设置适配器?【英文标题】:Why I can't set adapter in AsyncTask for ListView from another class?为什么我不能在 AsyncTask 中为另一个类的 ListView 设置适配器? 【发布时间】:2016-04-09 17:17:47 【问题描述】:我有 MainActivity 类和 AsyncTask 类。我有工作版本的代码,但后来我决定将 AsyncTask 类分离到另一个包中。在此之后,我遇到了一些问题,我正在努力解决它们。这是我的代码的最后一个工作版本。
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, SwipeRefreshLayout.OnRefreshListener
private static final String TAG = "MainActivity";
private static final int LAYOUT = R.layout.activity_main;
private static final String URL = "http://killpls.me";
private Toolbar toolbar;
private DrawerLayout drawerLayout;
private NavigationView navigationView;
private ActionBarDrawerToggle toggle;
private FloatingActionButton fab;
private ProgressDialog progressDialog;
private SwipeRefreshLayout mSwipeRefreshLayout;
private NewPostsAsyncTask newPostsAsyncTask;
public Elements content;
public ArrayList<String> titleList = new ArrayList<String>();
public ArrayAdapter<String> adapter;
public ListView listView;
private int navigationDrawerItemId;
private boolean isNavigationDrawerItemEnabled = false;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(LAYOUT);
initToolbar();
initNavigationView();
initActionBarDrawerToggle(); // Добавляет возможность открыть NavigationDrawer через значок
initFloatingActionButton();
initSwipeRefreshLayout();
listView = (ListView) findViewById(R.id.listView);
private void initToolbar()
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener()
@Override
public boolean onMenuItemClick(MenuItem item)
return false;
);
private void initNavigationView()
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
private void initActionBarDrawerToggle()
toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.setDrawerListener(toggle);
toggle.syncState();
private void initFloatingActionButton()
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
);
private void initSwipeRefreshLayout()
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
@Override
public void onBackPressed()
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START))
drawer.closeDrawer(GravityCompat.START);
else
super.onBackPressed();
@Override
public boolean onCreateOptionsMenu(Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
@Override
public boolean onOptionsItemSelected(MenuItem item)
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings)
return true;
return super.onOptionsItemSelected(item);
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item)
// Handle navigation view item clicks here.
navigationDrawerItemId = item.getItemId();
if (navigationDrawerItemId == R.id.new_posts)
Log.i(TAG, "Выбрано раздел \"Новые\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
newPostsAsyncTask = new NewPostsAsyncTask();
newPostsAsyncTask.execute();
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
else if (navigationDrawerItemId == R.id.moderation)
Log.i(TAG, "Выбрано раздел \"Модерация\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
else if (navigationDrawerItemId == R.id.tell_story)
Log.i(TAG, "Выбрано раздел \"Рассказать историю\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
else if (navigationDrawerItemId == R.id.most_terrible_stories)
Log.i(TAG, "Выбрано раздел \"Самые страшные\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
else if (navigationDrawerItemId == R.id.random_story)
Log.i(TAG, "Выбрано раздел \"Случайная\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
else if (navigationDrawerItemId == R.id.happy_end)
Log.i(TAG, "Выбрано раздел \"Happy end\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
else if (navigationDrawerItemId == R.id.about_project)
Log.i(TAG, "Выбрано раздел \"О проекте\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
else if (navigationDrawerItemId == R.id.help_all)
Log.i(TAG, "Выбрано раздел \"Хочу помочь всем\" в Navigation Drawer");
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.item, titleList);
if (!adapter.isEmpty()) adapter.clear();
isNavigationDrawerItemEnabled = true;
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
@Override
public void onRefresh()
new Handler().postDelayed(new Runnable()
@Override
public void run()
if (navigationDrawerItemId == R.id.new_posts)
Log.i(TAG, "Обновленно раздел \"Новые\" в Navigation Drawer");
newPostsAsyncTask = new NewPostsAsyncTask();
newPostsAsyncTask.execute();
else if (navigationDrawerItemId == R.id.moderation)
Log.i(TAG, "Обновленно раздел \"Модерация\" в Navigation Drawer");
else if (navigationDrawerItemId == R.id.tell_story)
Log.i(TAG, "Обновленно раздел \"Рассказать историю\" в Navigation Drawer");
else if (navigationDrawerItemId == R.id.most_terrible_stories)
Log.i(TAG, "Обновленно раздел \"Самые страшные\" в Navigation Drawer");
else if (navigationDrawerItemId == R.id.random_story)
Log.i(TAG, "Обновленно раздел \"Случайная\" в Navigation Drawer");
else if (navigationDrawerItemId == R.id.happy_end)
Log.i(TAG, "Обновленно раздел \"Happy end\" в Navigation Drawer");
else if (navigationDrawerItemId == R.id.about_project)
Log.i(TAG, "Обновленно раздел \"О проекте\" в Navigation Drawer");
else if (navigationDrawerItemId == R.id.help_all)
Log.i(TAG, "Обновленно раздел \"Хочу помочь всем\" в Navigation Drawer");
else
Log.i(TAG, "Попытка обновить главную страницу");
// Когда обновление закончено, вызываем метод setRefreshing(boolean) и передаем ему false.
mSwipeRefreshLayout.setRefreshing(false);
, 2000);
if (!adapter.isEmpty()) adapter.clear();
class NewPostsAsyncTask extends AsyncTask<String, Void, String>
@Override
protected void onPreExecute()
super.onPreExecute();
if (!isNavigationDrawerItemEnabled)
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setTitle("Новые");
progressDialog.setMessage("Загрузка...");
progressDialog.setIndeterminate(false);
progressDialog.show();
@Override
protected String doInBackground(String... params)
Document doc;
try
doc = Jsoup.connect(URL).get(); // Считываем заголовок страницы
// Получение номера страницы селектором и преобразование его в число
Elements pageSpan = doc.select("div.paginator > span:first-child");
int pageCount = Integer.parseInt(pageSpan.first().text());
// Стоит еще проверить, что элементы нашлись, вызовом !pageSpan.isEmpty(),
// first() для пустого списка возвращает null.
for (int i = pageCount; i > 0; i--)
String pageCountString = Integer.toString(i);
doc = Jsoup.connect("http://killpls.me/page/" + pageCountString).get();
parseDocument(doc);
if (i == 1697)
break; // Ограничение до 1697 страницы, чтобы не лагало. Надо исправить.
catch (IOException e)
e.printStackTrace(); // Если не получилось считать
return null;
@Override
protected void onPostExecute(String s)
super.onPostExecute(s);
listView.setAdapter(adapter);
progressDialog.dismiss();
public void parseDocument(Document doc)
// Парсит посты на странице
content = doc.select("[style=margin:0.5em 0;line-height:1.785em]");
for (Element contents : content)
if (!contents.text().contains("18+"))
// Выводит только посты без ссылки на 18+
titleList.add(contents.text());
我在使用 MainActivity 类的适配器时遇到问题。这是另一个包中的新 AsyncTask 类的代码。我在mainActivity.listView.setAdapter(mainActivity.adapter);
有 NullPointerException,你能告诉我为什么吗?
public class NewPostsAsyncTask extends AsyncTask<String, Void, String>
private static final String URL = "http://killpls.me";
private ProgressDialog progressDialog;
private Elements content;
private Context context;
public NewPostsAsyncTask(Context context)
this.context = context;
MainActivity mainActivity = new MainActivity();
@Override
protected void onPreExecute()
super.onPreExecute();
if (!MainActivity.isNavigationDrawerItemEnabled)
progressDialog = new ProgressDialog(context); //MainActivity.this
progressDialog.setTitle("Новые");
progressDialog.setMessage("Загрузка...");
progressDialog.setIndeterminate(false);
progressDialog.show();
@Override
protected String doInBackground(String... params)
Document doc;
try
doc = Jsoup.connect(URL).get(); // Считываем заголовок страницы
// Получение номера страницы селектором и преобразование его в число
Elements pageSpan = doc.select("div.paginator > span:first-child");
int pageCount = Integer.parseInt(pageSpan.first().text());
// Стоит еще проверить, что элементы нашлись, вызовом !pageSpan.isEmpty(),
// first() для пустого списка возвращает null.
for (int i = pageCount; i > 0; i--)
String pageCountString = Integer.toString(i);
doc = Jsoup.connect("http://killpls.me/page/" + pageCountString).get();
parseDocument(doc);
if (i == 1697)
break; // Ограничение до 1697 страницы, чтобы не лагало. Надо исправить.
catch (IOException e)
e.printStackTrace(); // Если не получилось считать
return null;
private void parseDocument(Document doc)
// Парсит посты на странице
content = doc.select("[style=margin:0.5em 0;line-height:1.785em]");
for (Element contents : content)
if (!contents.text().contains("18+"))
// Выводит только посты без ссылки на 18+
mainActivity.titleList.add(contents.text());
//titleList.add(contents.text());
@Override
protected void onPostExecute(String s)
super.onPostExecute(s);
mainActivity.listView.setAdapter(mainActivity.adapter);
//listView.setAdapter(adapter);
progressDialog.dismiss();
【问题讨论】:
首先,你不能通过调用new MainActivity()
来实例化MainActivity。 Android 不能那样工作。其次,listView
无论如何都是私有的,这意味着您无法在 MainActivity 类之外访问它。您需要做的是编写一个回调,将AsyncTask
的结果发送回您的 MainActivity。这是完成您正在尝试做的事情的正确方法。
@NoChinDeluxe 哦,对不起。我从我的 github 复制了这段代码。现在在我的项目中,我有公共字段: public ArrayList因为您在创建 MainActivity 构造函数时直接从 AsyncTask 引用 MainActivity 的成员字段,这是错误的。
只需在 AsyncTask 的构造函数中传递您想要的任何成员字段并使用那个,
喜欢,
private Context context;
private ListView mListView;
private ArrayAdapter<String> adapter;
private List<String> titleList = new ArrayList<String>();
public NewPostsAsyncTask(Context context, ListView listview)
this.context = context;
this.mListView = listview;
private void parseDocument(Document doc)
// Парсит посты на странице
content = doc.select("[style=margin:0.5em 0;line-height:1.785em]");
for (Element contents : content)
if (!contents.text().contains("18+"))
// Выводит только посты без ссылки на 18+
titleList.add(contents.text());
@Override
protected void onPostExecute(String s)
super.onPostExecute(s);
adapter = new ArrayAdapter<String>(context, R.layout.list_item, R.id.item, titleList);
mListView.setAdapter(adapter);
progressDialog.dismiss();
然后删除,MainActivity mainActivity = new MainActivity();
现在像这样从 Activity 调用 AsyncTask,
newPostsAsyncTask = new NewPostsAsyncTask(MainActivity.this, listView);
newPostsAsyncTask.execute();
【讨论】:
以上是关于为啥我不能在 AsyncTask 中为另一个类的 ListView 设置适配器?的主要内容,如果未能解决你的问题,请参考以下文章