Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/212.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 同步异步任务_Android_Multithreading - Fatal编程技术网

Android 同步异步任务

Android 同步异步任务,android,multithreading,Android,Multithreading,我正在使用内存数据库,做一些简单的任务,比如写一些电影,然后把它们读出来并显示出来。我正在使用RoomPersistance,我已经设置了一些存储库。我的问题是: 在这里,我从响应中获取电影,并通过insertMovie方法将它们插入数据库中 for (OMDBItem movie : response.body().getItems()) { omdbItemRepository.ins

我正在使用内存数据库,做一些简单的任务,比如写一些电影,然后把它们读出来并显示出来。我正在使用RoomPersistance,我已经设置了一些存储库。我的问题是:

在这里,我从响应中获取电影,并通过insertMovie方法将它们插入数据库中

for (OMDBItem movie : response.body().getItems())
                        {
                              omdbItemRepository.insertMovie(movie);
                        }
此方法如下所示:

public void insertMovie(OMDBItem movie){
    AsyncTask<Void,Void,Void> atask = new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... voids) {
            movieDataBase.movieDao().insert(movie);
            return null;
        }
    }.execute();
}
public List<OMDBItem>  getAllMovies(){

        new AsyncTask<Void,Void,Void>(){

            @Override
            protected Void doInBackground(Void... voids) {
                lista_filmovi=movieDataBase.movieDao().getAllMovies();
                return null;

            }
        }.execute();
return lista_filmovi;
    }
/** ViewModel providing additional features to ease Room DB access */
public class RoomViewModel extends AndroidViewModel {

    /** Thread executing Room operations */
    private static class RoomThread extends Thread {

        /** Queue of tasks pending execution */
        private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();

        /** Set to false to stop */
        private boolean running = true;

        /** Send this to stop the execution */
        private Runnable STOP = new Runnable() {
            @Override
            public void run() {
                running = false;
            }
        };

        @Override
        public void run()
        {
            while (running) {
                try {
                    // execute next in line, when available
                    tasks.take().run();
                } catch (InterruptedException e) {
                    // this should not happen
                    return;
                }
            }
        }
    }

    /** Executes backround Room requests in order */
    private RoomThread roomThread = new RoomThread();

    public RoomViewModel(@NonNull Application application) {
        super(application);

        // start the background execution thread
        roomThread.start();
    }

    /**
     * Queues the specified Runnable for execution
     * @param runnable The Runnable to be executed in background
     */
    protected void execute(Runnable runnable)
    {
        roomThread.tasks.offer(runnable);
    }

    @Override
    protected void onCleared() {
        // queue the stop request
        execute(roomThread.STOP);
        super.onCleared();
    }
}
getAllMovies是一种类似的方法,如下所示:

public void insertMovie(OMDBItem movie){
    AsyncTask<Void,Void,Void> atask = new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... voids) {
            movieDataBase.movieDao().insert(movie);
            return null;
        }
    }.execute();
}
public List<OMDBItem>  getAllMovies(){

        new AsyncTask<Void,Void,Void>(){

            @Override
            protected Void doInBackground(Void... voids) {
                lista_filmovi=movieDataBase.movieDao().getAllMovies();
                return null;

            }
        }.execute();
return lista_filmovi;
    }
/** ViewModel providing additional features to ease Room DB access */
public class RoomViewModel extends AndroidViewModel {

    /** Thread executing Room operations */
    private static class RoomThread extends Thread {

        /** Queue of tasks pending execution */
        private BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();

        /** Set to false to stop */
        private boolean running = true;

        /** Send this to stop the execution */
        private Runnable STOP = new Runnable() {
            @Override
            public void run() {
                running = false;
            }
        };

        @Override
        public void run()
        {
            while (running) {
                try {
                    // execute next in line, when available
                    tasks.take().run();
                } catch (InterruptedException e) {
                    // this should not happen
                    return;
                }
            }
        }
    }

    /** Executes backround Room requests in order */
    private RoomThread roomThread = new RoomThread();

    public RoomViewModel(@NonNull Application application) {
        super(application);

        // start the background execution thread
        roomThread.start();
    }

    /**
     * Queues the specified Runnable for execution
     * @param runnable The Runnable to be executed in background
     */
    protected void execute(Runnable runnable)
    {
        roomThread.tasks.offer(runnable);
    }

    @Override
    protected void onCleared() {
        // queue the stop request
        execute(roomThread.STOP);
        super.onCleared();
    }
}

问题是,有时候,这个方法getAllMovies会返回我想要的电影,但有时候它只返回null。它只在我放置一些断点并在调试器中运行时返回电影。我的问题是,通过在调试器中运行它并单击方法,我会给insertMoviemovie AsyncTasks更多的时间来完成它的工作,当调用getAllMovies时,它会给我一个很好的结果。所以基本上,问题是,我是否可以让getAllMovies异步任务在insertMovie异步任务完成之前不启动。我知道我可以在insertMovie中设置一个onPostExecute,但是我希望这些方法被单独创建,我不想每次在insertMovie之后调用getAllMovies。有什么解决方案吗?

您的代码中有一些问题。 首先,您需要等待数据库中写入的所有电影开始读回。然后在读取过程中,不能只返回lista_filmovi的值,因为读取是异步的,所以当您尝试读取时,返回的值将不存在

编写电影的异步任务示例如下:

public static class InsertMovie extends AsyncTask<OMDBItem,Void,Void> {

    private final Database movieDataBase;

    public InsertMovie(Database movieDataBase) {
        this.movieDataBase = movieDataBase;
    }

    @Override
    protected Void doInBackground(OMDBItem... movies) {
        for (OMDBItem movie : movies)
            movieDataBase.movieDao().insert(movie);
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        // data is stored
    }
}
在调用OnPostExecute之前,不得尝试读取数据。有多种方法可以做到这一点,但更简单的方法可能是从那里开始阅读

然后再读一遍:

public static class GetAllMovies extends AsyncTask<Void,Void,List<OMDBItem>> {

    private final Database movieDataBase;

    public GetAllMovies(Database movieDataBase) {
        this.movieDataBase = movieDataBase;
    }

    @Override
    protected List<OMDBItem> doInBackground(Void... voids) {
        return movieDataBase.movieDao().getAllMovies();
    }

    @Override
    protected void onPostExecute(List<OMDBItem> allMovies) {
        // post the result to your activity
    }
}
这对您很有帮助,因为您只有一个后台线程用于DB访问,因此操作将被排序

在MoviewModel扩展RoomViewModel中,您可以使用:

// write the movies
execute(new Runnable() {
    @Override
    public void run() {
        for (OMDBItem movie : movies) movieDataBase.movieDao().insert(movie);
    }
});


在“活动”中,您可以将allMovies作为可变LiveData进行观察,并在有新数据显示时收到通知。

我建议您更改insertMovie的代码,以便它需要一组电影。然后,在AsyncTask触发器GetAllMovies的onPostExecute方法中,我不知道我是如何想到放入一个电影数组而不是一个电影的。谢谢你的建议,但是对于onPostExecute,我不想每次调用insertMovie时都调用getAllMovies。你不必每次都调用getAllMovies…只要在调用时有一个条件语句。或者在任务中添加一个接口,并在需要时在回调中触发getAllMovies。如果你不知道什么时候打电话给getAllMovies,什么时候不打电话给getAllMovies,你就很难给你更多的建议了。很好,我明白你的意思,谢谢你的帮助。我想是的。