- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个将数据加载到列表适配器以显示在屏幕上的 fragment 。当我的应用程序启动时,它会启动一项服务来查找新数据,如果找到, fragment 将需要显示这些数据。目前,我的私有(private)广播接收器实际上是在主要 Activity 上——而不是 fragment 。这对我来说似乎不对,但我看不出如何将通知从广播接收器传递回 fragment ,当它在 fragment 本身上时,我读到的另一个问题是建议这种方法。
使用我在下面发布的代码,当我的广播接收器收到通知并在 fragment 上调用 updateConent 时,我得到了 - 我记录了以下错误:
10-26 20:31:21.328: E/AndroidRuntime(711): FATAL EXCEPTION: main
10-26 20:31:21.328: E/AndroidRuntime(711): java.lang.RuntimeException: Error receiving broadcast Intent { act=updatedata flg=0x10 (has extras) } in com.thedailydigi.dailydigi.Main$1@41458418
10-26 20:31:21.328: E/AndroidRuntime(711): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:765)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.os.Handler.handleCallback(Handler.java:615)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.os.Handler.dispatchMessage(Handler.java:92)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.os.Looper.loop(Looper.java:137)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.app.ActivityThread.main(ActivityThread.java:4745)
10-26 20:31:21.328: E/AndroidRuntime(711): at java.lang.reflect.Method.invokeNative(Native Method)
10-26 20:31:21.328: E/AndroidRuntime(711): at java.lang.reflect.Method.invoke(Method.java:511)
10-26 20:31:21.328: E/AndroidRuntime(711): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
10-26 20:31:21.328: E/AndroidRuntime(711): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-26 20:31:21.328: E/AndroidRuntime(711): at dalvik.system.NativeStart.main(Native Method)
10-26 20:31:21.328: E/AndroidRuntime(711): Caused by: java.lang.IllegalStateException: There is already a listener registered
10-26 20:31:21.328: E/AndroidRuntime(711): at android.support.v4.content.Loader.registerListener(Loader.java:130)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.support.v4.app.LoaderManagerImpl$LoaderInfo.start(LoaderManager.java:260)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.support.v4.app.LoaderManagerImpl.installLoader(LoaderManager.java:510)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.support.v4.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:497)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.support.v4.app.LoaderManagerImpl.restartLoader(LoaderManager.java:643)
10-26 20:31:21.328: E/AndroidRuntime(711): at com.thedailydigi.dailydigi.activity.HorizontalListFragment.updateContent(HorizontalListFragment.java:130)
10-26 20:31:21.328: E/AndroidRuntime(711): at com.thedailydigi.dailydigi.Main$1.onReceive(Main.java:36)
10-26 20:31:21.328: E/AndroidRuntime(711): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:755)
我发现“Caused by: java.lang.IllegalStateException: There is already a listener registered”是问题的症结所在,但我没有已注册的监听器?
谁能解释一下a)为什么我目前收到上述错误以及b) 这是否是将附加数据加载到 fragment 中的正确方法?
我的相关类的完整代码如下。感谢您的帮助。
主.java
public class Main extends FragmentActivity {
private static final String LOG_TAG = "dd-Main";
private HorizontalListFragment mDailyDigiFragment;
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//TODO go update the UI from the database
int newRecords = intent.getIntExtra(DownloadFeedService.DOWNLOADED,0);
long date = intent.getLongExtra(DownloadFeedService.BEGIN_DATE, DownloadFeedService.NULL_DATE);
Log.d(LOG_TAG, newRecords + " new records downloaded!");
if (intent.getStringExtra(DownloadFeedService.KEY).equals(getString(R.string.daily_digi_short))) {
mDailyDigiFragment.updateContent(newRecords, date);
} else {
//TODO add our other fragments here
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v(LOG_TAG, "Main Activity started");
registerReceiver(myReceiver, new IntentFilter(DownloadFeedService.UPDATEDATA));
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
//mDailyDigiFragment = HorizontalListFragment.newInstance(getString(R.string.daily_digi_short), 10, R.drawable.banner_dailydigi, true);
mDailyDigiFragment = HorizontalListFragment.newInstance(getString(R.string.daily_digi_short), 10, R.drawable.banner_dailydigi, true);
FragmentTransaction dailyDigiTransaction = getSupportFragmentManager().beginTransaction();
dailyDigiTransaction.add(R.id.dailydigi, mDailyDigiFragment).commit();
//TODO instantiate our other fragments here
/*
Fragment digiShowFragment = HorizontalListFragment.newInstance(getString(R.string.digi_show_short), 10, R.drawable.banner_digishow, true);
FragmentTransaction digiShowTransaction = getSupportFragmentManager().beginTransaction();
digiShowTransaction.add(R.id.digishow, digiShowFragment).commit();*/
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
HorizontalListFragment.java
public class HorizontalListFragment extends Fragment
implements LoaderManager.LoaderCallbacks<ArrayList<RssFeed.Article>> {
private ArticleAdapter adapter ;
private static final String LOG_TAG = "dd-HorizontalListFragment";
private static String MAX_LOAD_KEY = "max";
private static String DATASOURCE_KEY = "key";
private static String IMAGE_SRC_KEY = "image";
private static String SHOW_TEXT_OVERLAY = "showOverlay";
private String mRssFeedKey = "";
private int mDefaultLoad;
private int mImageResource = 0;
//TODO do we want to toggle the overlay on the digishow feed?
private boolean mShowTextOverlay = true;
private HorizontalListView mListView;
ArticleLoader mLoader;
public static HorizontalListFragment newInstance(String key, int max, int img, boolean showOverlay) {
HorizontalListFragment myFragment = new HorizontalListFragment();
Bundle args = new Bundle();
args.putString(DATASOURCE_KEY, key);
args.putInt(MAX_LOAD_KEY, max);
args.putInt(IMAGE_SRC_KEY, img);
args.putBoolean(SHOW_TEXT_OVERLAY, showOverlay);
myFragment.setArguments(args);
return myFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = this.getArguments();
mRssFeedKey = bundle.getString(DATASOURCE_KEY);
mDefaultLoad = bundle.getInt(MAX_LOAD_KEY, getResources().getInteger(R.integer.default_display_max));
mImageResource = bundle.getInt(IMAGE_SRC_KEY, 0);
mShowTextOverlay = bundle.getBoolean(SHOW_TEXT_OVERLAY, true);
mLoader = new ArticleLoader(getActivity(), mRssFeedKey,mDefaultLoad);
getActivity().getSupportLoaderManager().initLoader(0, null, this);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.horizontal_list_section, container, false);
ImageView img = (ImageView) view.findViewById(R.id.Header_Image);
img.setImageResource(mImageResource);
mListView = (HorizontalListView) view.findViewById(R.id.hr_listview);
return view;
}
@Override
public Loader<ArrayList<RssFeed.Article>> onCreateLoader(int arg0, Bundle bundle) {
Log.d(LOG_TAG, "onCreateLoader: find " + mDefaultLoad + " articles from " + mRssFeedKey);
return mLoader;
}
@Override
public void onLoadFinished(Loader<ArrayList<RssFeed.Article>> arg0, ArrayList<RssFeed.Article> result) {
Log.d(LOG_TAG, "onLoadFinished with " + result.size() + " records from " + mRssFeedKey);
//update the listview with the combined results list
if (adapter == null) {
adapter = new ArticleAdapter(this.getActivity(), result,true);
mListView.setAdapter(adapter);
} else {
insertNewArticles(result);
adapter.notifyDataSetChanged();
}
//TODO use these methods to reset the list position ?
//mListView.setSelectionFromTop(currentFirstVisibleItem, 0);
//mListView.getFirstVisiblePosition();
}
@Override
public void onLoaderReset(Loader<ArrayList<RssFeed.Article>> arg0) {
Log.v(LOG_TAG, "onLoaderReset");
// TODO what do we need to do here?
}
public void updateContent(int newRecords , long date) {
if (date == DownloadFeedService.NULL_DATE) {
Log.d(LOG_TAG, "updateContent requesting " + newRecords + " new records.");
//this is when some new recent content has been downloaded
mLoader.setDownloadParameters(newRecords, 0);
getActivity().getSupportLoaderManager().restartLoader(0, null, this);
} else {
//this was probably downloaded cuz we're scrolling near the end
}
}
//both lists should already be sorted in date desc order
private void insertNewArticles(ArrayList<RssFeed.Article> listB) {
//TODO - we need to make sure we only add new entries
int listPosition = 0;
for (Article a : listB ) {
for (int i = listPosition; i < adapter.getCount(); i++) {
Article b = adapter.getItem(i);
//already in the list - skip over it
if (a.getInternalId() == b.getInternalId()) {
listPosition = i+1;
break;
}
//our new item is published after - it shows at the front of the list
if (a.getPublicationDate().before(b.getPublicationDate())) {
adapter.insert(a, i-1);
listPosition = i;
break;
}
}
//when we get to new items that pre-date our current list items, add them at the end
if (listPosition == adapter.getCount()) {
adapter.insert(a, listPosition);
listPosition++;
}
}
}
}
文章加载器.java
public class ArticleLoader extends AsyncTaskLoader<ArrayList<RssFeed.Article>> {
private static final String LOG_TAG = "dd-ArticleLoader";
ArrayList<RssFeed.Article> mArticles;
final String mSource;
int mOffset = 0;
int mDownloadCount;
public ArticleLoader(Context context, String source, int max) {
super(context);
mSource = source;
mDownloadCount = max;
}
public void setDownloadParameters(int count, int offset) {
mOffset = offset;
mDownloadCount = count;
}
/**
* This is where the bulk of our work is done. This function is
* called in a background thread and should generate a new set of
* data to be published by the loader.
*/
@Override public ArrayList<RssFeed.Article> loadInBackground() {
Log.d(LOG_TAG, "loadInBackground: find " + mDownloadCount + " articles from " + mSource);
mArticles = ArticleManager.findArticles(getContext().getContentResolver(), mSource, mDownloadCount, mOffset);
return mArticles;
}
@Override
protected void onStartLoading() {
if(mArticles != null) {
deliverResult(mArticles);
} else {
forceLoad();
}
}
}
最佳答案
这里的问题是,当您在 updateContent()
方法中调用 getActivity().getSupportLoaderManager().restartLoader(0, null, this);
时,它再次调用 onCreateLoader(...)
。您的 onCreateLoader(..)
方法然后返回与第一次相同的加载程序。这个加载器已经有一个注册的监听器。
要解决这个问题,你只需要onCreateLoader(..)
每次返回一个新的加载器。
更改自:
@Override
public Loader<ArrayList<RssFeed.Article>> onCreateLoader(int arg0, Bundle bundle) {
Log.d(LOG_TAG, "onCreateLoader: find " + mDefaultLoad + " articles from " + mRssFeedKey);
return mLoader;
}
到:
@Override
public Loader<ArrayList<RssFeed.Article>> onCreateLoader(int arg0, Bundle bundle) {
Log.d(LOG_TAG, "onCreateLoader: find " + mDefaultLoad + " articles from " + mRssFeedKey);
return new ArticleLoader(getActivity(), mRssFeedKey,mDefaultLoad);
}
关于android - 重新启动加载程序调用时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13096529/
我是 C 语言新手,我编写了这个 C 程序,让用户输入一年中的某一天,作为返回,程序将输出月份以及该月的哪一天。该程序运行良好,但我现在想简化该程序。我知道我需要一个循环,但我不知道如何去做。这是程序
我一直在努力找出我的代码有什么问题。这个想法是创建一个小的画图程序,并有红色、绿色、蓝色和清除按钮。我有我能想到的一切让它工作,但无法弄清楚代码有什么问题。程序打开,然后立即关闭。 import ja
我想安装screen,但是接下来我应该做什么? $ brew search screen imgur-screenshot screen
我有一个在服务器端工作的 UDP 套接字应用程序。为了测试服务器端,我编写了一个简单的 python 客户端程序,它发送消息“hello world how are you”。服务器随后应接收消息,将
我有一个 shell 脚本,它运行一个 Python 程序来预处理一些数据,然后运行一个 R 程序来执行一些长时间运行的任务。我正在学习使用 Docker 并且我一直在运行 FROM r-base:l
在 Linux 中。我有一个 c 程序,它读取一个 2048 字节的文本文件作为输入。我想从 Python 脚本启动 c 程序。我希望 Python 脚本将文本字符串作为参数传递给 c 程序,而不是将
前言 最近开始整理笔记里的库存草稿,本文是 23 年 5 月创建的了(因为中途转移到 onedrive,可能还不止) 网页调起电脑程序是经常用到的场景,比如百度网盘下载,加入 QQ 群之类的 我
对于一个类,我被要求编写一个 VHDL 程序,该程序接受两个整数输入 A 和 B,并用 A+B 替换 A,用 A-B 替换 B。我编写了以下程序和测试平台。它完成了实现和行为语法检查,但它不会模拟。尽
module Algorithm where import System.Random import Data.Maybe import Data.List type Atom = String ty
我想找到两个以上数字的最小公倍数 求给定N个数的最小公倍数的C++程序 最佳答案 int lcm(int a, int b) { return (a/gcd(a,b))*b; } 对于gcd,请查看
这个程序有错误。谁能解决这个问题? Error is :TempRecord already defines a member called 'this' with the same paramete
当我运行下面的程序时,我在 str1 和 str2 中得到了垃圾值。所以 #include #include #include using namespace std; int main() {
这是我的作业: 一对刚出生的兔子(一公一母)被放在田里。兔子在一个月大时可以交配,因此在第二个月的月底,每对兔子都会生出两对新兔子,然后死去。 注:在第0个月,有0对兔子。第 1 个月,有 1 对兔子
我编写了一个程序,通过对字母使用 switch 命令将十进制字符串转换为十六进制,但是如果我使用 char,该程序无法正常工作!没有 switch 我无法处理 9 以上的数字。我希望你能理解我,因为我
我是 C++ 新手(虽然我有一些 C 语言经验)和 MySQL,我正在尝试制作一个从 MySQL 读取数据库的程序,我一直在关注这个 tutorial但当我尝试“构建”解决方案时出现错误。 (我正在使
仍然是一个初学者,只是尝试使用 swift 中的一些基本函数。 有人能告诉我这段代码有什么问题吗? import UIKit var guessInt: Int var randomNum = arc
我正在用 C++11 编写一个函数,它采用 constant1 + constant2 形式的表达式并将它们折叠起来。 constant1 和 constant2 存储在 std::string 中,
我用 C++ 编写了这段代码,使用运算符重载对 2 个矩阵进行加法和乘法运算。当我执行代码时,它会在第 57 行和第 59 行产生错误,非法结构操作(两行都出现相同的错误)。请解释我的错误。提前致谢:
我是 C++ 的初学者,我想编写一个简单的程序来交换字符串中的两个字符。 例如;我们输入这个字符串:“EXAMPLE”,我们给它交换这两个字符:“E”和“A”,输出应该类似于“AXEMPLA”。 我在
我需要以下代码的帮助: 声明 3 个 double 类型变量,每个代表三角形的三个边中的一个。 提示用户为第一面输入一个值,然后 将用户的输入设置为您创建的代表三角形第一条边的变量。 将最后 2 个步
我是一名优秀的程序员,十分优秀!