从单独的外部类的多个线程更新多个视图

时间:2019-04-04 10:06:24

标签: android multithreading view

我正在从事游戏项目。我想将游戏的每个视图关联到其各自的线程,然后根据该线程中运行的逻辑来更新视图。

为简单起见,我将发布一个示例:

这是Main Activity类,它将实现UI:

public class Main extends Activity{

    private View root;
    private boolean ready = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }

    private void init() {
        setContentView(R.layout.s_main);
        root = findViewById(R.id.root);
        ViewTreeObserver vto = root.getViewTreeObserver();
        vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                root.getViewTreeObserver().removeOnPreDrawListener(this);
                ready = true;
                return true;
            }
        });
    }

    public void start(View view) {
        try {
            if (ready && !Threads.run) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                    new AsyncTasks(this, R.id.txv1).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                    new AsyncTasks(this, R.id.txv2).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                } else {
                    new AsyncTasks(this, R.id.txv1).execute();
                    new AsyncTasks(this, R.id.txv2).execute();
                }
            } else {
                Threads.run = false;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

这是AsyncTask扩展类,用于更新View:

public class AsyncTasks extends AsyncTask<Void, Void, String> {

    private TextView view;
    private boolean breakMove;
    private String updateError;

    public AsyncTasks(Activity activity, int viewId) {
        breakMove = false;
        updateError = null;
        view = activity.findViewById(viewId);
    }

    @Override
    protected String doInBackground(Void... voids) {
        String message;
        Threads.run = true;
        try {
            while (!breakMove) {
                publishProgress();
                Thread.sleep(100);
            }
            message = updateError != null ? updateError : "Thread Ends";
        } catch (Exception ex) {
            ex.printStackTrace();
            message = ex.getMessage();
        }
        return message;
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
        try {
            breakMove = !Threads.run;
            if (view != null)
                view.setText(String.valueOf(Math.random() * 100));
        } catch (Exception ex) {
            breakMove = true;
            ex.printStackTrace();
            updateError = ex.getMessage();
        }
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        Threads.run = false;
    }
}

这很好。但是有局限性:

    推荐
  • AsyncTask用于短时线程,而不用于Game或Long Running Thread项目。

  • 在最新的android框架中,只能同时运行5个AsyncTask线程,其余线程将处于等待队列中。因此,如果我的项目需要同时更新5个以上的视图,它将无法正常工作。

我尝试过的事情:

  • 其他所有Thread实现(如Runnable,Handler,Service等)都不允许更新视图。请记住,我的线程是在单独的外部文件或类中编码的。

  • 不建议使用
  • runOnUiThread,因为它在UI线程上运行,因此它将使Main线程一直忙碌,并且在调用它的线程结束后,其输出也很明显。

我正在寻找一个简单的干净解决方案,就像我上面编写的那样,可以通过多个线程实现多视图更新。

预先感谢

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。简单干净:


public class Main extends Activity{

    private View root;
    private Runs runs;
    private boolean ready = false;
    private final Context context = this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }

    private void init() {
        setContentView(R.layout.s_main);
        runs = new Runs(this);
        root = findViewById(R.id.root);
        //
        ViewTreeObserver vto = root.getViewTreeObserver();
        vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                root.getViewTreeObserver().removeOnPreDrawListener(this);
                ready = true;
                return true;
            }
        });
    }

    private void startRuns() {
        try {
            runs.run();
            Threads.run = true;
        } catch (Exception ex) {
            Alerts.alert(context, ex.getMessage());
        }
    }

    public void start(View view) {
        try {
            if (ready && !Threads.run) {
                startRuns();
            } else {
                Threads.pause = !Threads.pause;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            Alerts.alert(context, ex.getMessage());
        }
    }
}

public class Runs implements Runnable {

    private int count;
    private Handler handler;
    private TextView view1, view2;

    public Runs(Activity activity) {
        count = 0;
        handler = new Handler();
        view1 = activity.findViewById(R.id.txv1);
        view2 = activity.findViewById(R.id.txv2);
    }

    @Override
    public void run() {
        if (!Threads.pause) {
            update();
        }
        handler.postDelayed(this, Threads.sleep);
    }

    private void update() {
        view1.setText(String.valueOf(count++));
        view2.setText(String.valueOf(Math.random() * 100));
    }


}