5

私は自分AsyncTaskをに変換しましたAsyncTaskLoader(主に構成の変更に対処するため)。TextView進行状況として使用していてonProgressUpdateAsyncTaskを更新するために使用していました。AsyncTaskLoader同等のものがあるようには見えないので、 loadInBackground(でAsyncTaskLoader)私はこれを使用しています:

getActivity().runOnUiThread(new Runnable() {
    public void run() {
        ((TextView)getActivity().findViewById(R.id.status)).setText("Updating...");
    }
});

私はこれをで使用しているFragmentので、を使用していgetActivity()ます。これは、画面の向きを変更するなどの構成変更が発生した場合を除いて、非常にうまく機能します。私AsyncTaskLoaderは走り続けます(それが私がを使用している理由ですAsyncTaskLoader)が、runOnUiThreadスキップされるようです。

なぜスキップされているのか、またはこれがからUIを更新するための最良の方法であるかどうかはわかりません AsyncTaskLoader

アップデート:

AsyncTaskUIの更新に適していると思われるため、最終的にはに戻りました。AsyncTaskで機能するものをとマージできることを望みAsyncTaskLoaderます。

4

5 に答える 5

4

それは実際に可能です。基本的に、をサブクラス化してメソッドAsyncTaskloaderを実装する必要がありますpublishMessage()。このメソッドは、を使用して、 (または呼び出したいものを)インターフェースHandlerを実装する任意のクラスに進行状況メッセージを配信します。ProgressListener

例としてこれをダウンロードしてください:http ://www.2shared.com/file/VW68yhZ1/SampleTaskProgressDialogFragme.html (オフラインになった場合はメッセージを送ってください)-これはhttp://habrahabr.ru/post/131560/に基づいています

于 2012-04-29T09:07:30.823 に答える
4

ええと...あなたはこれをするべきではありません。

匿名クラスが親クラスのメソッドまたはフィールドにアクセスする方法は、親クラスへの非表示の参照を格納することによるためです。

たとえば、あなたは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ライフサイクルの間生きたままになります...)

于 2014-01-31T10:12:58.363 に答える
1

私自身の質問に答えますが、私が言えることからAsyncTaskLoader、UIを更新する必要がある場合に使用するのは最善ではありません。

于 2012-04-24T14:34:06.240 に答える
0

実装するクラスLoaderManager.LoaderCallback(おそらくアクティビティ)には、onLoadFinished()オーバーライドする必要のあるメソッドがあります。これは、のAsyncTaskLoader読み込みが完了したときに返されるものです。

于 2012-04-16T03:40:38.160 に答える
0

最良の方法は、LiveDataを使用することです。100%動作します

ステップ1:ライフサイクルの依存関係を追加するか、プロジェクトの作成時にandroidxアーティファクトをyesとして使用します

implementation "androidx.lifecycle:lifecycle-livedata:2.1.0"

ステップ2:ローダークラスを次のように作成します。ローダーで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();
}

}

これがあなたのお役に立てば幸いです:)幸せなコーディング

于 2019-11-01T22:15:37.720 に答える