gpt4 book ai didi

android - 使用ViewPager的Android java.lang.IllegalStateException

转载 作者:太空宇宙 更新时间:2023-11-03 13:42:22 27 4
gpt4 key购买 nike

我用viewpager制作了一个非常简单的android拼图应用程序,用户可以通过它浏览一系列拼图。我在生产中看到一个不知道如何复制或调试的错误:

java.lang.IllegalStateException: 
at android.support.v4.view.ViewPager.a (ViewPager.java:204)
at android.support.v4.view.ViewPager.c (ViewPager.java:2)
at android.support.v4.view.ViewPager.onMeasure (ViewPager.java:207)
at android.view.View.measure (View.java:22002)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure (FrameLayout.java:185)
at android.view.View.measure (View.java:22002)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6580)
at android.support.v7.internal.widget.ActionBarOverlayLayout.onMeasure (ActionBarOverlayLayout.java:257)
at android.view.View.measure (View.java:22002)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure (FrameLayout.java:185)
at android.view.View.measure (View.java:22002)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6580)
at android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1514)
at android.widget.LinearLayout.measureVertical (LinearLayout.java:806)
at android.widget.LinearLayout.onMeasure (LinearLayout.java:685)
at android.view.View.measure (View.java:22002)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6580)
at android.widget.FrameLayout.onMeasure (FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure (DecorView.java:721)
at android.view.View.measure (View.java:22002)
at android.view.ViewRootImpl.performMeasure (ViewRootImpl.java:2414)
at android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:2159)
at android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:1390)
at android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:6762)
at android.view.Choreographer$CallbackRecord.run (Choreographer.java:966)
at android.view.Choreographer.doCallbacks (Choreographer.java:778)
at android.view.Choreographer.doFrame (Choreographer.java:713)
at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:952)
at android.os.Handler.handleCallback (Handler.java:789)
at android.os.Handler.dispatchMessage (Handler.java:98)
at android.os.Looper.loop (Looper.java:169)
at android.app.ActivityThread.main (ActivityThread.java:6595)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:240)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:767)

我应该做些什么来找出如何复制这个错误,并找出如何修复它?我的android编程技能相当有限,上面的堆栈跟踪对我来说非常神秘。
如果有帮助,下面是第二个看起来相关的堆栈跟踪:
java.lang.IllegalStateException: 
at android.support.v4.view.ViewPager.access$000 (ViewPager.java)
or .access$200 (ViewPager.java)
or .addNewItem (ViewPager.java)
or .calculatePageOffsets (ViewPager.java)
or .canScroll (ViewPager.java)
or .completeScroll (ViewPager.java)
or .determineTargetPage (ViewPager.java)
or .distanceInfluenceForSnapDuration (ViewPager.java)
or .executeKeyEvent (ViewPager.java)
or .getChildRectInPagerCoordinates (ViewPager.java)
or .infoForChild (ViewPager.java)
or .initViewPager (ViewPager.java)
or .isGutterDrag (ViewPager.java)
or .onPageScrolled (ViewPager.java)
or .onSecondaryPointerUp (ViewPager.java)
or .populate (ViewPager.java)
or .recomputeScrollPosition (ViewPager.java)
or .scrollToItem (ViewPager.java)
or .setCurrentItem (ViewPager.java)
or .setCurrentItemInternal (ViewPager.java)
or .smoothScrollTo (ViewPager.java)
at android.support.v4.view.ViewPager.arrowScroll (ViewPager.java)
or .populate (ViewPager.java)
or .requestParentDisallowInterceptTouchEvent (ViewPager.java)
at android.support.v4.view.ViewPager.onMeasure (ViewPager.java)
at android.view.View.measure (View.java:19759)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6124)
at android.widget.FrameLayout.onMeasure (FrameLayout.java:185)
at android.view.View.measure (View.java:19759)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6124)
at android.support.v7.internal.widget.ActionBarOverlayLayout.onMeasure (ActionBarOverlayLayout.java)
at android.view.View.measure (View.java:19759)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6124)
at android.widget.FrameLayout.onMeasure (FrameLayout.java:185)
at android.view.View.measure (View.java:19759)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6124)
at android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1464)
at android.widget.LinearLayout.measureVertical (LinearLayout.java:758)
at android.widget.LinearLayout.onMeasure (LinearLayout.java:640)
at android.view.View.measure (View.java:19759)
at android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:6124)
at android.widget.FrameLayout.onMeasure (FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure (DecorView.java:687)
at android.view.View.measure (View.java:19759)
at android.view.ViewRootImpl.performMeasure (ViewRootImpl.java:2283)
at android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:2036)
at android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:1258)
at android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:6348)
at android.view.Choreographer$CallbackRecord.run (Choreographer.java:871)
at android.view.Choreographer.doCallbacks (Choreographer.java:683)
at android.view.Choreographer.doFrame (Choreographer.java:619)
at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:857)
at android.os.Handler.handleCallback (Handler.java:751)
at android.os.Handler.dispatchMessage (Handler.java:95)
at android.os.Looper.loop (Looper.java:154)
at android.app.ActivityThread.main (ActivityThread.java:6123)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:757)

我应该发布我的viewpager代码的简缩版本吗?
编辑:这是做大部分工作的班级:
public class SolvePuzzle extends ActionBarActivity {

// The code is longer than is shown here, but hopefully this is enough to be helpful
static AppSectionsPagerAdapter mAppSectionsPagerAdapter;
static ViewPager mViewPager;
static int level;
static String images[];
static String levelDescriptions[];
static String puzzles[];
static String answers[];
static String hints[];
static String congratulationsArray[];

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_solve_puzzle);

// Some code related to getSupportActionBar(); which I've cut out for brevity

Intent intent = getIntent();
if (intent != null) {
level = intent.getIntExtra(PuzzleSelection.LEVEL, 0); // Possible bug here with default level set to 0?
}

// Here there's code that populates images, levelDescriptions, puzzles, answers, and other arrays using the level integer
// The arrays will have different lengths depending on the level
// i.e. there is a different number of puzzles in each level
// I do something along the lines of puzzles = getPuzzlesGivenLevel(level); and similarly for answers, hints, etc.

mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override public void onPageScrollStateChanged(int arg0) {
}
@Override public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override public void onPageSelected(int puzzleIndex) {
callSetShareIntent(puzzles[puzzleIndex]); // Make share button share the correct puzzle
}
});
mViewPager.setCurrentItem(indexFirstUnsolvedPuzzle());
}

private int indexFirstUnsolvedPuzzle() {
// Gets index of first unsolved puzzle in this level
}

private void callSetShareIntent(String puzzleStatement) {
// Creates an Intent called shareIntent; and then calls setShareIntent(shareIntent);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.solve_puzzle, menu);
MenuItem item = menu.findItem(R.id.menu_item_share);

// Following http://stackoverflow.com/questions/19118051/unable-to-cast-action-provider-to-share-action-provider
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
if (mShareActionProvider == null) {
// Following http://stackoverflow.com/questions/19358510/why-menuitemcompat-getactionprovider-returns-null
mShareActionProvider = new ShareActionProvider(this);
MenuItemCompat.setActionProvider(item, mShareActionProvider);
}
callSetShareIntent(puzzles[mViewPager.getCurrentItem()]);
return true; // Return true to display menu
}

private void setShareIntent(Intent shareIntent) {
if (mShareActionProvider != null) {
mShareActionProvider.setShareIntent(shareIntent); // Should be called whenever new fragment is displayed
}
}

public class AppSectionsPagerAdapter extends FragmentPagerAdapter {

public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int puzzleIndex) {
Fragment fragment = new SolvePuzzleFragment();
Bundle args = new Bundle();
args.putInt(PUZZLE_INDEX, puzzleIndex);
fragment.setArguments(args);
return fragment;
}

@Override
public int getCount() {
return puzzles.length;
}
}

public static class SolvePuzzleFragment extends Fragment implements OnClickListener {

public double correctAnswer;
public int puzzleIndex;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_solve_puzzle, container, false);
Bundle args = getArguments();
puzzleIndex = args.getInt(PUZZLE_INDEX);

// Sets a bunch of TextViews using the puzzleIndex
// For example, get string in puzzles[puzzleIndex] and put it in a TextView, et cetera
// Set a bunch of onClickListenters

}

// A bunch of functions for checking the user's answer, opening congratulations, etc
// E.g. public void openCongratulationsAlert(View view) { ... }, public void openIncorrectAnswerToast() { ... }

}

}

如果需要更多的解释,请告诉我。

最佳答案

我将你的应用程序安装在一个模拟器中,并且能够用monkey工具(https://developer.android.com/studio/test/monkey.html)重现这个崩溃。这个工具模拟用户的动作,如点击、触摸、旋转等,速度很快。但我不能手工复制。
你在问题中写道,你想知道如何找出问题所在,所以我将详细解释我的过程。对于实际的解决方案,请跳到第5节。
1。如何知道非法状态异常的消息
第一个堆栈跟踪显示异常是在viewpager.java上引发的,因此我在该文件中搜索字符串“throw new illegalstateexception”。有不同的版本,但是我检查过的少数几个版本只在6个地方抛出了这个异常,
有两个是关于程序化的viewpager drags,但是你的应用没有做到这一点,所以我放弃了这些
有两个将不会在继承自viewpager的类中调用super方法,但是由于在您的代码中您只是使用viewpager,所以我也放弃了那些
其中一个在addView()中,它不会出现在堆栈跟踪上,所以我也放弃了它。
剩下的只有一个被扔到populate(int),它必须是这个。但为了确定,我检查了第二个stacktrace:
第四行“at”表示调用了ViewPager.onMeasure()。这里没有“或”线,所以这是肯定的。
第三行“at”给出了三个选项。从源代码来看,只有populate()onMeasure()调用,所以它必须是那个。
第二行“at”给出了21个选项,但是再次查看源代码,populate()只调用了populate(int)。和以前一样的方法,所以很适合。
下面是populate(int)中的抛出代码:

throw new IllegalStateException("The application's PagerAdapter changed the adapter's"
+ " contents without calling PagerAdapter#notifyDataSetChanged!"
+ " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N
+ " Pager id: " + resName
+ " Pager class: " + getClass()
+ " Problematic adapter: " + mAdapter.getClass());

这就是我第一次回答这个问题的原因。
2。复制错误
在仿真器中下载应用程序后,我从命令行运行此命令:
adb shell monkey -p atorch.statspuzzles -v --pct-rotation 20 100000
这将以非常高的速度发送模拟器100.000个半随机触摸事件、旋转、音量增大/减小等,以在压力下测试应用程序。如果使用应用程序的调试版本运行此命令,您应该能够看到我在步骤1中获得的堆栈跟踪。
三。获取有关错误的信息(主要是推测性的)
从这里开始,你可以在你的代码中放很多行,运行 Log.d(),这应该会让你知道你的用户是怎么让你的应用崩溃的。当然我做不到,所以我用你提供的代码编写了一个小应用程序,并用 monkey运行它,看看是否可以得到其他东西。我所做的是:
删除了对r类的所有引用(例如,用我自己的一个布局替换了您的布局,只使用viewpager,用一个简单的视图替换了您的片段布局)。
monkey返回零,只是为了让android studio不必费心
在fragment类中,我添加了一个启动对话框的 indexFirstUnsolvedPuzzle(),这仅仅是因为你的应用程序有对话框。
带有 onClickListener活动的模拟级别选择,该活动随机选择一个级别在onresume()启动 PuzzleSelection
在两个活动中都添加了 SolvePuzzle,以便能够记录背压。
我在每个方法上添加了 onBackPressed(),以便能够遵循logcat中的过程。
我用 Log.d()运行了这个应用程序,在崩溃之前,我在日志中找到了这个:
(section 1)
SolvePuzzle@84e25c: back pressed
ViewPager{9256292}: scrolled, offset: 9.2589855E-4
AppSectionsPagerAdapter@4b49965: getCount() invoked, we have 3 elements
(section 2)
Creating Activity PuzzleSelection@580af24. Orientation: portrait
Starting puzzle for level 1
ViewPager{9256292}: scrolled, offset: 0.0
AppSectionsPagerAdapter@4b49965: getCount() invoked, we have 3 elements
AppSectionsPagerAdapter@4b49965: getCount() invoked, we have 3 elements
(section 3)
Creating Activity SolvePuzzle@16d7aaffor level 3. Orientation: portrait
Creating adapter AppSectionsPagerAdapter@958bebc with 2 elements.
AppSectionsPagerAdapter@958bebc: getCount() invoked, we have 2 elements
AppSectionsPagerAdapter@958bebc: getCount() invoked, we have 2 elements
ViewPager{c002954}: scrollStateChanged to 0
AppSectionsPagerAdapter@4b49965: getCount() invoked, we have 2 elements

4。坠机原因
注意,当 monkey不再显示在屏幕上时,第1节中的适配器(@4b49965)在第2节中一直被调用。在创建了新适配器之后,甚至在第3节中也调用了它。对于这个适配器,getCount()的结果在第1节和第3节中是不同的,这意味着适配器已经更改了其内容,因此引发了异常。
这个适配器很可能在其 SolvePuzzle完成后继续使用,因为它的 SolveActivity在变为不可见后正在进行一些整理。问题是,旧活动读取了对新活动刚刚写入的字符串数组的引用,这只是因为数组是 ViewPager的静态成员。
(顺便说一句,这些静态数组确实会在你的应用程序中引起另一个bug:如果你选择级别x,解决那里的问题,然后通过祝贺对话框返回菜单,然后选择另一个级别y,然后按back两次,你最终会进入级别y,而不是级别x。)
5。解决方案
一般来说,只有当静态字段是真正不可变的(如常量)时,或者至少在可以正确同步并发访问时,才使用静态字段。另一方面,由于内存泄漏,静态类几乎总是比内部类更可取。
在你的特殊情况下,你应该:
从所有数组(实际上,从所有字段)中删除 SolvePuzzle关键字。
应用程序节SPAGERADApter映射程序节SPAGERADApter;
可视寻呼机mviewpager;
int级;
字符串图像[];
字符串级别描述[];
字符串拼图[];
字符串应答[];
字符串提示[];
字符串祝贺数组[];
您也可以将这些字段设为私有字段,尽管这不是绝对必要的。
使适配器类也成为静态的。android studio会抱怨它找不到 static,所以您可以通过构造函数传递它,也可以传递其他以前的静态数组。
public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {

private String images[];
private String puzzles[];
...

public AppSectionsPagerAdapter(FragmentManager fm,
String[] puzzles,
String[] images,
...
) {
super(fm);
this.puzzles = puzzles;
this.images = images;
...
}

/* ... */
}

puzzles,不要向片段传递数组索引,而是向它们传递它们需要的特定值:
@Override
public Fragment getItem(int puzzleIndex) {
Fragment fragment = new SolvePuzzleFragment();
Bundle args = new Bundle();
args.putString(PUZZLE_CONTENT, puzzles[puzzleIndex]);
args.putString(PUZZLE_IMAGE, images[puzzleIndex]);
...
fragment.setArguments(args);
return fragment;
}

在片段中,检索新参数而不是数组索引。
应该可以。

关于android - 使用ViewPager的Android java.lang.IllegalStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49333138/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com