14

Android 3.x のドラッグ アンド ドロップ メカニズムに問題があります。いくつかのドラッグ (たとえば 30 回のドラッグ) を行った後、例外が発生します (添付のリンクを参照)。

https://groups.google.com/forum/#!msg/android-platform/2APvO248NNY/rKI-5dCT8XcJ (その投稿に添付されているものと同じものがログに記録されています..)

Android の技術者は、API のバグであると回答し、問題を回避する唯一の方法はガベージ コレクターを呼び出すことだと述べています。

やったよ。例外はスローされなくなりましたが、しばらくすると (さらに 30 ~ 40 回ドラッグすると)、Android は何らかの理由でドロップ イベントの呼び出しを停止します。

すべてのリソース/キャンバス/描画キャッシュ/リサイクル ビットマップを解放してすべてのビューを「更新」しようとしましたが、それらを再作成しましたが、役に立ちませんでした (もう例外をスローしませんでしたが、いくつかドラッグした後でもドロップ イベントは発生しません)。作業)

「役立つ」唯一のことは、アクティビティを閉じて、もう一度再開することです。

誰かがこの問題を何らかの形で解決したか、または良い簡単な代替手段を持っていますか??? (独自のドラッグアンドドロップ機能を実装する以外に..)

想定していないものを再起動または再作成することを強制しないソリューションを取得したいと思います..

バグを示すサンプル コードを次に示します(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>

これはスタック トレースです。

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 回繰り返すと、例外がスローされます。この非常に単純な例を作成して、アプリケーションによってオーバーヘッドが発生することなく例外がスローされることを示しました。

ティア

4

5 に答える 5

1

これを試して: -

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();
    }
}
于 2012-07-19T22:39:25.683 に答える
0

これを試して:

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

Android 3.2でうまくいきました!

于 2012-06-04T11:17:17.300 に答える
0

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

于 2012-06-04T11:42:15.017 に答える
0

その質問をしてからかなりの時間が経過しました。Android ICS がリリースされたとき、このバグはもう存在しませんでした。したがって、Android ICS 以降、Honeycomb を対象としたアプリケーションを作成する理由はまったくありません。いずれにせよ、このバージョンの OS を実行している Android デバイス全体の 0.3% しかありません。

だから私にとっての答えは - ハニカムを使用しないことです! :->

于 2013-01-12T11:31:33.837 に答える
0

アクティビティを再起動しても問題が解決しない場合は、ビューを削除してから再度追加して (新しいインスタンスの可能性があります)、ビューを再起動してみてください。また、invalidate() のような通常のスタッフ (通常は役に立ちません) を試して、onDraw() をオーバーライドし、呼び出される理由と呼び出されない理由を確認することもできます。

于 2012-03-14T13:06:27.070 に答える