3

目的

Android 3.0 のドラッグ アンド ドロップ フレームワークに従って、「ListView からアイテムを並べ替える」パラダイムを実装しました。

問題

Android 4.0.3 および 4.0.4 で見られます。他のリリースではテストされていません。

ListView の項目をドラッグし、ListView の最後の項目の後にドロップします。シャドー ボックスがクリアされ、ListView が無効になります。これは通常の動作であり、90% の確率で発生します。

しかし、残りの 10% については、次のようになります。

  • onDrag(View, DragEvent): 以下にリストされているすべての効果は、が に戻った後に見られACTION_DRAG_ENDEDます。つまり、問題が発生する前に、ドラッグ アンド ドロップ プロセス全体が完了しているように見えます。
  • シャドー ボックスが表示されるのは、消える前にわずか 10 秒です。ハンドラー forを呼び出すview.invalidate()と、それは修正されますが、ハングまたは再起動の問題は修正されません (以下を参照)。onDrag(View, DragEvent)ACTION_DRAG_ENDED
  • logcat のいくつかの異常なトレース:

I/ViewRootImpl( 954): レポート ドロップ結果: true I/InputQueue-JNI( 210): 入力メッセージがまだ進行中に登録解除されているため、入力チャネル 'ドラッグ (クライアント)' の完了信号を送信しています。I/InputQueue-JNI( 210): 登録されなくなったチャネルの終了信号を無視します。W/WindowManager( 210): ドラッグは進行中ですが、ドラッグ ウィンドウ ハンドルがありません。I/ViewRootImpl( 954): レポート ドロップ結果: true

  • 一部のデバイスでは、Android がハングまたは再起動します。デバイスによって異なりますが、効果は常に同じです。

ソースコード

import android.annotation.SuppressLint;
import android.app.ListActivity;
import android.content.ClipData;
import android.content.ClipDescription;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class TestReorderActivity extends ListActivity {

    @SuppressLint("NewApi")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ListView listView = getListView();
        String[] listeStrings = { "France", "United States", "Russia" };
        listView.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, listeStrings));

        listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {

            @Override
            public boolean onItemLongClick(AdapterView<?> adapter, View view,
                    int id, long position) {
                ClipData data = ClipData.newPlainText(" ",
                        Long.toString(position));

                DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
                        view);
                if (view.startDrag(data, shadowBuilder/*
                                                     * new
                                                     * MyDragShadowBuilder(view)
                                                     */, view, 0)) {
                    return true;
                }

                return false;
            }

        });

        listView.setOnDragListener(new ListView.OnDragListener() {

            @Override
            public boolean onDrag(View view, DragEvent event) {
                final int action = event.getAction();

                switch (action) {
                case DragEvent.ACTION_DRAG_STARTED:

                    if (event.getClipDescription().hasMimeType(
                            ClipDescription.MIMETYPE_TEXT_PLAIN)) {
                        // accept drag
                        return true;
                    } else {
                        // reject drag
                        return false;
                    }

                case DragEvent.ACTION_DRAG_ENTERED:
                    // entered drag
                    return true;

                case DragEvent.ACTION_DRAG_LOCATION:
                    // location is returned as event.getX() and event.getY()
                    return true;

                case DragEvent.ACTION_DRAG_EXITED:
                    // cancel drag.
                    return true;

                case DragEvent.ACTION_DROP:
                    // item dropped
                    processDrop(event);
                    return true;

                case DragEvent.ACTION_DRAG_ENDED:
                default: // unknown case
                    return true;
                }
            }

            private boolean processDrop(DragEvent event) {
                ClipData data = event.getClipData();
                if ((data != null) && (data.getItemCount() > 0)) {
                    ClipData.Item item = data.getItemAt(0);
                    CharSequence value = item.getText();
                    long position = Long.valueOf(value.toString());

                    int x = (int) event.getX();
                    int y = (int) event.getY();

                    ListView listView = getListView();

                    int newPosition = listView.pointToPosition(x, y);
                    if (newPosition > ListView.INVALID_POSITION) {

                        swap(position, newPosition);
                        return true;
                    }
                }

                return false;
            }

        });

    }

    // swap(long, long) here
}
4

2 に答える 2

0

その理由は次のとおりです。画面のアップロード action_move が遅すぎます。

通常、画面上で指を動かしていなくても、アクション ムーブは非常に頻繁にアップロードされます。ただし、一部の電話画面はそれほど敏感ではありません。

電話のしきい値を変更できます。カーネルのサポートが必要です。

于 2013-03-19T10:19:23.533 に答える
0

これは、 unregisterInputChannel がロックを取得できず、デッドロックが発生するためです。

于 2013-03-21T09:24:02.160 に答える