我已将AsyncTask
转换为AsyncTaskLoader
(主要用于处理配置更改)。我有一个TextView
我用作进度状态,并在onProgressUpdate
中使用AsyncTask
来更新它。它看起来不像AsyncTaskLoader
,因此在loadInBackground
期间(在AsyncTaskLoader
中)我正在使用它:
getActivity().runOnUiThread(new Runnable() {
public void run() {
((TextView)getActivity().findViewById(R.id.status)).setText("Updating...");
}
});
我在Fragment
中使用此功能,这就是我使用getActivity()
的原因。这项工作非常顺利,除非发生配置更改,例如更改屏幕方向。我的AsyncTaskLoader
一直在运行(这就是我使用AsyncTaskLoader
的原因),但runOnUiThread
似乎被跳过了。
不确定为什么会被跳过,或者这是从AsyncTaskLoader
更新用户界面的最佳方法。
更新:
我最终还原为AsyncTask
,因为它似乎更适合UI更新。希望他们可以合并AsyncTask
与AsyncTaskLoader
合作的内容。
答案 0 :(得分:4)
这实际上是可能的。您基本上需要子类化AsyncTaskloader
并实现publishMessage()
方法,该方法将使用Handler
将进度消息传递给任何实现ProgressListener
的类(或任何您想叫它)接口。
下载此示例:http://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html(如果它离线,请给我发消息) - 这是基于http://habrahabr.ru/post/131560/
答案 1 :(得分:4)
嗯......你不应该这样做。
因为匿名类访问父类Method或Field是如何通过存储对父类的不可见引用。
例如,您有一个Activity
:
public class MyActivity
extends Activity
{
public void someFunction() { /* do some work over here */ }
public void someOtherFunction() {
Runnable r = new Runnable() {
@Override
public void run() {
while (true)
someFunction();
}
};
new Thread(r).start(); // use it, for example here just make a thread to run it.
}
}
编译器实际上会生成如下内容:
private static class AnonymousRunnable {
private MyActivity parent;
public AnonymousRunnable(MyActivity parent) {
this.parent = parent;
}
@Override
public void run() {
while (true)
parent.someFunction();
}
}
因此,当您的父Activity
销毁(例如由于配置更改),并且您的匿名类仍然存在时,整个活动无法进行gc-ed。 (因为有人仍然持有参考资料。)
这会导致内存泄漏并使您的应用程序变得清晰!
如果是我,我会为这样的加载器实现“onProgressUpdate()”:
public class MyLoader extends AsyncTaskLoader<Something> {
private Observable mObservable = new Observable();
synchronized void addObserver(Observer observer) {
mObservable.addObserver(observer);
}
synchronized void deleteObserver(Observer observer) {
mObservable.deleteObserver(observer);
}
@Override
public void loadInBackground(CancellationSignal signal)
{
for (int i = 0;i < 100;++i)
mObservable.notifyObservers(new Integer(i));
}
}
在Activity
班级
public class MyActivity extends Activity {
private Observer mObserver = new Observer() {
@Override
public void update(Observable observable, Object data) {
final Integer progress = (Integer) data;
mTextView.post(new Runnable() {
mTextView.setText(data.toString()); // update your progress....
});
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreated(savedInstanceState);
MyLoader loader = (MyLoader) getLoaderManager().initLoader(0, null, this);
loader.addObserver(mObserver);
}
@Override
public void onDestroy() {
MyLoader loader = (MyLoader) getLoaderManager().getLoader(0);
if (loader != null)
loader.deleteObserver(mObserver);
super.onDestroy();
}
}
记住在deleteObserver()
期间onDestroy()
很重要,这样加载程序就不会永远引用您的活动。 (加载器可能会在Application
生命周期中保持活动状态......)
答案 2 :(得分:1)
回答我自己的问题,但据我所知,如果你需要更新用户界面,AsyncTaskLoader
并不是最好用的。
答案 3 :(得分:0)
在您实施LoaderManager.LoaderCallback
的类(可能是您的活动)中,您必须覆盖onLoadFinished()
方法。这是AsyncTaskLoader
加载完毕后返回的内容。
答案 4 :(得分:0)
最好的方法是使用LiveData,可以100%工作
第1步:添加生命周期依赖项,或者在创建项目时使用androidx工件
implementation "androidx.lifecycle:lifecycle-livedata:2.1.0"
第2步:按照以下步骤创建loader类,在loader中的public方法中,设置可从活动或片段中观察到的实时数据。请参阅加载程序类中的 setLiveCount 方法。
package com.androidcodeshop.asynctaskloaderdemo;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.MutableLiveData;
import androidx.loader.content.AsyncTaskLoader;
import java.util.ArrayList;
public class ContactLoader extends AsyncTaskLoader<ArrayList<String>> {
private MutableLiveData<Integer> countLive = new MutableLiveData<>();
synchronized public void setLiveCount(MutableLiveData<Integer> observer) {
countLive = (observer);
}
public ContactLoader(@NonNull Context context) {
super(context);
}
@Nullable
@Override
public ArrayList<String> loadInBackground() {
return loadNamesFromDB();
}
private ArrayList<String> loadNamesFromDB() {
ArrayList<String> names = new ArrayList<>();
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
names.add("Name" + i);
countLive.postValue(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return names;
}
@Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad(); // forcing the loading operation everytime it starts loading
}
}
第3步:从活动中设置实时数据,并按照以下说明进行更改
package com.androidcodeshop.asynctaskloaderdemo;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.MutableLiveData;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<ArrayList> {
private ContactAdapter mAdapter;
private ArrayList<String> mNames;
private MutableLiveData<Integer> countLiveData;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNames = new ArrayList<>();
mAdapter = new ContactAdapter(this, mNames);
RecyclerView mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mAdapter);
countLiveData = new MutableLiveData<>();
countLiveData.observe(this, new androidx.lifecycle.Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
Log.d(TAG, "onChanged: " + integer);
Toast.makeText(MainActivity.this, "" +
integer,Toast.LENGTH_SHORT).show();
}
});
// initialize the loader in onCreate of activity
getSupportLoaderManager().initLoader(0, null, this);
// it's deprecated the best way is to use viewmodel and livedata while loading data
}
@NonNull
@Override
public Loader onCreateLoader(int id, @Nullable Bundle args) {
ContactLoader loader = new ContactLoader(this);
loader.setLiveCount(countLiveData);
return loader;
}
@Override
public void onLoadFinished(@NonNull Loader<ArrayList> load, ArrayList data) {
mNames.clear();
mNames.addAll(data);
mAdapter.notifyDataSetChanged();
}
@Override
public void onLoaderReset(@NonNull Loader loader) {
mNames.clear();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
希望这会帮助您:)编码愉快