перетаскивание в Android 3.x вызывает недопустимое состояние исключения после небольшого числа перетаскиваний

есть проблема с механизмом перетаскивания в android 3.x: после некоторых перетаскиваний (скажем, 30 перетаскиваний) возникает исключение (см. Прикрепленную ссылку)

https://groups.google.com/forum/#!msg/android-platform/2APvO248NNY/rKI-5dCT8XcJ (я получаю в журнале то же самое, что и прикрепленное к этому сообщению..)

Android-техник отвечает там, что это ошибка в API, и говорит, что единственный способ избежать проблемы — вызвать сборщик мусора.

Я сделал это. исключение больше не выбрасывалось, но через некоторое время (скажем, более 30-40 перетаскиваний) андроид по какой-то причине перестает вызывать событие drop.

Я попытался «обновить» все представление, освободив все ресурсы/холст/кеш рисования/переработав растровые изображения и заново создав их, и это не помогло (больше не выдавало исключение, но все же после некоторых перетаскиваний событие падения не т работает)

единственное, что «помогает», — это закрыть активность и перезапустить ее снова.

кто-нибудь решил эту проблему как-то, или есть хорошая простая альтернатива??? (помимо реализации моей собственной функции перетаскивания..)

Я хотел бы получить решение, которое не заставит меня перезапускать или воссоздавать что-либо, что не предполагается.

вот пример кода, который демонстрирует ошибку (не демонстрирует ту часть, о которой я говорил о проблеме с событием перетаскивания после использования System.GC):

public class DragandDropExampleActivity extends Activity {

private boolean mIsBeenDragged = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final ImageView imageViewToDRag = (ImageView) findViewById(R.id.image_view_to_drag);

    imageViewToDRag.setClickable(true);

    imageViewToDRag.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                mIsBeenDragged = true;
                DragShadowBuilder shadowBuilder = new DragShadowBuilder(imageViewToDRag);
                imageViewToDRag.startDrag(null, shadowBuilder, imageViewToDRag, 0);
            } else if (event.getAction() == MotionEvent.ACTION_UP) {

                mIsBeenDragged = false; 
            }
            return false;
        }
    });

}
}

это xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<ImageView
    android:id="@+id/image_view_to_drag"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher" >

</ImageView>

this is the stack trace:

06-04 13:34:32.730: E/View(8061):
java.lang.IllegalArgumentException
    at android.view.Surface.lockCanvasNative(Native Method)
    at android.view.Surface.lockCanvas(Surface.java:350)
    at android.view.View.startDrag(View.java:11489)
    at com.show.dragandrop.DragandDropExampleActivity$1.onTouch(DragandDropExampleActivity.java:32)
    at android.view.View.dispatchTouchEvent(View.java:4617)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1560)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1291)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java: 1862)
    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1286)
    at android.app.Activity.dispatchTouchEvent(Activity.java:2315)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1835)
    at android.view.View.dispatchPointerEvent(View.java:4689)
    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2415)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:2077)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:132)
    at android.app.ActivityThread.main(ActivityThread.java:4126)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
    at dalvik.system.NativeStart.main(Native Method)

Чтобы исключить начисление - просто перетащите изображение в какую-то точку экрана и оставьте палец. повторите это ровно 30 раз, и будет выброшено исключение. Я сделал этот очень простой пример, чтобы продемонстрировать, что исключение выдается без каких-либо накладных расходов, вызванных моим приложением.

ТИА


person Tal Kanel    schedule 05.03.2012    source источник
comment
Не могли бы вы добавить пример кода для игры? Я думаю, что это что-то об отмененных мероприятиях. Где объекты находятся в состоянии вторжения.   -  person rekire    schedule 03.06.2012
comment
Да, я могу, но я сейчас не на своей рабочей станции, поэтому я опубликую это завтра.. спасибо   -  person Tal Kanel    schedule 03.06.2012
comment
@rekire: я добавил код. жду, чтобы увидеть, что вы придумали. кстати - на эмуляторе исключение не кидается   -  person Tal Kanel    schedule 04.06.2012
comment
@TalKanel Это плохо, у меня нет подходящего устройства. Я все равно посмотрю.   -  person rekire    schedule 04.06.2012
comment
@rekire: исключение выдается также из эмулятора, я только что еще раз проверил   -  person Tal Kanel    schedule 04.06.2012
comment
это «в com.show.dragandrop.DragandDropExampleActivity$1.onTouch(DragandDropExampleActivity.java:32)» выглядит как причина такой вещи. Взгляните на эту строку кода. Вы можете найти там   -  person Paulius Vindzigelskis    schedule 06.06.2012
comment
Вам это как-то помогает? stackoverflow.com/questions/8875702/   -  person Vrashabh Irde    schedule 07.06.2012
comment
@Vrashabh: похоже, это имеет какое-то отношение, я проверю это более серьезно позже. спасибо   -  person Tal Kanel    schedule 08.06.2012


Ответы (5)


Попробуй это: -

private OnTouchListener drag = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            setViewPosition(v, Math.round(event.getRawX()),
                    Math.round(event.getRawY()));
        }
        return false;
    }
};


private void setViewPosition(View v, int x, int y) {
    if (v != null) {
        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT);
        params.leftMargin = (x - v.getMeasuredWidth() / 2);
        params.topMargin = (y - v.getMeasuredHeight() / 2);
        v.setLayoutParams(params);
        v.invalidate();
    }
}
person Talha    schedule 19.07.2012

Если перезапуск действия помогает, попробуйте перезапустить представление, удалив его и добавив снова (может быть, новый экземпляр). Также вы можете попробовать обычный персонал (обычно это не помогает), например, invalidate(), переопределить onDraw() и посмотреть, почему он вызывается или не вызывается.

person Ilya Gazman    schedule 14.03.2012
comment
хорошая мысль, но если это было недостаточно ясно - я тоже пробовал, и это не помогло. в любом случае - я хотел бы иметь решение, которое не заставит меня перезапускать/удалять что-либо... - person Tal Kanel; 15.03.2012

Попробуй это:

imageViewToDRag.startDrag(null, shadowBuilder, imageViewToDRag, 0);
System.gc();

У меня сработало на Android 3.2!

person Eng.Fouad    schedule 04.06.2012
comment
пробовал уже. Я написал об этом в теле вопроса. в простом демонстрационном приложении это помогает, но когда я использую его много раз, события перетаскивания через некоторое время перестают вызываться. также это не настоящее решение, вызывающее GC.. - person Tal Kanel; 04.06.2012

Из комментария к < href="https://stackoverflow.com/questions/7385536/android-3-0-drag-n-drop-illegalargumentexception-after-30-actions">вопрос, касающийся проблемы, которую вы опубликовали в Google Обсуждение в группах:

Эта проблема возникает из-за того, что GC не выполняет сбор перетаскиваний. Но если окно перерисовывается, GC выполняет сбор перетаскиваний. Окно будет перерисовано после открытия программной клавиатуры или обновления какого-либо ImageView или чего-то в этом роде.

Таким образом, похоже, что вы можете заставить сборщик мусора собирать объекты перетаскивания, принудительно перерисовывая содержащий View. У меня нет под рукой устройства 3.0, но, возможно, стоит попробовать что-то вроде этого:

        } else if (event.getAction() == MotionEvent.ACTION_UP) {
           findViewById(R.id.main_frame).invalidate();
        }

Вам также может понадобиться предложенная подсказка по сбору мусора:

        } else if (event.getAction() == MotionEvent.ACTION_UP) {
           findViewById(R.id.main_frame).invalidate();
           System.gc();
        }

но я думаю, что вы правы, если хотите избежать этого, если это возможно, поэтому я бы попробовал это только в том случае, если без него это не сработает.

Кроме того, я думаю, что onTouch() должно возвращать true, так как вы использовали событие касания.

person Darshan Rivka Whittle    schedule 04.06.2012

много времени прошло с тех пор, как я задал этот вопрос. когда был выпущен Android ICS - этой ошибки больше не было. поэтому, поскольку Android ICS действительно не имеет смысла писать приложения, ориентированные на Honeycomb. в любом случае только 0,3% от общего числа устройств Android с этой версией ОС,

так что для меня ответ - просто не использовать Honeycomb! :->

person Tal Kanel    schedule 12.01.2013