为视图设置相同的 id 后,findViewByID 返回 null
Posted
技术标签:
【中文标题】为视图设置相同的 id 后,findViewByID 返回 null【英文标题】:findViewByID returns null after setting same id to the view 【发布时间】:2016-03-17 19:22:59 【问题描述】:我在 onCreate() 中膨胀 layout,这已在我的活动中声明:
layout = (RelativeLayout) findViewById(R.id.layout);
假设 id 在我的活动中被声明为 int。
稍后,在某些事件之后,我将一个图像视图添加到此 布局
id = (int) Calendar.getInstance().getTimeInMillis();
ImageView imageView = new ImageView(context);
imageView.setImageResource(R.drawable.ic_launcher);
imageView.setId(id);
layout.addView(imageView);
稍后,我想从我们之前设置的 id 中获取 imageView:
ImageView imageView = (ImageView) findViewById(id);
if (imageView == null)
Log.e("Test", "imageview is null");
所有代码都成功运行,Imageview 总是返回 null,如日志中打印的那样。
注意:我无法保留 imageview 本身的对象,因为我在实际项目中有许多不同的视图。在这里,我使用单个 imageview 描述了我的问题。我已经存储了视图的所有 ID,但无法使用 findViewById() 获取所有这些视图。我之所以使用 Calendar.getInstance().getTimeInMillis() 来生成 id 是因为我每次都想要一个唯一的 id。我已经存储了所有布局数据,包括 id 以供以后使用。如果用户再次打开此活动,他将从他离开的地方开始。因此,在添加任何新的 imageview 时,不得重复之前生成的 id。
关键点:如果我将设备日期时间提前 2-3 天或更早,那么它可以正常工作。我认为问题在于使用日历生成 id。
【问题讨论】:
正确阅读问题。我不能这样做,因为我使用的是多个视图而不是单个图像视图。 我希望您不会对所有图像视图使用相同的 id,是吗? 显然不是。即使我使用相同,为什么我会得到 null? 您能否展示更多代码,例如如何生成和设置 id? 问题中都提到了。 【参考方案1】:最后,我通过尝试和错误得到了解决方案。
正如我所提到的,它在 2 天前工作正常,我决定使用生成的 id 进行调试,并通过每次减少日期来从long
转换为int
。假设计数器在活动中声明为int
。
ImageView imageView = new ImageView(context);
imageView.setImageResource(R.drawable.ic_launcher);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) - counter);
counter++;
String date = getDate(calendar.getTimeInMillis(), "dd/MM/yyyy hh:mm:ss.SSS");
Log.e("Test", "Date :" + date);
int id = (int) calendar.getTimeInMillis();
Log.e("Test", "ID:" + id);
imageView.setId(id);
layout.addView(imageView);
imageView = (ImageView) findViewById(id);
if (imageView == null)
Log.e("Test", "imageview is null");
else
Log.e("Test", "not null");
日志:
03-17 23:13:44.952: E/Test(1469): Date :17/03/2016 11:13:44.952
03-17 23:13:44.952: E/Test(1469): ID:-2018055688
03-17 23:13:44.952: E/Test(1469): imageview is null
03-17 23:13:48.744: E/Test(1469): Date :16/03/2016 11:13:48.745
03-17 23:13:48.744: E/Test(1469): ID:-2104451895
03-17 23:13:48.748: E/Test(1469): imageview is null
03-17 23:13:53.376: E/Test(1469): Date :15/03/2016 11:13:53.380
03-17 23:13:53.376: E/Test(1469): ID:2104120036
03-17 23:13:53.376: E/Test(1469): not null
在这里,我发现我在过去两天得到了 negative int,而在此之前我得到了 positive int。如文档中所述,您应该将 id 设置为正整数。然后我使用以下方法将相同的 id 转换为绝对值:
id = Math.abs(id);
一切正常。
最后,我想知道为什么 setId()
设置为非正数 int
时不会给出异常。他们应该给出例外,因为他们已经提到它应该是正整数,以便任何开发人员都知道问题出在哪里。
【讨论】:
关于id为负时他们应该给出异常的部分,发现这个answer:int必须为正,否则为随意如果我的理解是正确的,如果提供的id是正确的,android自己会生成一个未指定的随机id来代替。【参考方案2】:如果您不提供需要从中查找视图的容器,例如 View v = findViewById(id)
,那么这将尝试在使用的 xml 中查找视图。
这样做
ImageView imageView = (ImageView) layout.findViewById(id);
if (imageView == null)
Log.e("Test", "imageview is null");
注意:
使用它来动态生成 id
int id = System.currentTimeMillis();
getTimeInMillis()
返回日历表示的时间,必要时从其字段重新计算时间。如果未设置时间并且无法从当前字段值计算时间。这可能是你的情况,你不能得到毫秒。
Official doc
【讨论】:
@BrijeshChopda 是id
一个正整数?
它只是一个 int。 int 可以有正数也可以有负数。
@BrijeshChopda 尝试System.currentTimeMillis();
生成 id。请查看我的更新答案。【参考方案3】:
当以编程方式生成 id 时,您应该使用以下代码来设置视图的 id,
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
myView.setId(Utils.generateViewId());
else
myView.setId(View.generateViewId());
你可以用它来设置id并测试它吗?
【讨论】:
我不能使用它,因为当用户再次进入活动并且其他视图可能具有这些 id 时,它们会从 1、2、3 之类的开头生成 id。跨度> 【参考方案4】:好的,所以我去社区四处看看,看到了有关如何在 R.id
中动态添加 id 以供 findViewById()
使用的帖子。起初我认为您应该继续使用View.generateViewId()
,但正如您在其中一个答案中评论的那样,您不喜欢使用它。因此,我选择了您的实现并进行了尝试,并添加了一些日志等。首先,这是我的简单活动代码:
MainActivity.java
package com.example.my.myapplication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout llmain = (LinearLayout) findViewById(R.id.ll_main);
int id = (int) System.currentTimeMillis();
Log.d("SAMPLE", "Generated ID: " + id);
ImageView imageView = new ImageView(this);
imageView.setImageResource(R.drawable.sample_img);
imageView.setId(id);
llmain.addView(imageView);
Log.d("SAMPLE", "Get ID: " + imageView.getId());
ImageView iv = (ImageView) findViewById(id);
if (iv == null)
Log.d("SAMPLE", "ID: IMAGE VIEW IS NULL!");
else
Log.d("SAMPLE", "ID: ImageView not null!");
所以我去试了一下..这里是日志..
03-18 10:54:47.907 29562-29562/com.example.my.myapplication D/SAMPLE: Generated ID: -2019192733
03-18 10:54:47.913 29562-29562/com.example.my.myapplication D/SAMPLE: Get ID: -2019192733
03-18 10:54:47.913 29562-29562/com.example.my.myapplication D/SAMPLE: ID: IMAGE VIEW IS NULL!
然后我从setId()的文档中看到:
标识符应该是一个正数。
请注意,之前生成的 id 是否定。所以我去把id生成改成这样:
int id = Math.abs((int) System.currentTimeMillis());
并尝试再次运行它,这是日志:
03-18 10:58:05.073 32662-32662/? D/SAMPLE: Generated ID: 2018995567
03-18 10:58:05.080 32662-32662/? D/SAMPLE: Get ID: 2018995567
03-18 10:58:05.080 32662-32662/? D/SAMPLE: ID: ImageView not null!
请注意,现在生成的 id 是正。现在它能够以某种方式识别它。
【讨论】:
以上是关于为视图设置相同的 id 后,findViewByID 返回 null的主要内容,如果未能解决你的问题,请参考以下文章
constraintsWithVisualFormat 为所有视图设置相同的 Y 位置
如何将相同的viewmodel设置为xamarin表单中的新mvvm中的两个视图
如何将附件视图背景设置为与 UItableViewCell 中的内容视图相同的背景?