在Android中更改ImageView的位置出现问题

4
我在我的Android应用程序中似乎无法更改ImageView的位置。这种情况发生在我将代码放置在特定方法中时,如下所述。
我在我的Android项目中使用IndoorAtlas库。我下载了示例应用程序并在手机上运行。效果很好。
此库具有一个onServiceUpdate方法,用于处理位置更新。我的目标是在位置更新时移动ImageView。非常简单。
以下是示例提供的原始方法(对我来说工作正常):
/* IndoorAtlasListener interface */

/**
* This is where you will handle location updates.
*/
public void onServiceUpdate(ServiceState state) {
    mSharedBuilder.setLength(0);
    mSharedBuilder.append("Location: ")
            .append("\n\troundtrip : ").append(state.getRoundtrip()).append("ms")
            .append("\n\tlat : ").append(state.getGeoPoint().getLatitude())
            .append("\n\tlon : ").append(state.getGeoPoint().getLongitude())
            .append("\n\tX [meter] : ").append(state.getMetricPoint().getX())
            .append("\n\tY [meter] : ").append(state.getMetricPoint().getY())
            .append("\n\tI [pixel] : ").append(state.getImagePoint().getI())
            .append("\n\tJ [pixel] : ").append(state.getImagePoint().getJ())
            .append("\n\theading : ").append(state.getHeadingDegrees())
            .append("\n\tuncertainty: ").append(state.getUncertainty());
    log(mSharedBuilder.toString());
}

以下是我用来更新ImageView位置的代码:
ImageView imgPoint = (ImageView) findViewById(R.id.imagePoint);
imgPoint.setX(250);
imgPoint.setY(200);

如果我将这些行添加到上面的onServiceUpdate方法中,该方法不起作用。 onServiceUpdate方法中的任何内容都不会运行。
但是,如果我将这3行放在onCreate或任何其他方法中,则可以正常工作。 ImageView能够成功移动。
我还注意到,如果在onServiceUpdate中添加一个ToastAlert,同样的事情会发生。 onServiceUpdate方法根本没有触发。
Toast.makeText(getApplicationContext(), "Hello!",
      Toast.LENGTH_LONG).show();

这是我的activity_main.xml文件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="300dp"
        android:layout_weight="1">

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/imageView"
            android:layout_weight="1" />

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1">

            <ImageView
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_marginTop="1dp"
                android:layout_marginLeft="1dp"
                android:id="@+id/imagePoint"
                android:layout_weight="1" />

        </RelativeLayout>

        </RelativeLayout>

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

我认为这是因为你将它放在了一个RelativeLayout中,而该布局又位于另一个布局内部。你可以改变图片的位置,但布局会将其放回到边界内。此外,你还没有定义任何相对属性来确定ImageView应该位于哪个组件的左侧/右侧/上方/下方。 - Remi
@wiseindy 我已经更新了我的答案,它应该适用于你。我用我的应用程序测试过了,完全正常。 - Xcihnegn
3个回答

6

yummy的观点有一定道理。 我下载了SDK并查看了示例应用程序。 请注意您在代码片段中引用的log()函数,其在示例应用程序中的实现如下:

    private void log(final String msg) {
    Log.d(TAG, msg);
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mLogAdapter.add(msg);
            mLogAdapter.notifyDataSetChanged();
        }
    });
}

这意味着onServiceUpdate没有在UI线程中运行,这意味着如果它崩溃了,你可能无法获得任何日志或访问断点。
我的建议是将你的3行代码添加到日志方法中。
        private void log(final String msg) {
    Log.d(TAG, msg);
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mLogAdapter.add(msg);
            mLogAdapter.notifyDataSetChanged();
            ImageView imgPoint = (ImageView)findViewById(R.id.imagePoint);
            imgPoint.setX(250);
            imgPoint.setY(200);
        }
    });
}

看看它是否运行,如果是,请将图像视图与X和Y参数一起设置为私有成员;在onServiceUpdate上更新X和Y,并将它们的值设置为UI线程中log中的ImageView。

(显然,如果它能工作,之后需要进行一些重构,但这将给你一个很好和快速的测试)。


3

onServiceUpdate(...) 是在后台线程中的 IndoorAtlas 的回调方法,如果你想要与主 UI 线程通讯,那么你需要使用 runOnUIThread(...)

public void onServiceUpdate(ServiceState state) {
     mSharedBuilder.setLength(0);
     mSharedBuilder.append("Location: ")
        .append("\n\troundtrip : ").append(state.getRoundtrip()).append("ms")
        .append("\n\tlat : ").append(state.getGeoPoint().getLatitude())
        .append("\n\tlon : ").append(state.getGeoPoint().getLongitude())
        .append("\n\tX [meter] : ").append(state.getMetricPoint().getX())
        .append("\n\tY [meter] : ").append(state.getMetricPoint().getY())
        .append("\n\tI [pixel] : ").append(state.getImagePoint().getI())
        .append("\n\tJ [pixel] : ").append(state.getImagePoint().getJ())
        .append("\n\theading : ").append(state.getHeadingDegrees())
        .append("\n\tuncertainty: ").append(state.getUncertainty());

     log(mSharedBuilder.toString());

     setImagePoint(state.getImagePoint());    

}


private void setImagePoint(final ImagePoint imgPt) {

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            ImageView imgPoint = (ImageView) findViewById(R.id.imagePoint);  
            imageMan.setX(imgPt.getI());
            imageMan.setY(imgPt.getJ());
        }
    });
}

希望这能帮到你!

2

方法onServiceUpdate是否在非UI线程上调用,但通过try-catch忽略错误?然后尝试使用Handle。

private Handler mUpdateHandler = new Handler() {
    public void handleMessage(Message msg){
        if (msg.obj instanceof ServiceState) {
            ServiceState state = (ServiceState) msg.obj;
            ImageView imgPoint = (ImageView) findViewById(R.id.imagePoint);
            imgPoint.setX(state.getMetricPoint().getX());
            imgPoint.setY(state.getMetricPoint().getY());
        }
    }
}

public void onServiceUpdate(ServiceState state) {
    mUpdateHandler.obtainMessage(0, state).sendToTarget();
    //....
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接