关于Listview、Girdview的setSelection无效的解决方法与解析

我的解决方法就是,将setSelection放到handler的post方法中,这样就解决了这个问题。

			new Handler().post(new Runnable() {
				
				@Override
				public void run() {
					listView.setSelection(position);
					
				}
			});


至于原因,本人在网上也查了许多,但是也没有人说出一个具体的原因,大致都是说在setSelection的时候,主线程可能在做其他操作,导致setSelection失效。

我查看了一下安卓源码。handler.post源码:

    /**
     * Causes the Runnable r to be added to the message queue.
     * The runnable will be run on the thread to which this handler is 
     * attached. 
     *  
     * @param r The Runnable that will be executed.
     * 
     * @return Returns true if the Runnable was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }


很简单,就是调用了sendMessageDelayed方法,作用就是把一个Runnable加入到消息队列中,它是放在handler所在线程的消息队列之中。

再看sendMessageDelayed源码:

    /**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

同样也是很简单,但是注意!这个方法的注释这样写道:

 Enqueue a message into the message queue after all pending messages 。

将一个消息加入排队在所有等待消息的最后。

看到这便恍然大悟,可能正是这个方法的原因,保证了setSelection在最后执行,而不与其他主线程的操作产生冲突。

同时想到:

关于View的测量,我们不能直接通过view.getMeasuredWidth(),view.getMeasuredHeight()方法得到高度,但是我们可以在view.post()的方法中调用view.getMeasuredWidth(),view.getMeasuredHeight()获得,其原因应该也就是,view.post()同样也调用了sendMessageDelayed()方法,它使得调用getMeasuredWidth()方法时,在消息队列的最后,此时view已经绘制完成,因此可以得到宽高度。

结论:

setSelection方法要在主线程的handler.post中进行。如果还是不行,可以试试

		new Handler().post(new Runnable() {
			
			@Override
			public void run() {
				adapter.notifyDataSetChanged();
				listView.setSelection(position);
				
			}
		});


如果大家有什么看法,或者我说的有所不足,欢迎大家指出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值