自定义listview android中的textview不稳定

Posted

技术标签:

【中文标题】自定义listview android中的textview不稳定【英文标题】:The textview is not stable in custom listview android 【发布时间】:2019-02-24 07:02:30 【问题描述】:

实际上我有一个包含倒数计时器的自定义列表视图,倒数计时器是由处理程序创建的,现在列表加载正常,一切似乎都是正确的,但是当我开始滚动倒数计时器时,值变得不稳定且不稳定似乎彼此重叠意味着 lastrow 值打印在第一行中,诸如此类的值是向上和向下的,并且它不能正常工作,这里 API 发送一个 long 值,该值传递给处理程序,处理程序将其转换到倒数计时器,所以问题出在哪里,每当我刷新列表时一切都很好,但是当我开始滚动时,同样的问题又来了..这是我的代码

public class fixtures extends Fragment 

 private ListView fixtureListView;
 String Balance,userEmail;
 SwipeRefreshLayout mSwipeRefreshLayout;
 private static final String FORMAT = "%02d:%02d:%02d";
 List<ListView_fixture_conveyer> fixture_conveyerList;
 ListView_fixture_conveyer fixtureList;


@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) 
    View view = inflater.inflate(R.layout.fixtures, viewGroup, false);
    fixtureListView = view.findViewById(R.id.fixture_list);
    mSwipeRefreshLayout = view.findViewById(R.id.swipeToRefresh);
    User user = SharedPrefManager.getInstance(getActivity()).getUser();
    userEmail= user.getEmail();
    new JSONTask().execute("http://www.judgement6.com/judgement_files/fixture_json.php");


    DisplayImageOptions options = new DisplayImageOptions.Builder()

            .cacheInMemory(true)
            .cacheOnDisk(true)

            .build();
    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(Objects.requireNonNull(getActivity()))
            .defaultDisplayImageOptions(options)
            .build();
          com.nostra13.universalimageloader.core.ImageLoader.getInstance().init(config);


    mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() 
        @Override
        public void onRefresh() 

            fixture_conveyerList.clear();
            new JSONTask().execute("http://www.judgement6.com/judgement_files/fixture_json.php");

            mSwipeRefreshLayout.setRefreshing(false);
        
    );

    return view;



@SuppressLint("StaticFieldLeak")
public class JSONTask extends AsyncTask<String, String, List<ListView_fixture_conveyer>> 

    ProgressDialog loading;

    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        loading = ProgressDialog.show(getActivity(), "loading,please wait...", null, true, true);
    

    @Override
    protected List<ListView_fixture_conveyer> doInBackground(String... params) 
        HttpURLConnection connection = null;
        BufferedReader reader = null;

        try 

            URL url = new URL(params[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            InputStream stream = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(stream));
            StringBuilder buffer = new StringBuilder();
            String line = "";
            while ((line = reader.readLine()) != null) 
                buffer.append(line);
            


            String finalJson = buffer.toString();
            JSONObject parentObject = new JSONObject(finalJson);
            JSONArray parentArray = parentObject.getJSONArray("list");
            fixture_conveyerList = new ArrayList<ListView_fixture_conveyer>();

            for (int i = 0; i < parentArray.length(); i++) 
                JSONObject finalObject = parentArray.getJSONObject(i);
                Log.e("fixtureObject",finalObject.toString());
                fixtureList = new ListView_fixture_conveyer();
                fixtureList.setTournament(finalObject.getString("tournament"));
                fixtureList.setTeam1_photo(finalObject.getString("team1_photo"));
                fixtureList.setTeam2_photo(finalObject.getString("team2_photo"));
                fixtureList.setTeam1_name(finalObject.getString("team1_name"));
                fixtureList.setTeam2_name(finalObject.getString("team2_name"));
                fixtureList.setTime(finalObject.getString("Time"));
                fixture_conveyerList.add(fixtureList);
            

            return fixture_conveyerList;

         catch (IOException | JSONException e) 
            e.printStackTrace();
         finally 
            if (connection != null) 
                connection.disconnect();
            
            try 
                if (reader != null) 
                    reader.close();
                
             catch (IOException e) 
                e.printStackTrace();
            
        
        return null;
    

    @Override
    protected void onPostExecute(List<ListView_fixture_conveyer> result) 
        super.onPostExecute(result);

        if (result !=null) 
            loading.dismiss();
            ListAdapter adapter = new ListAdapter(getActivity(), R.layout.custom_list_fixture, result);
            fixtureListView.setAdapter(adapter);

        
        else
        
            Toast.makeText(getActivity(), "No Internet Connection!", Toast.LENGTH_LONG).show();
            loading.dismiss();
        


  

public class ListAdapter extends ArrayAdapter 

    private List<ListView_fixture_conveyer> fixture_conveyerList;
    private int resource;
    private LayoutInflater inflater;

    ListAdapter(Context context, int resource, List<ListView_fixture_conveyer> objects) 
        super(context, resource, objects);
        fixture_conveyerList = objects;
        this.resource = resource;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    

    @Override
    public int getViewTypeCount() 
        return getCount();
    

    @Override
    public int getItemViewType(int position) 
        return position;
    

    @NonNull
    @Override
    public View getView(final int position, View convertView, @NonNull ViewGroup parent) 

        if (convertView == null) 
            convertView = inflater.inflate(resource, null);
        

        final TextView team1_name,team2_name;
        final TextView tournament,time;
        ImageView team1_photo,team2_photo;

        team1_photo =  convertView.findViewById(R.id.team1);
        team2_photo =  convertView.findViewById(R.id.team2);
        team1_name =  convertView.findViewById(R.id.team1_name);
        team2_name =  convertView.findViewById(R.id.team2_name);
        tournament= convertView.findViewById(R.id.tournament);
        time= convertView.findViewById(R.id.timecounter);
        ImageLoader.getInstance().displayImage(fixture_conveyerList.get(position).getTeam1_photo(), team1_photo);
        ImageLoader.getInstance().displayImage(fixture_conveyerList.get(position).getTeam2_photo(), team2_photo);

        team1_name.setText(fixture_conveyerList.get(position).getTeam1_name());
        team2_name.setText(fixture_conveyerList.get(position).getTeam2_name());
        tournament.setText(fixture_conveyerList.get(position).getTournament());
        time.setText(fixture_conveyerList.get(position).getTime());

        Log.e("mytimer",fixture_conveyerList.get(position).getTime());

        if (!("false").equals(fixture_conveyerList.get(position).getTime()))
            Log.e("inside_mytimer",fixture_conveyerList.get(position).getTime());

        long newValue=Long.parseLong(fixture_conveyerList.get(position).getTime());
        new CountDownTimer(newValue, 1000) 

            @SuppressLint("DefaultLocale", "SetTextI18n")
            public void onTick(long millisUntilFinished) 

                time.setText("" + String.format(FORMAT,
                        TimeUnit.MILLISECONDS.toHours(millisUntilFinished),
                        TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(
                                TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
                        TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(
                                TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished))));

            

            public void onFinish() 
                time.setText("Fixture closed");
            
        .start();
        
        else
            time.setText("Fixture closed");
        


        return convertView;
    
    
 

这是我的模型类代码

public class ListView_fixture_conveyer 

private String tournament;
private String team1_photo;
private String team2_photo;
private String team1_name;
private String team2_name;
private String time;

public String getTime() 
    return time;


public void setTime(String time) 
    this.time = time;




public String getTeam1_name() 
    return team1_name;


public void setTeam1_name(String team1_name) 
    this.team1_name = team1_name;


public String getTeam2_name() 
    return team2_name;


public void setTeam2_name(String team2_name) 
    this.team2_name = team2_name;



public String getTournament() 
    return tournament;


public void setTournament(String tournament) 
    this.tournament = tournament;




public String getTeam1_photo() 
    return team1_photo;


public void setTeam1_photo(String team1_photo) 
    this.team1_photo = team1_photo;


public String getTeam2_photo() 
    return team2_photo;


public void setTeam2_photo(String team2_photo) 
    this.team2_photo = team2_photo;



【问题讨论】:

最好使用 RecylerView 好的,但是现在请帮我解决这个问题,因为我无法在这个项目中更改它 使用持有人模式。 我怎么没用过这个 【参考方案1】:

编辑 (已测试)

---> 对于 Timer 问题,您需要在类中获取 time 变量并更新变量 with Handler 将其与重新加载数据一起使用。喜欢,

Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() 
    @Override
    public void run() 
         for (int i = 0, dataLength = fixture_conveyerList.size(); i < dataLength; i++) 
               ListView_fixture_conveyer item = fixture_conveyerList.get(i);
               item.timeRemaining -= 1000;
         
        adapter.notifyDataSetChanged();
        timerHandler.postDelayed(this, 1000); //run every Second

    
;

列出适配器类

  public class ListAdapter extends ArrayAdapter 

    private List<ListView_fixture_conveyer> fixture_conveyerList;
    private int resource;
    private LayoutInflater inflater;
    ViewHolder holder;

    ListAdapter(Context context, int resource, List<ListView_fixture_conveyer> objects) 
        super(context, resource, objects);
        fixture_conveyerList = objects;
        this.resource = resource;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        timerHandler.postDelayed(timerRunnable, 50);   //start unique timer

    

    @Override
    public int getViewTypeCount() 
        return getCount();
    

    @Override
    public int getItemViewType(int position) 
        return position;
    

    @NonNull
    @Override
    public View getView(final int position, View convertView, @NonNull ViewGroup parent) 

        if (convertView == null) 
            convertView = inflater.inflate(resource, null);
            holder = new ViewHolder();
            holder.team1_photo = convertView.findViewById(R.id.team1);
            holder.team2_photo = convertView.findViewById(R.id.team2);
            holder.team1_name = convertView.findViewById(R.id.team1_name);
            holder.team2_name = convertView.findViewById(R.id.team2_name);
            holder.tournament = convertView.findViewById(R.id.tournament);
            holder.time = convertView.findViewById(R.id.timecounter);
            convertView.setTag(holder);

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


        ImageLoader.getInstance().displayImage(fixture_conveyerList.get(position).getTeam1_photo(), holder.team1_photo);
        ImageLoader.getInstance().displayImage(fixture_conveyerList.get(position).getTeam2_photo(), holder.team2_photo);
        holder.team1_name.setText(fixture_conveyerList.get(position).getTeam1_name());
        holder.team2_name.setText(fixture_conveyerList.get(position).getTeam2_name());
        holder.tournament.setText(fixture_conveyerList.get(position).getTournament());
        holder.time.setText(fixture_conveyerList.get(position).timeRemaining);

        Log.e("mytimer", fixture_conveyerList.get(position).getTime());

        if (!("false").equals(fixture_conveyerList.get(position).getTime())) 
            Log.e("inside_mytimer", fixture_conveyerList.get(position).getTime());

            long newValue = fixture_conveyerList.get(position).timeRemaining;
         if (newValue > 0) 

            holder.time.setText(String.format(FORMAT,
                    TimeUnit.MILLISECONDS.toHours(newValue),
                    TimeUnit.MILLISECONDS.toMinutes(newValue) - TimeUnit.HOURS.toMinutes(
                            TimeUnit.MILLISECONDS.toHours(newValue)),
                    TimeUnit.MILLISECONDS.toSeconds(newValue) - TimeUnit.MINUTES.toSeconds(
                            TimeUnit.MILLISECONDS.toMinutes(newValue))));
         else 
           holder.time.setText("Fixture closed");
        



         else 
            holder.time.setText("Fixture closed");
        


        return convertView;
    

【讨论】:

除最后一个之外的所有计时器都消失了,它只打印来自 API 本身的原始值,当我滚动列表时最后一个也会抖动 你在哪里定义timeRemaining?? 我在哪里添加那个可以制作计时器的处理程序??@Abhay Koradiya 我需要在我的模型类中添加它吗?你能检查我的模型类并具体告诉我。 怎么样,我的意思是准确的

以上是关于自定义listview android中的textview不稳定的主要内容,如果未能解决你的问题,请参考以下文章

android下拉刷新和滑动到底部加载更多,自定义listview

Android - ListView 中的 EditTexts 绑定到自定义 ArrayAdapter - 跟踪更改

ArrayIndexOutOfBoundsException 与 ListView 中的多个视图的自定义 Android 适配器

将自定义 ListView 项传递给 Android 中的其他活动

自定义ListView的RelativeLayout中的Android布局居中

Android Studio,如何使用数组或光标中的数据填充自定义 ListView?