线程问题使用帖子

时间:2017-11-16 15:59:43

标签: java android multithreading

我是Android和线程的新手。我目前正在制作一个游戏,其中渲染和逻辑发生在与UI不同的线程上。 我的问题是我似乎无法使用工作线程中的帖子更新ui。

这是我的主要活动:

private GameScene gameScene;
private Handler uiHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.game);
    uiHandler = new Handler(Looper.getMainLooper());

    gameScene = new GameScene(getApplicationContext(), uiHandler);
    LinearLayout gameHolder = (LinearLayout)findViewById(R.id.game_view);
    gameHolder.addView(gameScene);
    gameScene.resume();
}

这是实现runnable的类:

public abstract class Scene extends SurfaceView implements Runnable {

    Handler uiHandler;
    Thread thread = null;
    public Scene(Context context, Handler uiHandler) {
        super(context);
        this.uiHandler = uiHandler;
    }

    @Override
    public void run() {
        uiHandler.post(() -> {
            TextView textView = findViewById(R.id.fps_counter);
            textView.setText("hello");
        });
    }

    public void resume() {
        thread = new Thread(this);
        thread.start();
    }

的xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/game_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:visibility="visible">

        <TextView
            android:id="@+id/fps_counter"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="0"
            android:textColor="@color/colorAccent"
            android:textSize="24sp" />
    </LinearLayout>

</FrameLayout>

帖子里面的代码应该在ui线程上运行吗?但是在尝试设置文本时,我得到一个空对象引用。是的,id为fps_counter的文本存在。

2 个答案:

答案 0 :(得分:2)

由于Gamescene不包含fps_counter文本视图,因此请修改您的抽象场景和类扩展,以便您可以将引用传递给textview。

public abstract class Scene extends SurfaceView implements Runnable {

    Handler uiHandler;
    Thread thread = null;
    TextView textView;
    public Scene(Context context, Handler uiHandler, TextView textView) {
        super(context);
        this.uiHandler = uiHandler;
        this.textView = textView;
    }

    @Override
    public void run() {
        uiHandler.post(() -> {
            textView.setText("hello");
        });
    }

    public void resume() {
        thread = new Thread(this);
        thread.start();
    }

然后使用textview的第3个参数创建GameScene:

TextView textView = findViewById(R.id.fps_counter);
// no need to use getApplicationContext(), you may use this (a reference to "mainActivity")
gameScene = new GameScene(this, uiHandler, textView);

答案 1 :(得分:1)

您正在findViewById内调用SurfaceView,有效地在SurfaceView中寻找具有给定ID的视图。

但是您的R.id.fps_counter ID视图位于活动内部,因此您应该在活动中查找它。

我建议您在创建GameScene类之前找到它并在构造函数中提供它。

请参阅https://developer.android.com/reference/android/view/View.html#findViewById(int)https://developer.android.com/reference/android/app/Activity.html#findViewById(int)

在后面的答案中使用petey的代码。

另一个解决方案是将活动传递给您的GameScene,然后您就可以在没有处理程序的情况下执行此操作。

private GameScene gameScene;
private TextView fpsCounter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.game);

    fpsCounter = findViewById(R.id.fps_counter);
    gameScene = new GameScene(this);
    LinearLayout gameHolder = (LinearLayout)findViewById(R.id.game_view);
    gameHolder.addView(gameScene);
    gameScene.resume();
}

public void setFps(String fps) {
    fpsCounter.setText(fps);
}

public abstract class Scene extends SurfaceView implements Runnable {

    Thread thread;
    Activity activity;

    public Scene(Activity activity) {
        super(activity);
        this.activity = activity;
    }

    @Override
    public void run() {
        activity.runOnUiThread(() -> {
            activity.setFps("Hello");
        });
    }

    public void resume() {
        thread = new Thread(this);
        thread.start();
    }

更好的方法是使用框架所期望的构造函数并在init方法中设置活动,如here