【发布时间】:2018-01-02 22:00:59
【问题描述】:
我正在尝试学习适用于 Android 的 Room Persistence 数据库,但遇到了一些严重的概念障碍。我想要做的是使用 Room 来查询数据库并返回一些数据。完成后,我想根据该数据更新 TextView 的值。
最终,希望创建一个与数据库相关的表单,其中的字段可以预先填写数据库中已有的信息。
经过几个小时的修修补补,我想出了以下代码,它确实有效:
public class DBTestFragment extends Fragment {
public static final String FRAGMENT_TAG = "DB Test";
private DBTCompanionDatabase mDb;
private TextView mDbDumpText;
private Button mAddDaily;
private Button mRemoveDailies;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public DBTestFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment DBTestFragment.
*/
// TODO: Rename and change types and number of parameters
public static DBTestFragment newInstance(String param1, String param2) {
DBTestFragment fragment = new DBTestFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
mDb = DBTCompanionDatabase.getDBTCompanionDatabase(this.getContext());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_dbtest, container, false);
mDbDumpText = rootView.findViewById(R.id.database_test_database_printout);
mAddDaily = rootView.findViewById(R.id.database_test_add_dummy_daily);
mAddDaily.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
addDaily();
}
});
mRemoveDailies = rootView.findViewById(R.id.database_test_remove_dummy_dailies);
/*
mRemoveDailies.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
removeDailies();
}
});
*/
return rootView;
}
@Override
public void onStart() {
super.onStart();
new GetDailyListAsync(mDb, mDbDumpText).execute();
}
private void addDaily() {
DatabaseInitializer.populateAsync(mDb);
new GetDailyListAsync(mDb, mDbDumpText).execute();
}
private static class GetDailyListAsync extends AsyncTask<Void, Void, List<Daily>> {
private final DBTCompanionDatabase mDb;
private TextView mDumpText;
GetDailyListAsync(DBTCompanionDatabase db, TextView dumpText) {
mDb = db;
mDumpText = dumpText;
}
@Override
protected List<Daily> doInBackground(final Void... params) {
return mDb.dailyDao().getAll();
}
@Override
protected void onPostExecute(List<Daily> dailies) {
mDumpText.setText(dailies.toString());
}
}}
我意识到有几个默认参数和一些我没有改变的东西,但我只是想在弄乱其他任何东西之前让它工作。当然,我在 IDE 中收到警告,告诉我私有 TextView mDumpText(在我的 AsyncTask 中)泄漏了一个上下文对象。但是,至少事情是可行的。
我尝试了几种不同的方法来避免这种泄漏,但没有任何效果。我尝试不将 TextView 传递给 AsyncTask,而是从父 Fragment 调用方法。但是,除非该方法被声明为静态(因为 AsyncTask 是静态的),否则我不能调用此方法。我无法将其设置为静态,因为这样我就无法引用我想要更新的 TextView(因为它不是静态的 [而且我无法将其设为静态,因为我收到另一个 IDE 警告,将任何 Android 上下文类放在静态字段中是也是内存泄漏])。
我已经四处寻找了几个小时,但所有内容要么给出了一个未完成的示例代码(这没有帮助),要么引用了 Room 以外的任何东西,这似乎也从来没有工作过。在 Room 数据库操作完成后(不造成内存泄漏)更新 UI 元素(例如 TextView)的最佳做法是什么?
【问题讨论】:
标签: android multithreading android-asynctask