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.

+3


source to share


4 answers


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.

+7


source


Had the same problem and posted my solution on another thread: fooobar.com/questions/2158935 / ...



I changed the ShowcaseView class a bit

0


source


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);

        }
    }

      

0


source


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'

0


source







All Articles