[英]Android update listview after changing data using sharedpreferences
I'm trying to implement PreferenceFragmentCompat
and SharedPreferences.OnSharedPreferenceChangeListener
. 我正在尝试实现
PreferenceFragmentCompat
和SharedPreferences.OnSharedPreferenceChangeListener
。
My app consists of main activity and fragments. 我的应用包含主要活动和片段。 The home fragment has a list of URLs with a title, and I would like to add a setting to add a URL to this list.
home片段有一个带有标题的URL列表,我想添加一个设置以将URL添加到此列表中。 This is what I've tried so far:
到目前为止,这是我尝试过的:
Here's the SettingsFragment.java
: 这是
SettingsFragment.java
:
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference preference = findPreference(key);
if (preference instanceof EditTextPreference) {
EditTextPreference editTextPreference = (EditTextPreference) preference;
String value = editTextPreference.getText();
new HomeFragment().addLink(value);
} else {
assert preference != null;
preference.setSummary(sharedPreferences.getString(key, ""));
}
}
And the HomeFragment.java
: 还有
HomeFragment.java
:
private ArrayList<LinkItem> urls = new ArrayList<>(Arrays.asList(
new LinkItem("LifeHacker RSS Feed", "https://lifehacker.com/rss"),
new LinkItem("Google News Feed", "https://news.google.com/news/rss");
private LinkItemAdapter itemAdapter;
private ListView listView;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
listView = view.findViewById(R.id.postListView);
itemAdapter = new LinkItemAdapter(getActivity(), R.layout.link_item, urls);
listView.setAdapter(itemAdapter);
listView.setOnItemClickListener(onItemClickListener);
itemAdapter.notifyDataSetChanged();
return view;
}
void addLink(String title) {
urls.add(new LinkItem(title, "https://google.com"));
itemAdapter.notifyDataSetChanged();
}
private AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
HomeFragmentDirections.ActionHomeFragmentToRssFragment action =
HomeFragmentDirections.actionHomeFragmentToRssFragment(urls.get(position).Link, urls.get(position).Title);
NavHostFragment.findNavController(HomeFragment.this).navigate(action);
}
};
If I try doing it like this, the itemAdapter will be null, crashing the app, so I am unsure of how to implement this. 如果我尝试这样做,则itemAdapter将为null,从而使应用程序崩溃,因此我不确定如何实现此目的。 If I try recreating it in addLink like in the onCreate method of HomeFragment, the activity ends up being null.
如果我尝试在HomeLink的onCreate方法中的addLink中重新创建它,则该活动最终为null。 If I try passing the activity or the context from settings fragment, the same result occurs.
如果我尝试通过设置片段传递活动或上下文,则会发生相同的结果。
LinkItemAdapter
adapts the following object: LinkItemAdapter
适应以下对象:
public class LinkItem {
public String Title;
public String Link;
}
My results so far have always been the same: crash as soon as I click "OK" on the edit text field after changing it, due to a null pointer. 到目前为止,我的结果始终是相同的:由于指针为空,更改后在编辑文本字段上单击“确定”后立即崩溃。 Could anyone help me out with this, please?
有人可以帮我吗? I am new to android.
我是Android新手。
Stack trace: 堆栈跟踪:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myfragmentapp, PID: 5185
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.myfragmentapp.adapters.LinkItemAdapter.notifyDataSetChanged()' on a null object reference
at com.example.myfragmentapp.screens.HomeFragment.addLink(HomeFragment.java:86)
at com.example.myfragmentapp.screens.SettingsFragment.onSharedPreferenceChanged(SettingsFragment.java:42)
at android.app.SharedPreferencesImpl$EditorImpl.notifyListeners(SharedPreferencesImpl.java:560)
at android.app.SharedPreferencesImpl$EditorImpl.apply(SharedPreferencesImpl.java:443)
at androidx.preference.Preference.tryCommit(Preference.java:1632)
at androidx.preference.Preference.persistString(Preference.java:1663)
at androidx.preference.EditTextPreference.setText(EditTextPreference.java:80)
at androidx.preference.EditTextPreferenceDialogFragmentCompat.onDialogClosed(EditTextPreferenceDialogFragmentCompat.java:99)
at androidx.preference.PreferenceDialogFragmentCompat.onDismiss(PreferenceDialogFragmentCompat.java:267)
at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1377)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6709)
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:769)
You should call addLink()
after you've created the adapter: 创建适配器后,应调用
addLink()
:
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
listView = view.findViewById(R.id.postListView);
itemAdapter = new LinkItemAdapter(getActivity(), R.layout.link_item, urls);
listView.setAdapter(itemAdapter);
listView.setOnItemClickListener(onItemClickListener);
addLnk();
return view;
}
If you're trying to set a value from one fragment to another you should either use callbacks or a ViewModel, the simpler of those being a callback: 如果您尝试将一个片段中的值设置为另一个片段,则应使用回调或ViewModel,其中更简单的是回调:
Define a callback inteface: 定义一个回调接口:
interface OnSetPreferenceItem{
void setPrefItemInList(String item);
}
Inside SettingsFragment, define a variable: 在SettingsFragment中,定义一个变量:
private OnSetPreferenceItem callback;
In the same fragment, fill in the variable in onAttach: 在同一片段中,在onAttach中填写变量:
public void onAttach(Context context) {
super.onAttach(context);
callback = (OnSetPreferenceItem )context;
}
Now instead of calling new HomeFragment().addLink(value);, call 现在,不调用new HomeFragment()。addLink(value);,而是
callback.setPrefItemInList(value);
Let your parent activity implement that interface and implement the method suggested: 让您的父活动实现该接口并实现建议的方法:
public void setPrefItemInList(String item){
homeFragment.addLink(item);
}
Modify your addLink method to protect it: 修改您的addLink方法以保护它:
void addLink(String title) {
urls.add(new LinkItem(title, "https://google.com"));
if(itemAdapter!=null){
itemAdapter.notifyDataSetChanged();
}
}
I would suggest you using the lifecycle functions of the Fragment
correctly. 我建议您正确使用
Fragment
的生命周期功能。 When you are modifying some data (ie adding a new URL in the list) from another fragment (ie SettingsFragment
), you do not have to call the HomeFragment.addLink
right away actually. 当您从另一个片段(即
SettingsFragment
)修改某些数据(即在列表中添加新的URL)时,实际上不必立即调用HomeFragment.addLink
。 Instead, you might consider having the onResume
method implemented in your HomeFragment
so that when you go back to your HomeFragment
, the onResume
function is called automatically and there you should update your list and consider calling notifyDataSetChanged
on your adapter. 相反,您可以考虑在
HomeFragment
实现onResume
方法,以便当您返回HomeFragment
,将自动调用onResume
函数,在那里您应该更新列表并考虑在适配器上调用notifyDataSetChanged
。
Hence I am trying to provide some pseudo code here. 因此,我试图在此处提供一些伪代码。 In your
SettingsFragment
do something like the following. 在您的
SettingsFragment
执行以下操作。
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference preference = findPreference(key);
if (preference instanceof EditTextPreference) {
EditTextPreference editTextPreference = (EditTextPreference) preference;
String value = editTextPreference.getText();
// new HomeFragment().addLink(value); // You do not call this here
saveTheNewURLInPrefrence(); // Just save the new value in your preference
} else {
assert preference != null;
preference.setSummary(sharedPreferences.getString(key, ""));
}
}
Now in your HomeFragment
, implement the onResume
function like the following. 现在在您的
HomeFragment
,实现onResume
函数,如下所示。
@Override
protected void onResume() {
super.onResume();
urls = getAllItemsFromPreference();
if(itemAdapter != null) itemAdapter.notifyDataSetChanged();
else {
itemAdapter = new LinkItemAdapter(getActivity(), R.layout.link_item, urls);
listView.setAdapter(itemAdapter);
listView.setOnItemClickListener(onItemClickListener);
}
}
To understand more about fragment lifecycle, please check the documentation here . 要了解有关片段生命周期的更多信息,请在此处查看文档 。 I hope you get the idea.
希望您能明白。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.