ShowcaseView - width and height must be> 0
Research has proven fruitless as all other references to this error seem to be reliably repeatable; I cannot 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 said above, this error does not occur all the time. It seems to happen (but not quite) 2-3 times, then 2-3 runs pass without problems.
Here is my resource 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. Note that I even tried to hardcode the width and height for my ViewTarget, but I still get conflicting errors. I also tried to create placeholder TextViews in my resource file but still don't 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 sure this is a definite problem with how android pulls objects, but I have no knowledge to know why they are drawn correctly on some runs but not others.
Please do not ask this question unless you are sure if asked elsewhere regarding an intermittent problem :-)
Any help is appreciated.
source to share
This is a known issue: Github issues when updateBitmap () is called too early.
This issue comes from the Bitmap.createBitmap () method of either width or height equal to 0. The
workaround is to delay the creation of the ShowcaseView any longer:
someView.post(new Runnable() {
@Override
public void run() {
// display ShowcaseView here
}
});
You can also change the updateBitmap () method from the library to not generate bitmaps if the view width or height is incorrect.
source to share
Had the same problem and posted my solution on another thread: fooobar.com/questions/2158935 / ...
I changed the ShowcaseView class a bit
source to share
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);
}
}
source to share
This was a bug in ShowcaseView and has been fixed since 5.4.2: https://github.com/amlcurran/ShowcaseView/commit/c79c60dc798f081fb62e48c549c7bdbff8da51b9
So, you can simply update your build.gradle
to:
compile 'com.github.amlcurran.showcaseview:library:5.4.2'
source to share