“必须已调用 setView"- 自定义类扩展按钮 [英] "setView must have been called" - Custom Class extending button

查看:23
本文介绍了“必须已调用 setView"- 自定义类扩展按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个 12 x 9 的按钮"网格,称为瓷砖".Tile.java 扩展了小部件按钮".

So I've got a 12 x 9 grid of "buttons" called "tiles". Tile.java extends the widget "Button".

不过,我现在遇到了一个问题,我试图让按钮显示一个 Toast 来回忆按下按钮的 ID.

I've got an issue right now though, where I'm trying to get the button to display a toast that recalls the ID of the button pushed.

网格是动态添加的,我希望它保持这种状态.

The grid is added dynamically and I want it to stay that way.

这是来自 GameBoardActivity.java 的代码:

Here's the code from GameBoardActivity.java:

这会生成 12x9 的tiles"网格并为每个网格添加一个监听器.

This makes the 12x9 grid of "tiles" and adds a listener for each.

    public void gridRowButtons(int iterations){
    final Tile[] gridSpaces = new Tile[12];
    LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
    for (int i = 0; i < 12; i++) {
        String idString = String.valueOf(aToI[iterations]) + String.valueOf(i + 1);
        final int id = getResources().getIdentifier(idString, "id", getPackageName());
        gridSpaces[i] = new Tile(getApplicationContext());
        gridSpaces[i].setText("");
        gridSpaces[i].setHeight(40);
        gridSpaces[i].setWidth(40);
        gridSpaces[i].setLayoutParams(buttonParams);
        gridSpaces[i].setId(id);
        OnClickListener showID = new OnClickListener(){
            public void onClick(View view){                 
                TextView text = (TextView) findViewById(R.id.tileIDText);
                String tileID = getApplicationContext().getResources().getResourceEntryName(id);
                text.setText(tileID);
                Tile clickedTile = (Tile) findViewById(id);
                clickedTile.tileClick(0, tileID);
            }
        };
        gridSpaces[i].setOnClickListener(showID);
    }
    LinearLayout buttonRow = new LinearLayout(getApplicationContext());
    buttonRow.setOrientation(LinearLayout.HORIZONTAL);
    buttonRow.setLayoutParams(buttonParams);
    LinearLayout boardSpace = (LinearLayout) this.findViewById(R.id.boardLayout);
    for (int i = 0; i < gridSpaces.length; i++) {
        buttonRow.addView(gridSpaces[i]);
    }
    boardSpace.addView(buttonRow);
}

这里是上面提到的 tileClick 方法:

And here's the tileClick method mentioned above:

    public void tileClick(int action, String tileID) {
    switch(action) {
        case 1 :
            //action 1
        case 2 :
            //action 2
        default :
            Context context = getContext();
            Toast toast = new Toast(context);
            Toast.makeText(context, tileID, Toast.LENGTH_SHORT);
            toast.show();
    }
}

LogCat 显示以下内容:

The LogCat shows the following:

02-22 20:45:14.623: E/AndroidRuntime(7868): FATAL EXCEPTION: main
02-22 20:45:14.623: E/AndroidRuntime(7868): java.lang.RuntimeException: setView must have been called
02-22 20:45:14.623: E/AndroidRuntime(7868):     at android.widget.Toast.show(Toast.java:103)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at com.jneal.ecquire.Tile.tileClick(Tile.java:51)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at com.jneal.ecquire.GameBoardActivity$1.onClick(GameBoardActivity.java:55)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at android.view.View.performClick(View.java:3627)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at android.view.View$PerformClick.run(View.java:14329)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at android.os.Handler.handleCallback(Handler.java:605)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at android.os.Handler.dispatchMessage(Handler.java:92)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at android.os.Looper.loop(Looper.java:137)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at android.app.ActivityThread.main(ActivityThread.java:4511)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at java.lang.reflect.Method.invokeNative(Native Method)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at java.lang.reflect.Method.invoke(Method.java:511)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:976)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:743)
02-22 20:45:14.623: E/AndroidRuntime(7868):     at dalvik.system.NativeStart.main(Native Method)

这是怎么回事?我的 MainActivity.java 中显示 Toast 的代码几乎完全相同,并且可以毫无问题地执行.是不是因为我扩展了 Button 并且它不知道视图已经是什么?此外,由于某种原因,Eclipse 不会让我添加 setView().我确定我在这里遇到了封装问题,但我对它们是什么感到困惑.提前感谢您的帮助.Jrad

What's going on? I've got virtually the exact same code for displaying a toast in my MainActivity.java and that executes with no problem. Is it because I've extended Button and it doesn't know what the view is already? Also, Eclipse won't let me add setView() for some reason. I'm sure I've got encapsulation issues here but I'm confused as to what they are. Thanks for your help in advance. JRad

推荐答案

将下面的代码行更改为以下几行:

Change the lines of code below, to the one's that follow:

        Toast toast = new Toast(context);
        Toast.makeText(context, tileID, Toast.LENGTH_SHORT);
        toast.show();

改为:

    Toast toast = Toast.makeText(context, tileID, Toast.LENGTH_SHORT);
    toast.show();       

从源代码中可以看出,只有当 mNextView 为 null 时才会抛出该异常.函数makeText"应该设置它,并且确实设置了它,但是您的原始代码没有捕获对它构建的 Toast 的引用.相反,您的原始代码会创建两个 Toast,并尝试显示"尚未设置其视图的那个.

As you can see from the source code, that exception is thrown only when mNextView is null. The function "makeText" is suppose to set it, and it does, but your original code does not capture the reference to the Toast it builds. Instead, your original code creates two Toasts, and attempts to "show" the one which has not yet had its view set.

public void show() {
    if (mNextView == null) {
        throw new RuntimeException("setView must have been called");
    }

....

public static Toast makeText(Context context, CharSequence text, int duration) {
    Toast result = new Toast(context);

    LayoutInflater inflate = (LayoutInflater)
            context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
    TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
    tv.setText(text);

    result.mNextView = v;
    result.mDuration = duration;

    return result;
}

这篇关于“必须已调用 setView"- 自定义类扩展按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆