【问题标题】:Spinner doesn't show the selected item微调器不显示所选项目
【发布时间】:2016-10-20 20:45:11
【问题描述】:

您好,我在 android 中制作了一个简单的应用程序,它连接到服务器并获取帖子列表,然后我有一个 spinner,其中填充了每个帖子的标题,您可以选择其中一个。

这一切都有效,直到我必须选择一个帖子,我打开spinner,它显示了我选择一个的所有标题,没有任何反应,帖子没有在spinner 中选择并且文本没有'不要改变,我读了 10 篇关于微调器没有显示项目但我无法使其工作的帖子,请帮助我,这是我的 java 代码:

package com.example.lagarto.blog;

import android.graphics.Color;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import org.w3c.dom.Text;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import android.util.Log;
import android.widget.Spinner;

public class MainActivity extends AppCompatActivity {
    ArrayList<Post> archivo=new ArrayList<Post>();
    ArrayList<String> titulos=new ArrayList<String>();
    public ArrayAdapter<String> spinnerArrayAdapter;
    private static final String TAG= MainActivity.class.getSimpleName();
    private class GetDBConnection extends AsyncTask<Integer, Void, String>{
        @Override
        protected String doInBackground(Integer... params) {
            try{
                Connection conn= DBConnection.getInstance().getConnection();
                Statement st= conn.createStatement();
                String sql=("SELECT * FROM posts");
                ResultSet rs=st.executeQuery(sql);
                while(rs.next()) {
                    int id = rs.getInt("Id");
                    String title = rs.getString("Title");
                    String body = rs.getString("Body");
                    String date = rs.getString("Date");
                    Post post = new Post(id, title, body, date);
                    archivo.add(post);
                    System.out.println(archivo);
                }
                Log.d(TAG,"Terminado");
            }catch(SQLException e){
                e.printStackTrace();
            }
            return "Valido";
        }

        @Override
        protected void onPostExecute(String result) {
            Spinner spinner=(Spinner) findViewById(R.id.spinner);
            spinner.setVisibility(View.VISIBLE);
            for (Post i:archivo) {
                titulos.add(i.getTitle());
            }
            TextView title=(TextView) findViewById(R.id.title);
            TextView body=(TextView) findViewById(R.id.body);
            title.setVisibility(View.VISIBLE);
            body.setVisibility(View.VISIBLE);
            TextView connection=(TextView) findViewById(R.id.connection);
            connection.setVisibility(View.INVISIBLE);
            spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                    spinnerArrayAdapter.notifyDataSetChanged();
                    Post resultado=archivo.get(position);
                    title.setText(resultado.getTitle());
                    body.setText(resultado.getBody());
                }

                @Override
                public void onNothingSelected(AdapterView<?> parent) {
                    spinnerArrayAdapter.notifyDataSetChanged();
                    Post resultado=archivo.get(0);
                    title.setText(resultado.getTitle());
                    body.setText(resultado.getBody());
                }
            });

        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new GetDBConnection().execute(0);
        Spinner spinner=(Spinner) findViewById(R.id.spinner);
        spinnerArrayAdapter=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, titulos);
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(spinnerArrayAdapter);
        spinner.setSelection(1);
        System.out.println(archivo);



    }


}

这是我的 xml 代码:

<?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/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.lagarto.blog.MainActivity">



    <TextView
        android:layout_width="400dp"
        android:layout_height="50dp"
        android:text="Hello World!"
        android:textSize="30dp"
        android:textAlignment="center"
        android:layout_alignParentEnd="true"
        android:id="@+id/title"
        android:layout_marginTop="40dp"
        android:visibility="invisible"
        />
    <TextView
        android:layout_width="400dp"
        android:layout_height="500dp"
        android:text="Hello World!"
        android:textSize="16dp"
        android:layout_marginTop="100dp"
        android:layout_alignParentEnd="true"
        android:id="@+id/body"
        android:visibility="invisible"
        />

    <Spinner
        android:layout_width="400dp"
        android:layout_height="50dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/spinner"
        android:textSize="20dp"
        android:visibility="invisible"
        android:backgroundTint="@color/colorPrimaryDark"
        android:textAlignment="center"
        />

    <TextView
        android:text="Waiting for connection please wait"
        android:layout_width="400dp"
        android:layout_height="100dp"
        android:textSize="30dp"
        android:textAlignment="center"
        android:layout_marginTop="150dp"
        android:id="@+id/connection" />


</RelativeLayout>

【问题讨论】:

  • 我认为如果你把spinner.setOnItemSelectedListener放在onCreate上会更好。您应该集中获取数据的后台进程。
  • 它没有修复错误:/
  • 奇怪...onPostExecute 完成后您是否得到任何 logcat?
  • 因为我怀疑spinner.setSelection(1); 将返回IndexOutOfBoundsException,因为您的AsyncTask 尚未完成......

标签: java android xml android-layout spinner


【解决方案1】:

好的,这是我的评估:

TL;DR

您尝试在后台线程上更新 UI。

解释

这是你在onCreate上的一段代码

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new GetDBConnection().execute(0);
    Spinner spinner=(Spinner) findViewById(R.id.spinner);
    spinnerArrayAdapter=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, titulos);
    spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(spinnerArrayAdapter);
    spinner.setSelection(1);
    System.out.println(archivo);
}

基于此的几点建议:

  • 之前调用了GetDBConnection,您的微调器甚至准备好了。您的GetDBConnection 将在后台异步运行,因此当您为您的微调器获取数据设置onItemSelectedListener(我稍后会解释)时,您已经创建了一个竞争条件并设置启动你的微调器。
  • 您的微调器似乎已填充,但这并不是一个好的做法。
  • 然后,使用spinner.setSelection(1); 设置选择,异步调用是否已完成。我忘了这是否应该引发异常。

现在开始你的onPostExecute 代码:

@Override        
protected void onPostExecute(String result) {
    Spinner spinner=(Spinner) findViewById(R.id.spinner);
    spinner.setVisibility(View.VISIBLE);
    for (Post i:archivo) {
        titulos.add(i.getTitle());
    }
    TextView title=(TextView) findViewById(R.id.title);
    TextView body=(TextView) findViewById(R.id.body);
    title.setVisibility(View.VISIBLE);
    body.setVisibility(View.VISIBLE);
    TextView connection=(TextView) findViewById(R.id.connection);
    connection.setVisibility(View.INVISIBLE);
    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            spinnerArrayAdapter.notifyDataSetChanged();
            Post resultado=archivo.get(position);
            title.setText(resultado.getTitle());
            body.setText(resultado.getBody());
        }
        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            spinnerArrayAdapter.notifyDataSetChanged();
            Post resultado=archivo.get(0);
            title.setText(resultado.getTitle());
            body.setText(resultado.getBody());
        }
    });
}
  • 如果您想即时更新微调器的元素,您还应该在适配器中包含更新(添加、删除或更新)List 元素的方法。
  • 就像我之前提到的,将侦听器放在AsyncTask 中虽然可能适用,但并不是一个好习惯。更不用说您也尝试更改 UI(设置 TextView 值)。这将产生错误,因为您的调用不在 UI 线程上。这就是为什么我说你应该将AsyncTask 集中在only 获取数据上

假设您有自己的自定义适配器,这是我的自定义适配器,它能够处理数据更新:

public abstract class CustomListAdapter<T> extends BaseAdapter {
    protected List<T> mData = new ArrayList<>();
    protected LayoutInflater mInflater;
    protected ViewHolder holder;

    /*truncated*/

    public void addItem(T item){
        mData.add(item);
        notifyDataSetChanged();
    }

    public void clear(){
        mData = new ArrayList<>();
        notifyDataSetChanged();
    }

    public void deleteItem(int position){
        mData.remove(position);
        notifyDataSetChanged();
    }

    public void fill(Collection<T> items){
        mData.addAll(items);
        notifyDataSetChanged();
    }
}

当然,这只是一个例子。

总结

尝试如下更新您的代码:

//Declare your elements here first;

TextView title;
TextView body;
TextView connection;
Spinner spinner;

private class GetDBConnection extends AsyncTask<Integer, Void, String>{
    @Override
    protected String doInBackground(Integer... params) {
        try{
            Connection conn= DBConnection.getInstance().getConnection();
            Statement st= conn.createStatement();
            String sql=("SELECT * FROM posts");
            ResultSet rs=st.executeQuery(sql);
            while(rs.next()) {
                int id = rs.getInt("Id");
                String title = rs.getString("Title");
                String body = rs.getString("Body");
                String date = rs.getString("Date");
                Post post = new Post(id, title, body, date);
                archivo.add(post);
                System.out.println(archivo);
            }
            Log.d(TAG,"Terminado");
        }catch(SQLException e){
            e.printStackTrace();
        }
        return "Valido";
    }

    @Override
    protected void onPostExecute(String result) {
        /*
            all code that changes your UI should resides in the UI Thread. This is still in Background Thread.
        */
        //Spinner spinner=(Spinner) findViewById(R.id.spinner); --> this is also unneccessary
        //spinner.setVisibility(View.VISIBLE);

        /*
            something like this is possible as long as it doesn't change your UI.
        */
        for (Post i:archivo) {
            titulos.add(i.getTitle());
            /*
            - update your Adapter List elements here.
            */
        }
        // - also call your adapter notifyDataSetChanged here, if neccessary.

        //TextView title=(TextView) findViewById(R.id.title); --> unneccessary!
        //TextView body=(TextView) findViewById(R.id.body); --> unneccessary!
        //title.setVisibility(View.VISIBLE);
        //body.setVisibility(View.VISIBLE);
        //TextView connection=(TextView) findViewById(R.id.connection); --> unneccessary!
        //connection.setVisibility(View.INVISIBLE);

        /*
            instead, you can call another method that resides in the UI Thread 
        */
        // updateUI();
        /*
            or, execute them under runOnUIThread()
        */
        runOnUIThread(new Runnable(){
            @Override
            public void run(){
                spinner.setVisibility(View.VISIBLE);
                title.setVisibility(View.VISIBLE);
                body.setVisibility(View.VISIBLE);
                connection.setVisibility(View.INVISIBLE);
            }
        });
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /*
            you should initiate ALL your UI elements on the onCreate()
        */
        spinner=(Spinner) findViewById(R.id.spinner);
        title=(TextView) findViewById(R.id.title);
        body=(TextView) findViewById(R.id.body);
        connection=(TextView) findViewById(R.id.connection);
        spinnerArrayAdapter=new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, titulos);
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        /*
            then, set your listeners
        */
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                //spinnerArrayAdapter.notifyDataSetChanged(); --> this is unneccessary
                Post resultado=archivo.get(position);
                title.setText(resultado.getTitle());
                body.setText(resultado.getBody());
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                //spinnerArrayAdapter.notifyDataSetChanged(); --> this is unneccessary
                Post resultado=archivo.get(0);
                title.setText(resultado.getTitle());
                body.setText(resultado.getBody());
            }
        });
        spinner.setAdapter(spinnerArrayAdapter);
        System.out.println(archivo);

        new GetDBConnection().execute(0);   // --> After all has been set, then execute your AsyncTask.
    }

    private void updateUI(){
        spinner.setVisibility(View.VISIBLE);
        title.setVisibility(View.VISIBLE);
        body.setVisibility(View.VISIBLE);
        connection.setVisibility(View.INVISIBLE);
    }
}

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多