findViewByID returns 为视图设置相同的 id 后为 null

findViewByID returns null after setting same id to the view

我在 onCreate() 中膨胀 layout,它已经在我的 activity:

中声明
layout = (RelativeLayout) findViewById(R.id.layout);

假设 id 在我的 activity.

中声明为 int

稍后,在一些事件之后我向这个 layout

添加了一个 imageview
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 总是 returns 日志中打印的 null。

Note: I can't able to keep the object of imageview itself because I have many number of different views in real project. Here I have described my problem using single imageview. I have stored all the ids of the views but can't able to get all those views using findViewById(). The reason why I have used Calendar.getInstance().getTimeInMillis() to generate id is because I want a unique id everytime. I have stored all the layout data including ids for later use. If user again opens this activity anytime, he will get from where he left off. So while adding any new imageview the id must not be repeated which is generated earlier.

Keypoint: If I set the device date-time 2-3 or more days earlier then it is worknig properly. I think the issue is with generating the id using calendar.

如果您不提供需要从中查找视图的容器,如 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() Returns 日历表示的时间,必要时从其字段重新计算时间。如果未设置时间并且无法根据当前字段值计算时间。这可能是你的情况,你不能得到毫秒。

Official doc

以编程方式生成 ID 时,您应该使用以下代码设置视图的 ID,

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {

   myView.setId(Utils.generateViewId());

} else {

   myView.setId(View.generateViewId());

}

你能用它来设置 id 并测试它吗?

好的,所以我四处看看社区,看到了关于如何在 R.id 中动态添加 id 以供 findViewById() 使用的帖子。起初我认为你应该继续使用 View.generateViewId() 但正如你在其中一个答案中评论的那样,你不喜欢使用它。所以我接受了你的实施并进行了尝试,添加了一些日志等。首先,这是我的简单 activity 代码:

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()的文档中看到:

The identifier should be a positive number.

注意之前生成的id是negative。所以我去把 id generation 改成这样:

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是positive。现在它能够以某种方式识别它。

最后,我通过试错找到了解决方案。 正如我所提到的,它在 2 天前工作正常,我决定通过每次减少日期来使用从 long 生成并转换为 int 的 id 进行调试。假设计数器在 activity.

中声明为 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 则不给出异常。他们应该给出例外,因为他们已经提到它应该是 postive int 这样任何开发人员都会知道问题是什么。