问题
Research has been fruitless because all other references to this error seem to be reliably repeatable; I'm unable to consistently repeat this error:
08-22 17:32:25.216 22699-22699/com.smbds.punisher11 E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:1023)
at android.graphics.Bitmap.createBitmap(Bitmap.java:1002)
at android.graphics.Bitmap.createBitmap(Bitmap.java:985)
at com.github.amlcurran.showcaseview.ShowcaseView.updateBitmap(ShowcaseView.java:171)
at com.github.amlcurran.showcaseview.ShowcaseView.onGlobalLayout(ShowcaseView.java:354)
at android.view.ViewTreeObserver.dispatchOnGlobalLayout(ViewTreeObserver.java:655)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2054)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1190)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4860)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:766)
at android.view.Choreographer.doCallbacks(Choreographer.java:575)
at android.view.Choreographer.doFrame(Choreographer.java:542)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:751)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:5751)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1083)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:850)
at dalvik.system.NativeStart.main(Native Method)
As I stated above, this error does not occur all the time. It seems to happen about (but not exactly) 2-3 times, then 2-3 runs go through without a problem.
Here is my resources file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container_fragment_person_list"
android:tag="PersonListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.PersonListFragment">
<TextView
android:id="@+id/textView_add_guardian_placeholder"
android:layout_centerInParent="true"
android:layout_width="1dp"
android:layout_height="1dp" />
<TextView
android:id="@+id/textView_intro_placeholder"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:minWidth="1dp"
android:minHeight="1dp"
android:layout_width="1dp"
android:layout_height="1dp" />
<ListView
android:visibility="gone"
android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:orientation="vertical"
android:id="@id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" >
<TextView
android:text="@string/no_people"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageButton
android:id="@+id/imageButton_empty_text"
android:src="@drawable/ic_man_silhouette_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/generic_content_description"/>
<TextView
android:id="@+id/test"
android:text="@string/tap_icon_to_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
And here is my java. Please notice that I even tried hard-coding a width and height for my ViewTarget, but still get inconsistent errors. I also tried creating placeholder TextViews in my resources file, but still no go.
public class PersonListFragment extends BaseListFragment {
private PersonAdapter personAdapter;
private PersonModel personModel;
private int personCount;
private TextView tvTargetIntro;
public static PersonListFragment newInstance(String tag, Long index) {
PersonListFragment fragment = new PersonListFragment();
Bundle args = new Bundle();
args.putString(TAG, tag);
args.putLong(INDEX, index);
fragment.setArguments(args);
return fragment;
}
public PersonListFragment() {
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(People_FetchedEvent ignored) {
refreshList();
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(Person_CreatedEvent ignored) {
String createType;
if(ignored.getId() == 0 | ignored.getPerson().getId() == null) {
createType = resources.getString(R.string.added);
} else {
createType = resources.getString(R.string.updated);
}
MessageManager.getInstance().makeToast(getActivity(), ignored.getPerson().getName(), " ", createType);
fm.popBackStack();
refreshList();
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(Person_BuiltEvent ignored) {
makeCreatePersonBackgroundTask(ignored.getPerson());
}
@SuppressWarnings("UnusedDeclaration")
public void onEventMainThread(Person_DeletingEvent ignored) {
personModel.deletePersonByLocalId(ignored.getId());
MessageManager.getInstance().makeToast(getActivity(), PersonController.getInstance().getCurrentPerson().getName() + " " + resources.getString(R.string.removed));
refreshList();
FragmentManager fm = getChildFragmentManager();
fm.popBackStack();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
personModel = PersonModel.getInstance();
personAdapter = new PersonAdapter(getActivity().getLayoutInflater(), getActivity(), ListType.PROFILE_INFO);
setListAdapter(personAdapter);
personCount = PersonModel.getInstance().getPersonCount();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_person_list, container, false);
LinearLayout layoutEmptyList = (LinearLayout) view.findViewById(android.R.id.empty);
tvTargetIntro = (TextView) view.findViewById(R.id.textView_intro_placeholder);
ImageButton imageButtonEmptyText = (ImageButton) view.findViewById(R.id.imageButton_empty_text);
imageButtonEmptyText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction ft;
ft = fm.beginTransaction();
ft.replace(R.id.container_fragment_person_list, PersonEditFragment.newInstance("PERSON_EDIT_FRAGMENT", (long) 0, new Person()), "PERSON_EDIT_FRAGMENT");
ft.addToBackStack(null);
ft.commit();
fm.executePendingTransactions();
}
});
switch(personCount) {
case 0:
break;
case 1:
break;
default:
}
return view;
}
private void makeShowCaseIntro() {
ViewTarget target1 = new ViewTarget(tvTargetIntro);
tvTargetIntro.setWidth(1);
tvTargetIntro.setHeight(1);
ShowcaseView sv = new ShowcaseView.Builder(getActivity())
.setTarget(target1)
.setContentTitle(resources.getString(R.string.showcase_intro_title))
.setContentText(resources.getString(R.string.showcase_intro_text))
.setStyle(R.style.CustomShowcaseTheme2)
.build();
sv.setButtonText(resources.getString(R.string.next));
sv.show();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
makeShowCaseIntro();
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
PersonController.getInstance().setCurrentPerson(personAdapter.getItem(position));
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container_fragment_person_list, PersonDisplayFragment.newInstance("PERSON_DISPLAY_FRAGMENT", PersonController.getInstance().getLocalId(), PersonController.getInstance().getCurrentPerson()), "PERSON_DISPLAY_FRAGMENT");
ft.addToBackStack(null);
ft.commit();
fm.executePendingTransactions();
}
private void refreshList() {
new SimpleBackgroundTask<LazyList<Person>>(getActivity()) {
@Override
protected LazyList<Person> onRun() {
return PersonModel.getInstance().lazyLoadPeople();
}
@Override
protected void onSuccess(LazyList<Person> result) {
personAdapter.replaceLazyList(result);
}
}.execute();
}
private void makeCreatePersonBackgroundTask(Person person) {
jobManager.addJobInBackground(new CreatePersonJob(person));
fm.popBackStack();
}
@Override
public void onResume() {
super.onResume();
jobManager.addJobInBackground(new FetchPeopleJob());
if(dataDirty) {
refreshList();
dataDirty = false;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
FragmentTransaction ft;
Person person = PersonController.getInstance().getCurrentPerson();
ft = fm.beginTransaction();
switch(item.getItemId()) {
case R.id.action_new:
ft.replace(R.id.container_fragment_person_list, PersonEditFragment.newInstance("PERSON_EDIT_FRAGMENT", (long) 0, new Person()), "PERSON_EDIT_FRAGMENT");
ft.addToBackStack(null);
ft.commit();
fm.executePendingTransactions();
return true;
case R.id.action_edit:
ft.replace(R.id.container_fragment_person_list, PersonEditFragment.newInstance("PERSON_EDIT_FRAGMENT", person.getId(), person), "PERSON_EDIT_FRAGMENT");
ft.addToBackStack(null);
ft.commit();
fm.executePendingTransactions();
return true;
case R.id.action_remove:
String title = MessageManager.getInstance().makeString(resources.getString(R.string.remove), " ", person.getName());
String message = MessageManager.getInstance().makeString(resources.getString(R.string.message_confirm_remove), " ", person.getName(), resources.getString(R.string.punctuation_question));
final InfoDialogFragment dialog = InfoDialogFragment.newInstance(title, message, DialogActionType.Delete, DialogActionTarget.Person, person.getId());
dialog.show(ft, DIALOG_TAG);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
I'm pretty sure this is some timing issue with the way android draws out objects, but I don't have the knowledge to know why they're drawn correctly on some runs but not on others.
Please don't zap this question unless you're sure that it has been asked elsewhere with respect to an intermittent problem :-)
Any help is appreciated.
回答1:
This is a known issue : Github issues when updateBitmap() is called too early.
This issue comes from Bitmap.createBitmap() method either width or height equals to 0.
A workaround is to delay the ShowcaseView creation more:
someView.post(new Runnable() {
@Override
public void run() {
// display ShowcaseView here
}
});
You could also change the updateBitmap() method from the library to not create the bitmap if the view width or height is wrong.
回答2:
Had the same problem, and posted my solution in another thread: https://stackoverflow.com/a/25521608/1752670
I changed the ShowcaseView class slightly
回答3:
go to com.github.amlcurran.showcaseview.ShowcaseView
and change this method
private void updateBitmap() {
if ((bitmapBuffer == null || haveBoundsChanged()) && getMeasuredHeight() > 0 && getMeasuredWidth() > 0) {
if(bitmapBuffer != null)
bitmapBuffer.recycle();
int width = getMeasuredWidth();
int height = getMeasuredHeight();
if(width > 0 && height > 0)
bitmapBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
}
回答4:
This was a bug in ShowcaseView, and was fixed starting in v5.4.2: https://github.com/amlcurran/ShowcaseView/commit/c79c60dc798f081fb62e48c549c7bdbff8da51b9
So, you can just update your build.gradle
to:
compile 'com.github.amlcurran.showcaseview:library:5.4.2'
来源:https://stackoverflow.com/questions/25456289/showcaseview-width-and-height-must-be-0