java - 无法在主线程上访问数据库,因为它可能会长时间锁定 UI

标签 java android multithreading

我尝试在 onCreate() 方法中创建新线程并启动它,但应用程序卡住并且消息仍然相同(无法访问主线程上的数据库,因为它可能会长时间锁定 UI。)

也尝试了 Runnable 和 Handler 相同的消息 我搜索了很多相同的问题,发现 runOnUIThread 仍然是相同的问题

任何有帮助的文章或视频请引用 您想要查看的任何缺失代码也请引用它 提前致谢。

package com.example.android.popularmovies;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;

import com.example.android.popularmovies.DataBase.AppDatabase;
import com.example.android.popularmovies.DataBase.FavoriteMovies;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;


public class MainActivity extends AppCompatActivity {
    private ArrayList<ListItem> arrayMovies = new ArrayList<>();
    private RecyclerView mRecyclerView;
    private RecyclerViewAdapter adapter;
    private RecyclerViewAdapterFavorite adapterFavorite;
    private String dataRetrieved;
    private static final String TAG = "MAINACTIVITY";
    private String top_rated = "http://api.themoviedb.org/3/movie/top_rated?api_key=*****";
    private String MoviesURL = "http://api.themoviedb.org/3/movie/popular?api_key=*****";
    private AppDatabase mDb;
    private List<FavoriteMovies> allFavoriteMovies=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDb=AppDatabase.getInstance(getApplicationContext());
        networkUtilites(false);
        getArrayMovies();
        RecyclerViewAdapter();




        MainActivity.this.runOnUiThread(new Runnable()
        {
            @Override
            public void run() {
                allFavoriteMovies= mDb.taskDao().loadAllTasks();
            }
        });

        for(int i=0;i<allFavoriteMovies.size();i++)
        {
            System.out.println(allFavoriteMovies.get(i).getTitle());
        }


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.sorting_menu, menu);
        return true;
    }

    @Override
    protected void onResume() {
        super.onResume();


    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.most_popular:
                Toast.makeText(this, "MostPopularClicked", Toast.LENGTH_SHORT).show();
                arrayMovies.clear();
                networkUtilites(false);
                getArrayMovies();
                RecyclerViewAdapter();

                return true;

            case R.id.top_rated:
                Toast.makeText(this, "TopRatedClicked", Toast.LENGTH_SHORT).show();
                arrayMovies.clear();
                networkUtilites(true);
                getArrayMovies();
                RecyclerViewAdapter();

                return true;

            case R.id.favorite:
                Toast.makeText(this, "Favorite", Toast.LENGTH_SHORT).show();
                RecyclerViewAdapterFavorite();




                return true;

            default:
                return super.onOptionsItemSelected(item);
        }

    }

    public void networkUtilites(Boolean check) {

        NetworkUtilites ob = new NetworkUtilites();
        if (check) {
            ob.setMoviesURL(top_rated);
        } else {
            ob.setMoviesURL(MoviesURL);
        }

        try {
            dataRetrieved = ob.execute().get();

        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }


    public void getArrayMovies() {

        try {


            if (!dataRetrieved.equals(null)) {
                JSONObject parentObject = new JSONObject(dataRetrieved);
                JSONArray parentArray = parentObject.getJSONArray("results");

                //System.out.println(parentArray.length());
                for (int i = 0; i < parentArray.length(); i++) {

                    JSONObject movieDetails = parentArray.getJSONObject(i);
                    String poster_path = "http://image.tmdb.org/t/p/w500";
                    poster_path += movieDetails.getString("poster_path");
                    String original_title = movieDetails.getString("original_title");
                    String overview = movieDetails.getString("overview");
                    int vote_average = movieDetails.getInt("vote_average");
                    String release_date = movieDetails.getString("release_date");
                    int id =movieDetails.getInt("id");

                    ListItem ob = new ListItem(original_title, poster_path, overview, vote_average, release_date,id);
                    arrayMovies.add(ob);
                }

            }
        } catch (Exception e) {

        }


    }

    public void RecyclerViewAdapter() {
        adapter = new RecyclerViewAdapter(this, arrayMovies);
        mRecyclerView = findViewById(R.id.recycler_view);
        mRecyclerView.setAdapter(adapter);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));

    }

    public void RecyclerViewAdapterFavorite()
    {
        if (allFavoriteMovies != null) {
            adapterFavorite = new RecyclerViewAdapterFavorite(this, allFavoriteMovies);
            mRecyclerView = findViewById(R.id.recycler_view);
            mRecyclerView.setAdapter(adapterFavorite);
            mRecyclerView.setHasFixedSize(true);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        }

    }





}

TaskDao

package com.example.android.popularmovies.DataBase;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;

import java.util.List;

@Dao
public interface TaskDao
{

    @Query("SELECT * From movies")
    List<FavoriteMovies> loadAllTasks();

    @Query("DELETE From movies")
    void deleteallTasks();

    @Insert
    void insertMovie(FavoriteMovies favoriteMovies);

    @Delete
    void deleteMovie(FavoriteMovies favoriteMovies);

}

最喜欢的电影

package com.example.android.popularmovies.DataBase;

import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;

@Entity(tableName = "movies")
public class FavoriteMovies
{


    @PrimaryKey
    private int id;
    private  String image;
    private  String title;
    private  String overview;

    @Ignore
    public FavoriteMovies(String image, String title, String overview) {
        this.image = image;
        this.title = title;
        this.overview = overview;
    }

    public FavoriteMovies(int id, String image, String title, String overview) {
        this.id = id;
        this.image = image;
        this.title = title;
        this.overview = overview;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getOverview() {
        return overview;
    }

    public void setOverview(String overview) {
        this.overview = overview;
    }




}

应用程序数据库

package com.example.android.popularmovies.DataBase;

import android.content.Context;

import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;

@Database(entities = {FavoriteMovies.class},version = 1,exportSchema = false)
public abstract class AppDatabase  extends RoomDatabase
{
    private static final String DATABASE_NAME="FavouriteMovies";
    private static final Object LOCK = new Object();
    private static AppDatabase sInstance;

    public static AppDatabase getInstance(Context context)
    {
        if(sInstance==null)
        {
            synchronized (LOCK){
                sInstance= Room.databaseBuilder(context.getApplicationContext(),AppDatabase.class,AppDatabase.DATABASE_NAME)
                        .build();
            }
        }
        return sInstance;

    }

    public abstract TaskDao taskDao();
}

堆栈跟踪:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.android.popularmovies, PID: 5342
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.popularmovies/com.example.android.popularmovies.MainActivity}: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
     Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

最佳答案

卡住的原因是因为您将任务放在 runonuithread 上,这意味着它与 UI 运行在同一线程上,并且会阻塞系统。

您可以尝试https://developer.android.com/reference/android/os/AsyncTask 。它有一个易于使用的 API,用于短时间的多线程目的。

另一种方法是在 onCreate 中创建新的 java 线程,该线程不在 ui 线程上运行。

Thread t = new Thread(new Runnable(){yourcodehere})
t.start()

关于java - 无法在主线程上访问数据库,因为它可能会长时间锁定 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58788885/

相关文章:

java - 如何使用两个不共享同一父类的近乎相同的类?

java - hibernate 连接失败

java - 在具有以下 api 21 的设备上运行时,CardView 不显示

带有消费者线程和作业队列的 Ruby Sinatra

java - 我的 GUI 每次启动时都会弹出两个窗口

java - android.os.NetworkOnMainThreadException 如何调整在单独线程中运行的代码

java - 并行方法过程

android - 在滑出式菜单中滑动时淡化布局

android - 单击按钮时删除 RecyclerView 中的所有内容

java - Tomcat 日志 : What's the difference between %D and %F?