Android 从AsyncTaskLoader更新UI

Android 从AsyncTaskLoader更新UI,android,android-asynctask,android-ui,asynctaskloader,Android,Android Asynctask,Android Ui,Asynctaskloader,我已将我的AsyncTask转换为AsyncTaskLoader(主要用于处理配置更改)。我有一个TextView我正在用作进度状态,并且在AsyncTask中使用onProgressUpdate来更新它。它看起来不像AsyncTaskLoader有一个等价物,因此在loadInBackground(在AsyncTaskLoader中)期间,我使用以下方法: getActivity().runOnUiThread(new Runnable() { public void run() {

我已将我的
AsyncTask
转换为
AsyncTaskLoader
(主要用于处理配置更改)。我有一个
TextView
我正在用作进度状态,并且在
AsyncTask
中使用
onProgressUpdate
来更新它。它看起来不像
AsyncTaskLoader
有一个等价物,因此在
loadInBackground
(在
AsyncTaskLoader
中)期间,我使用以下方法:

getActivity().runOnUiThread(new Runnable() {
    public void run() {
        ((TextView)getActivity().findViewById(R.id.status)).setText("Updating...");
    }
});
我在
片段中使用它,这就是为什么我使用
getActivity()
。这项工作非常好,除非发生配置更改,例如更改屏幕方向。我的
AsyncTaskLoader
一直在运行(这就是为什么我使用
AsyncTaskLoader
),但是
runOnUiThread
似乎被跳过了

不确定为什么要跳过它,或者这是否是从
AsyncTaskLoader
更新UI的最佳方法

更新:


我最终返回到
AsyncTask
,因为它似乎更适合UI更新。希望他们能够在实现
LoaderManager.LoaderCallback
(可能是您的活动)的类中,将与
AsyncTask
一起工作的内容与
AsyncTaskLoader
合并,有一个
onLoadFinished()
方法必须重写。这是当
AsyncTaskLoader
完成加载时返回的结果。

回答了我自己的问题,但从我所知道的情况来看,
AsyncTaskLoader
在需要更新UI时不是最好的选择。

这实际上是可能的。本质上,您需要对
AsyncTaskloader
进行子类化,并实现
publishMessage()
方法,该方法将使用
处理程序
将进度消息传递给实现
ProgressListener
(或任何您想要调用它的)接口的任何类


下载以下示例:(脱机时给我发消息)-这是基于

Emm。。。你不应该这样做

因为匿名类如何通过存储对父类的不可见引用来访问父类方法或字段

例如,您有一个
活动

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();
    }
}
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));
    }
}
因此,当您的父级
活动
销毁(例如,由于配置更改),并且您的匿名类仍然存在时,整个活动无法gc-ed(因为仍有人持有引用)

这将导致内存泄漏,并使您的应用程序陷入困境

如果是我,我会为加载程序实现“onProgressUpdate()”,如下所示:

private static class AnonymousRunnable {
    private MyActivity parent;
    public AnonymousRunnable(MyActivity parent) {
        this.parent = parent;
    }

    @Override
    public void run() {
        while (true)
            parent.someFunction();
    }
}
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));
    }
}

请记住在
onDestroy()
期间
deleteObserver()
非常重要,这样加载程序就不会永远保存对活动的引用。(加载程序可能在应用程序的生命周期内保持活动状态…

最好的方法是使用LiveData,100%工作

步骤1:在项目创建过程中添加生命周期依赖项或使用androidx工件作为是

implementation "androidx.lifecycle:lifecycle-livedata:2.1.0"
步骤2:按照下面的步骤创建loader类,在loader Create in public方法中设置可以从活动或片段中观察到的livedata。请参阅我的loader类中的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
}
}
package com.androidcodeshop.asynctaskloaderdemo;
导入android.content.Context;
导入androidx.annotation.NonNull;
导入androidx.annotation.Nullable;
导入androidx.lifecycle.MutableLiveData;
导入androidx.loader.content.AsyncTaskLoader;
导入java.util.ArrayList;
公共类ContactLoader扩展了AsyncTaskLoader{
private MutableLiveData countLive=新的MutableLiveData();
同步的公共void setLiveCount(MutableLiveData观察者){
countLive=(观察员);
}
公共ContactLoader(@NonNull上下文){
超级(上下文);
}
@可空
@凌驾
公共阵列列表loadInBackground(){
返回loadNamesFromDB();
}
私有ArrayList loadNamesFromDB(){
ArrayList name=新的ArrayList();
对于(int i=0;i<10;i++){
试一试{
睡眠(1000);
名称。添加(“名称”+i);
countLive.postValue(i);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
返回姓名;
}
@凌驾
开始加载时受保护的void(){
super.onStartLoading();
forceLoad();//每次开始加载时强制加载操作
}
}
步骤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();
}

}
package com.androidcodeshop.asynctaskloaderdemo;
导入android.os.Bundle;
导入android.util.Log;
导入android.widget.Toast;
导入androidx.annotation.NonNull;
导入androidx.annotation.Nullable;
导入androidx.appcompat.app.appcompat活动;
导入androidx.lifecycle.MutableLiveData;
导入androidx.loader.app.LoaderManager;
导入androidx.loader.content.loader;
导入androidx.recyclerview.widget.LinearLayoutManager;
导入androidx.recyclerview.widget.recyclerview;
导入java.util.ArrayList;
公共类MainActivity扩展了AppCompatActivity实现
LoaderManager.LoaderCallbacks{
私人通讯适配器;
私人ArrayList mNames;
私有可变LiveData countLiveData;
私有静态最终字符串TAG=“MainActivity”;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNames=newarraylist();
mAdapter=新的ContactAdapter(此,mNames);
RecyclerView mRecyclerView=findViewById(R.id.recycler\u视图);
mRecyclerView.setLayoutManager(新的LinearLayoutManager(this));
mRecyclerView.setAdapter(mAdapter);
countLiveData=新的可变LiveData();
countLiveData.observe(这是一个新的androidx.lifecycle.observator()){
@凌驾
更改后的公共void(整数){
Log.d(标记“onChanged:+整数);
Toast.makeText(MainActivit