在繁忙的 ListView 中更新 TextView 而不会失去 Spinner 焦点

问题描述 投票:0回答:2

我使用自定义用户速率对传感器进行采样(这使 ListView 忙碌),并在列表视图中显示值,因此我有一个带有 3 个文本视图(用于 x、y 和 z 值)和一个微调器的自定义列表视图。

我的布局是:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="fill_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:minWidth="140dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="X:"
            android:id="@+id/tvX"
            android:focusable="false"
            android:focusableInTouchMode="false"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="Y:"
            android:focusable="false"
            android:focusableInTouchMode="false"
            android:id="@+id/tvY" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="Z:"
            android:focusable="false"
            android:focusableInTouchMode="false"
            android:id="@+id/tvZ" />
    </LinearLayout>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="30dp">

        <Spinner
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:id="@+id/spinner"/>
    </LinearLayout>

</LinearLayout>

我使用此代码作为适配器:

public class customListView extends BaseAdapter
{
    public Activity context;
    ArrayList<MyActivity.SensorProperties> sensorPropertieses;
    public String[] spinnerValues;

    public LayoutInflater inflater;


    public  customListView(Activity context, ArrayList<MyActivity.SensorProperties> sensorPropertieses, String[] spinnerArray)
    {
        super();
        this.context = context;
        this.sensorPropertieses = sensorPropertieses;
        spinnerValues = spinnerArray;
        this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return sensorPropertieses.size();
    }

    @Override
    public Object getItem(int i) {
        return null;
    }

    @Override
    public long getItemId(int i) {
        return 0;
    }

    class ViewHolder
    {
        TextView Xvalue, Yvalue, Zvalue;
        Spinner spinner;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup)
    {
        ViewHolder holder;
        if (view == null)
        {
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.custom_layout, null);

            holder.Xvalue = (TextView) view.findViewById(R.id.tvX);
            holder.Yvalue = (TextView) view.findViewById(R.id.tvY);
            holder.Zvalue = (TextView) view.findViewById(R.id.tvZ);
            holder.spinner = (Spinner) view.findViewById(R.id.spinner);

            // populate spinner
            ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>
                    (view.getContext(), android.R.layout.simple_spinner_item, spinnerValues);
            holder.spinner.setAdapter(dataAdapter);
            
            view.setTag(holder);
        }
        else
            holder = (ViewHolder) view.getTag();


        // update sensor values
        holder.Xvalue.setText(String.valueOf("X: " + sensorPropertieses.get(i).x));
        holder.Yvalue.setText(String.valueOf("Y: " + sensorPropertieses.get(i).y));
        holder.Zvalue.setText(String.valueOf("Z: " + sensorPropertieses.get(i).z));

        return view;
    }
}

我的主要活动代码是(布局仅包含一个按钮和列表视图):

public class MyActivity extends Activity implements SensorEventListener
{
    public class SensorProperties
    {
        public float x = 0, y = 0, z = 0;
    }

    ListView listView;
    ArrayList<SensorProperties> sensorPropertieses = new ArrayList<SensorProperties>();
    customListView adapter;
    SensorManager sensorManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        // let's work only on two nodes
        sensorPropertieses.add(new SensorProperties());
        sensorPropertieses.add(new SensorProperties());

        listView = (ListView) findViewById(R.id.listView);
        String[] spinnerValues = new String[] {"A", "B", "C"};
        adapter = new customListView(MyActivity.this, sensorPropertieses, spinnerValues);
        listView.setAdapter(adapter);

        Button btnRegister = (Button) findViewById(R.id.buRegister);
        btnRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view)
            {
                RegisterToSensors();
            }
        });
    }

    void RegisterToSensors()
    {
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_FASTEST);
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent)
    {
        SensorProperties tmp = new SensorProperties();
        tmp.x = sensorEvent.values[0];
        tmp.y = sensorEvent.values[1];
        tmp.z = sensorEvent.values[2];
        if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
            sensorPropertieses.set(0, tmp);
        else
            sensorPropertieses.set(1, tmp);
        adapter.notifyDataSetChanged();
    }
    ///...
}

问题:尽管我更新了 TextView 频率,但我应该如何使用包含 TextView 和 Spinner 的 ListView 而不丢失微调器焦点?

编辑

感谢

mmlooloo
评论,我更改了问题标题和正文。

明确一点:

  • 如果 ListView 不忙,我成功下拉微调器
  • 当我更新 TextView 频率而不是 ListView 时,我成功下拉微调器
  • 仅当 ListView 且列表视图繁忙时才会出现此问题

编辑2

目前,我不确定问题是否是旋转器焦点丢失。为了进行调试,我在自定义列表视图中更新文本视图中的传感器值(在

// update sensor values
之前)之前添加了 30 毫秒的睡眠时间:

try {
    Thread.sleep(30);
} catch (InterruptedException e) {
    e.printStackTrace();
}

我成功地下拉旋转器并在文本视图更新时选择另一个项目(一切都很慢,但有效!)。

编辑3

我现在发现,问题可能出在

adapter.notifyDataSetChanged()
,因为当我将文本视图打印变灰时,我也无法放下微调器。

底线,我真的不知道根本原因是什么,但当我更新列表视图中的文本视图频率时,我无法下拉微调器,问题是为什么?

android listview android-spinner android-sensors
2个回答
3
投票

这里的问题是你经常调用adapter.notifyDataSetChanged();在你的 onSensorChanged 方法中,所以它每次都会绑定 listview 你的 getView 每次都会被调用,并且每次都会设置微调值。

我所做的是,在 onSensorChanged 方法中访问你的列表视图的第一个和第二个子视图,然后我访问了 texviews 并根据需要频繁更新它们 您也可以访问您的微调器。

@Override
public void onSensorChanged(SensorEvent sensorEvent) {
    // SensorProperties tmp = new SensorProperties();
    // tmp.x = sensorEvent.values[0];
    // tmp.y = sensorEvent.values[1];
    // tmp.z = sensorEvent.values[2];
    // if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
    // sensorPropertieses.set(0, tmp);
    // else
    // sensorPropertieses.set(1, tmp);
    // adapter.notifyDataSetChanged();

    Log.i("tag", "ensorEvent.values[0] = " + sensorEvent.values[0]);

    if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        View childView = (View) listView.getChildAt(0);
        TextView xTextView = (TextView) childView.findViewById(R.id.tvX);
        xTextView.setText(String.valueOf(sensorEvent.values[0]));
        TextView yTextView = (TextView) childView.findViewById(R.id.tvY);
        yTextView.setText(String.valueOf(sensorEvent.values[1]));
        TextView zTextView = (TextView) childView.findViewById(R.id.tvZ);
        zTextView.setText(String.valueOf(sensorEvent.values[2]));
    } else {
        View childView = (View) listView.getChildAt(1);
        TextView xTextView = (TextView) childView.findViewById(R.id.tvX);
        xTextView.setText(String.valueOf(sensorEvent.values[0]));
        TextView yTextView = (TextView) childView.findViewById(R.id.tvY);
        yTextView.setText(String.valueOf(sensorEvent.values[1]));
        TextView zTextView = (TextView) childView.findViewById(R.id.tvZ);
        zTextView.setText(String.valueOf(sensorEvent.values[2]));
    }

}

1
投票

运行这段代码,它会给你一些想法!

public class MainActivity extends ActionBarActivity {
    List<myItem> myItemList;
    ListView list;
    boolean isTouchEvent = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myItemList = new ArrayList<myItem>();

        for (int i = 0; i < 9; i++) {
            myItem m = new myItem();
            m.setMyText("This is item number "+i);
            myItemList.add(m);
        }

        list = (ListView)findViewById(R.id.list);
        list.setAdapter(new MyAdapter(this, R.layout.list_item, myItemList));
        list.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                    long arg3) {

                Toast.makeText(MainActivity.this, "You have clicked item number "+arg2, Toast.LENGTH_SHORT).show();

            }

        });

        list.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                isTouchEvent = true;
                return false;
            }
        });

    }

    class MyAdapter extends ArrayAdapter<myItem> {

        Context ctx;
        public MyAdapter(Context context, int resource, List<myItem> objects) {
            super(context, resource, objects);
            ctx = context;

        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final ViewHolder holder;

            if(convertView == null){

                holder = new ViewHolder();
                LayoutInflater inflater = (LayoutInflater)ctx.getSystemService (Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.list_item, parent, false);
                holder.txt = (TextView)convertView.findViewById(R.id.TextView_txt);
                holder.sp = (Spinner)convertView.findViewById(R.id.Spinner_sp);

                List<String> spinnerValues = new ArrayList<String>();
                for (int i = 0; i < 5; i++) {
                    String temp = "Val #" + i;
                    spinnerValues.add(temp);
                }
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(ctx,android.R.layout.simple_spinner_item,spinnerValues);
                adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                holder.sp.setAdapter(adapter);
                convertView.setTag(holder);     

            }else {
                holder = (ViewHolder)convertView.getTag();  
            }

            holder.sp.setOnTouchListener(new OnTouchListener() {

                @Override
                public boolean onTouch(View arg0, MotionEvent arg1) {
                    isTouchEvent = true;
                    return false;
                }
            });

            holder.sp.setOnItemSelectedListener(new OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> arg0, View arg1,
                        int arg2, long arg3) {
                    if(!isTouchEvent){
                        return;
                    }
                    String spinnerStringValue = (String)holder.sp.getAdapter().getItem(arg2);
                    holder.txt.setText("You have selected "+ spinnerStringValue );
                    holder.txt.invalidate();
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {

                }

            });

            holder.txt.setText(myItemList.get(position).getMyText());
            return convertView;
        }



    }

    static class  ViewHolder {
        public TextView txt;
        public Button bt;
        public Spinner sp;
    }

    public class myItem {

        private String myText="";

        public String getMyText() {
            return myText;
        }

        public void setMyText(String myText) {
            this.myText = myText;
        }

    }

}

activity_main.xml:

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants"
    />

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:descendantFocusability="blocksDescendants"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/TextView_txt"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
         android:layout_marginLeft="16dip" />


    <Spinner
        android:id="@+id/Spinner_sp"
        android:layout_marginLeft="50dip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
© www.soinside.com 2019 - 2024. All rights reserved.