操作栏上不确定的进度条上的空指针异常
Posted
技术标签:
【中文标题】操作栏上不确定的进度条上的空指针异常【英文标题】:Null pointer exception on indeterminate progressbar on actionbar 【发布时间】:2015-09-22 06:02:44 【问题描述】:所以我开始创建一个使用 jsoup 来废弃股票数据的应用程序。当我通过导航抽屉从家庭活动移动到“股票”活动时,我需要生成的活动显示第一个片段(viewpager 中的 recyclerview),它会抓取并列出所有股票。但是,这总是会导致以下错误。但是,如果将该片段作为第三个片段并如下图所示打开(编辑:尚无法发布图片),则可以正常工作。
9200-9200/com.blueinklabs.investmentportfoliopakistan E/androidRuntime:致命异常:主进程: com.blueinklabs.investmentportfoliopakistan, PID: 9200 java.lang.NullPointerException:尝试调用接口方法 'android.view.MenuItem android.view.MenuItem.setVisible(boolean)' 空对象引用 com.blueinklabs.investmentportfoliopakistan.StocksActivity.showProgressBar(StocksActivity.java:68) 在 com.blueinklabs.investmentportfoliopakistan.StockData$Title.onPreExecute(StockData.java:37) 在 android.os.AsyncTask.executeOnExecutor(AsyncTask.java:591) 在 android.os.AsyncTask.execute(AsyncTask.java:539) 在 com.blueinklabs.investmentportfoliopakistan.StockData.(StockData.java:28) 在 com.blueinklabs.investmentportfoliopakistan.StocksCompleteListFragment.getSymbols(StocksCompleteListFragment.java:63) 在 com.blueinklabs.investmentportfoliopakistan.StocksCompleteListFragment.setupRecyclerView(StocksCompleteListFragment.java:55) 在 com.blueinklabs.investmentportfoliopakistan.StocksCompleteListFragment.onCreateView(StocksCompleteListFragment.java:48) 在 android.support.v4.app.Fragment.performCreateView(Fragment.java:1789) 在 android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:955) 在 android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1138) 在 android.support.v4.app.BackStackRecord.run(BackStackRecord.java:740) 在 android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1501) 在 android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:490) 在 android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) 在 android.support.v4.view.ViewPager.populate(ViewPager.java:1105) 在 android.support.v4.view.ViewPager.populate(ViewPager.java:951) 在 android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1473) 在 android.view.View.measure(View.java:17547) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) 在 android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:573) 在 android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:640) 在 android.view.View.measure(View.java:17547) 在 android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:868) 在 android.view.View.measure(View.java:17547) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:436) 在 android.support.v7.internal.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:124) 在 android.view.View.measure(View.java:17547) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) 在 android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436) 在 android.widget.LinearLayout.measureVertical(LinearLayout.java:722) 在 android.widget.LinearLayout.onMeasure(LinearLayout.java:613) 在 android.view.View.measure(View.java:17547) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:436) 在 android.view.View.measure(View.java:17547) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) 在 android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436) 在 android.widget.LinearLayout.measureVertical(LinearLayout.java:722) 在 android.widget.LinearLayout.onMeasure(LinearLayout.java:613) 在 android.view.View.measure(View.java:17547) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:436) 在 com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2615) 在 android.view.View.measure(View.java:17547) 在 android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2015) 在 android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1173) 在 android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1379) 在 android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) 在 android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:588
我认为问题在于异步任务(如下)发生在 onPrepareOptionsMenu 加载之前。以下类中的 PreExecute 发生错误:
import android.content.Context;
import android.os.AsyncTask;
import android.support.v7.widget.RecyclerView;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Iterator;
public class StockData
private ArrayList<String> symbolList;
Context myContext;
RecyclerView recyclerV;
public StockData(Context getcontext, RecyclerView recyclerView)
myContext = getcontext;
symbolList = new ArrayList<String>();
recyclerV = recyclerView;
new Title().execute();
private class Title extends AsyncTask<Void, Void, Void>
String title;
@Override
protected void onPreExecute()
super.onPreExecute();
((StocksActivity) myContext).showProgressBar();
@Override
protected Void doInBackground(Void... params)
Document doc = null;
try
doc = Jsoup.connect("websiteurl").get();
catch (MalformedURLException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
Element table = doc.select("table.mGrid").get(1);
Elements rows = table.select("tr");
Iterator<Element> rowIterator = rows.iterator();
rowIterator.next();
while (rowIterator.hasNext())
Element row = rowIterator.next();
Elements cols = row.select("td");
symbolList.add(cols.get(1).text());
return null;
@Override
protected void onPostExecute(Void result)
((StocksCompleteListFragment.SimpleStringRecyclerViewAdapter) recyclerV.getAdapter()).changeList(symbolList);
((StocksActivity) myContext).hideProgressBar();
public ArrayList<String> getSymbolList()
return symbolList;
StocksActivity.java 如下:
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* TODO
*/
public class StocksActivity extends AppCompatActivity
private DrawerLayout mDrawerLayout;
public MenuItem miActionProgressItem;
@Override
public boolean onPrepareOptionsMenu(Menu menu)
// Store instance of the menu item containing progress
miActionProgressItem = menu.findItem(R.id.mi_ActionProgress);
// Extract the action-view from the menu item
ProgressBar v = (ProgressBar) MenuItemCompat.getActionView(miActionProgressItem);
// Return to finish
Toast.makeText(this, "Hi", Toast.LENGTH_SHORT).show();
return super.onPrepareOptionsMenu(menu);
public void showProgressBar()
// Show progress item
miActionProgressItem.setVisible(true);
public void hideProgressBar()
// Hide progress item
miActionProgressItem.setVisible(false);
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stocks);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final ActionBar ab = getSupportActionBar();
ab.setHomeAsUpIndicator(R.drawable.ic_menu);
ab.setDisplayHomeAsUpEnabled(true);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
final NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
if (navigationView != null)
setupDrawerContent(navigationView);
final Menu navMenu = navigationView.getMenu();
((MenuItem) navMenu.findItem(R.id.menuItem1)).setChecked(true);
final ArrayList<View> mMenuItems = new ArrayList<>(navigationView.getChildCount());
//for (int i = 0; i < navigationView.getChildCount(); i++)
navigationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
@Override
public void onGlobalLayout()
// Remember to remove the installed OnGlobalLayoutListener
navigationView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Loop through and find each MenuItem View
for (int i = 0; i < 6; i++)
final String id = "menuItem" + (i);
final MenuItem item = navMenu.findItem(getResources().getIdentifier(id, "id", getPackageName()));
navigationView.findViewsWithText(mMenuItems, item.getTitle(), View.FIND_VIEWS_WITH_TEXT);
// Loop through each MenuItem View and apply your custom Typeface
for (final View menuItem : mMenuItems)
((TextView) menuItem).setTypeface(null, Typeface.BOLD);
((TextView) menuItem).setTextSize(14);
);
//
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
if (viewPager != null)
setupViewPager(viewPager);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
Snackbar.make(view, "Here's a Snackbar", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
@Override
public boolean onCreateOptionsMenu(Menu menu)
getMenuInflater().inflate(R.menu.sample_actions, menu);
miActionProgressItem = menu.findItem(R.id.mi_ActionProgress);
// Extract the action-view from the menu item
ProgressBar v = (ProgressBar) MenuItemCompat.getActionView(miActionProgressItem);
return true;
@Override
public boolean onOptionsItemSelected(MenuItem item)
switch (item.getItemId())
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
return super.onOptionsItemSelected(item);
private void setupViewPager(ViewPager viewPager)
Adapter adapter = new Adapter(getSupportFragmentManager());
adapter.addFragment(new StocksCompleteListFragment(), "Category 1");
adapter.addFragment(new CheeseListFragment(), "Category 2");
adapter.addFragment(new CheeseListFragment(), "All Stocks");
viewPager.setAdapter(adapter);
private void setupDrawerContent(NavigationView navigationView)
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener()
@Override
public boolean onNavigationItemSelected(MenuItem menuItem)
mDrawerLayout.closeDrawers();
switch (menuItem.getItemId())
case R.id.menuItem0:
Intent mainIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(mainIntent);
finish();
break;
case R.id.menuItem1:
Intent stocksIntent = new Intent(getApplicationContext(), StocksActivity.class);
startActivity(stocksIntent);
finish();
break;
return true;
);
@Override
public void onBackPressed()
Intent mainIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(mainIntent);
finish();
static class Adapter extends FragmentPagerAdapter
private final List<Fragment> mFragments = new ArrayList<>();
private final List<String> mFragmentTitles = new ArrayList<>();
public Adapter(FragmentManager fm)
super(fm);
public void addFragment(Fragment fragment, String title)
mFragments.add(fragment);
mFragmentTitles.add(title);
@Override
public Fragment getItem(int position)
return mFragments.get(position);
@Override
public int getCount()
return mFragments.size();
@Override
public CharSequence getPageTitle(int position)
return mFragmentTitles.get(position);
过去 8 小时我一直在尝试解决这个问题,这是我第一次在这个论坛上发帖,如果我发错了,请原谅。我已经搜索并尝试了一些我认为相关的解决方案。
http://i.stack.imgur.com/Wxxr6.png
编辑:这是片段 StocksCompleteListFragment.java 的类
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
public class StocksCompleteListFragment extends Fragment
ArrayList<String> list;
RecyclerView rv;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
rv = (RecyclerView) inflater.inflate(
R.layout.fragment_stocks_completelist, container, false);
setupRecyclerView(rv);
return rv;
private void setupRecyclerView(RecyclerView recyclerView)
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
recyclerView.setAdapter(new SimpleStringRecyclerViewAdapter(getActivity(),
getSymbols(recyclerView)));
private ArrayList<String> getSymbols(RecyclerView recyclerView)
list = new ArrayList<>();
StockData stockDataClass = new StockData(getActivity(), recyclerView);
list = stockDataClass.getSymbolList();
return list;
public static class SimpleStringRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder>
private final TypedValue mTypedValue = new TypedValue();
private int mBackground;
private List<String> mValues;
public static class ViewHolder extends RecyclerView.ViewHolder
public String mBoundString;
public final View mView;
public final ImageView mImageView;
public final TextView mTextView;
public ViewHolder(View view)
super(view);
mView = view;
mImageView = (ImageView) view.findViewById(R.id.avatar);
mTextView = (TextView) view.findViewById(android.R.id.text1);
@Override
public String toString()
return super.toString() + " '" + mTextView.getText();
public void changeList (ArrayList<String> tempStringList)
mValues = tempStringList;
notifyDataSetChanged();
public String getValueAt(int position)
return mValues.get(position);
public SimpleStringRecyclerViewAdapter(Context context, List<String> items)
context.getTheme().resolveAttribute(R.attr.selectableItemBackground, mTypedValue, true);
mBackground = mTypedValue.resourceId;
mValues = items;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.completestocks_listitem, parent, false);
view.setBackgroundResource(mBackground);
return new ViewHolder(view);
@Override
public void onBindViewHolder(final ViewHolder holder, int position)
holder.mBoundString = mValues.get(position);
holder.mTextView.setText(mValues.get(position));
holder.mView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Context context = v.getContext();
Intent intent = new Intent(context, CheeseDetailActivity.class);
intent.putExtra(CheeseDetailActivity.EXTRA_NAME, holder.mBoundString);
context.startActivity(intent);
);
Glide.with(holder.mImageView.getContext())
.load(Cheeses.getRandomCheeseDrawable())
.fitCenter()
.into(holder.mImageView);
@Override
public int getItemCount()
return mValues.size();
【问题讨论】:
尝试将您的showProgressBar
和 hideProgressBar
更改为您的 AsyncTask
并将对菜单的引用作为参数传递。您收到该错误是因为当您调用这些方法时,不存在对 MenuItem
的引用。
日志说你的上下文“myContext”为空。你能展示一下使用 StockData 的代码吗?
Eric,根据您的建议,我使用片段类中的 getActivity() 方法从 StocksActivity.java 访问 MenuItem。然后将它传递给异步类(StockData),并将方法转移到这个类。仍然显示空指针。严重卡住了!
约翰,我在后期编辑中插入了片段类。如果您能提供帮助会很高兴!
据我所知,菜单项在 onPrepareOptionsMenu(Menu menu) 方法中的 StocksActivity 实例化之前被调用。但我也需要立即启动 asynctask,所以我不知道还能做什么。
【参考方案1】:
在评论中解释它可能是什么有点困难,所以我会在这个答案中帮助你调试。
所以,StockActivity
加载片段,StocksCompleteListFragment
执行AsyncTask
(最后一个访问StockActivity
的菜单项)。
AsyncTask
(StockData
的内部类)应该收到对 MenuItem
的引用。
我会尝试,就像我之前告诉你的那样,将访问MenuItem
的两种方法移到AsyncTask
。
private class Title extends AsyncTask<Void, Void, Void>
// ...
@Override
protected void onPreExecute()
super.onPreExecute();
showProgressBar();
@Override
protected void onPostExecute(Void result)
((StocksCompleteListFragment.SimpleStringRecyclerViewAdapter) recyclerV.getAdapter()).changeList(symbolList);
hideProgressBar();
// I don't need them to be public if I move them here
//
private void showProgressBar()
// Show progress item
item.setVisible(true);
private void hideProgressBar()
// Hide progress item
item.setVisible(false);
之后,您应该将MenuItem
传递给StocksCompleteListFragment
所以:
添加一个接收它的构造函数
public class StocksCompleteListFragment extends Fragment
private MenuItem item;
// Default constructor
public StocksCompleteListFragment()
public StocksCompleteListFragment(MenuItem item)
this.item = item;
// ...
然后将其传递给 Fragment 类
// StocksActivity.java
adapter.addFragment(new StocksCompleteListFragment(miActionProgressItem ), "Category 1");
稍后将项目从 StocksCompleteListFragment
传递给 StockData
类,以便内部 AsyncTask
可以访问它
public class StockData
private ArrayList<String> symbolList;
Context myContext;
RecyclerView recyclerV;
private MenuItem item;
public StockData(Context getcontext, RecyclerView recyclerView)
myContext = getcontext;
symbolList = new ArrayList<String>();
recyclerV = recyclerView;
new Title().execute();
public StockData(Context getcontext, RecyclerView recyclerView, MenuItem item)
this(getcontext, recyclerView);
this.item = item;
最后编辑您的代码段,调用AsyncTask
以传递MenuItem
private ArrayList<String> getSymbols(RecyclerView recyclerView)
list = new ArrayList<>();
StockData stockDataClass = new StockData(getActivity(), recyclerView, item);
list = stockDataClass.getSymbolList();
return list;
如果我在正确的轨道上,当您调用 AsyncTask
时,MenuItem
应该已经存在。
我是这样看的:
StockActivity(完全加载,操作栏和一切)-> 传递菜单项-> StocksCompleteListFragment(调用AsyncTask
)-> 传递菜单项-> AsyncTask 隐藏/显示菜单项。
这就是我的看法,一定有更简单的选择,但我想不出更简单的方法。
试试这个,我宁愿这是一个评论而不是一个答案,但我不能写这么多。
继续努力,明天我会回来跟踪这个帖子。希望对你有一点帮助。
【讨论】:
感谢您的帮助,但这仍然不起作用:(我在创建片段之前放置了两个日志,以了解菜单在那个阶段是否为空,并且它是。所以很可能一个进度条在设置之前询问菜单参考的情况。解释为什么它作为第三个片段工作。if (miActionProgressItem == null) Log.w("myApp", "MenuItem is Null"); else Log .w("myApp", "MenuItem is Filled"); adapter.addFragment(new StocksCompleteListFragment(miActionProgressItem), "Category 1"); 我已经研究了将进度条放在片段本身顶部的替代实现,因此如果无法解决,它应该可以工作 好吧,我找不到其他方法,我真的很抱歉。如果您发现了另一种方式,如果您分享它并将其标记为正确答案应该会很好。 埃里克,非常感谢。尽管尝试了很多,但我没有找到任何问题的答案。所以我从操作栏中的进度条转移到我的片段中的进度条。以上是关于操作栏上不确定的进度条上的空指针异常的主要内容,如果未能解决你的问题,请参考以下文章