Androidのバックグラウンドスレッドでコードを実行するにはどうすればよいですか?


131

一部のコードをバックグラウンドで継続的に実行してほしい。サービスでそれをしたくありません。他に可能な方法はありますか?

私はThread自分の中でクラスを呼び出してみましたActivityが、Activityしばらくの間バックグラウンドに留まり、その後停止します。Threadクラスには、作業を停止します。

class testThread implements Runnable {
        @Override
        public void run() {
            File file = new File( Environment.getExternalStorageDirectory(), "/BPCLTracker/gpsdata.txt" );
            int i = 0;

            RandomAccessFile in = null;

            try {
                in = new RandomAccessFile( file, "rw" );
            } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            }
//String line =null;
            while ( true ) {
                HttpEntity entity = null;
                try {
                    if ( isInternetOn() ) {
                        while ( ( line = in.readLine() ) != null ) {

                            HttpClient client = new DefaultHttpClient();
                            String url = "some url";
                            HttpPost request = new HttpPost( url );
                            StringEntity se = new StringEntity( line );
                            se.setContentEncoding( "UTF-8" );
                            se.setContentEncoding( new BasicHeader( HTTP.CONTENT_TYPE, "application/json" ) );
                            entity = se;
                            request.setEntity( entity );
                            HttpResponse response = client.execute( request );
                            entity = response.getEntity();
                            i++;
                        }
                        if ( ( line = in.readLine() ) == null && entity != null ) {
                            file.delete();
                            testThread t = new testThread();
                            Thread t1 = new Thread( t );
                            t1.start();
                        }


                    } else {
                        Thread.sleep( 60000 );
                    } // end of else

                } catch (NullPointerException e1) {
                    e1.printStackTrace();
                } catch (InterruptedException e2) {
                    e2.printStackTrace();
                } catch (IOException e1) {
// TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }// end of while
        }// end of run

    }

1
こんにちは。あなたが試したことの例としていくつかのコードを投稿していただけますか?バックグラウンドスレッドでコードを実行する方法はいくつかありますが、UIコンポーネントにアクセスする場合は、runOnUiThread()メソッドを使用してUIスレッドでそれらにアクセスする必要があることを覚えておく必要があります。
Alex Wiese 2013年

3
サービスを使用しない特別な理由はありますか
DeltaCap019

これはあまりお勧めできません。継続的に実行すると、デバイスのバッテリーが消耗します。
HelmiB 2013年

コードを送信しました。
user2082987 2013年

サービスで使用してみましたが、同じレコードが複数回送信されました。
user2082987 2013年

回答:


379

もしあなたが必要ならば:

  1. バックグラウンドスレッドでコードを実行する

  2. UIに触れたり更新したりしないコードを実行する

  3. 完了するまでに最大で数秒かかる(短い)コードを実行する

次に、AsyncTaskを使用する次のクリーンで効率的なパターンを使用します。

AsyncTask.execute(new Runnable() {
   @Override
   public void run() {
      //TODO your background code
   }
});

10
注:APIレベル11が必要です
friederbluemle 2015年

9
より軽量な次のコードを使用しないのはなぜですか。new Thread(new Runnable(){@Override public void run(){// background code}})。start();
awardak

3
これによりメモリリークが発生する可能性はありますか?
ヒルフリッツ2018年

5
注意すべきことの1つは、AsyncTasksがキューされていることです。これを一連のサーバーAPI呼び出しに使用すると、並列に実行されません。
チェイスロバーツ


45

ランニングバックグラウンドを忘れないでください。継続的なランニングは2つの異なるタスクです。

長期的なバックグラウンドプロセスの場合、Androidではスレッドは最適ではありません。しかし、ここにコードがあり、あなた自身の責任でそれをしてください...

サービスまたはスレッドはバックグラウンドで実行されますが、更新を取得するにはタスクをトリガー(何度も呼び出す)する必要があります。つまり、タスクが完了したら、次の更新のために関数を呼び出す必要があります。

タイマー(定期的なトリガー)、アラーム(タイムベーストリガー)、ブロードキャスト(イベントベーストリガー)、再帰によって機能が呼び起こされます。

public static boolean isRecursionEnable = true;

void runInBackground() {
    if (!isRecursionEnable)
        // Handle not to start multiple parallel threads
        return;

    // isRecursionEnable = false; when u want to stop
    // on exception on thread make it true again  
    new Thread(new Runnable() {
        @Override
        public void run() {
            // DO your work here
            // get the data
            if (activity_is_not_in_background) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // update UI
                        runInBackground();
                    }
                });
            } else {
                runInBackground();
            }
        }
    }).start();
}

サービスの使用: を起動すると、サービスが開始され、タスクが実行され、サービス自体が終了します。タスク実行後。終了も例外によって引き起こされるか、ユーザーが設定から手動で強制終了した可能性があります。START_STICKY(スティッキーサービス)は、サービスが終了した場合にサービスが自動的に再起動するというandroidによって提供されるオプションです。

マルチプロセッシングとマルチスレッドの違いを覚えていますか? サービスはバックグラウンドプロセスです(UIのない​​アクティビティと同様)。メインスレッド(アクティビティスレッド)の負荷を回避するためにアクティビティでスレッドを起動する方法と同じです。サービスでスレッド(または非同期タスク)を起動する必要があるのと同じ方法です。サービスへの負荷を避けるため。

1つのステートメントで、バックグラウンド継続タスクの実行が必要な場合は、StickyServiceを起動し、イベントベースのサービスでスレッドを実行する必要があります


UIスレッドを更新するためにリスナーから毎秒1回値を取得しながら、バックグラウンドで平均20分間カスタムSignalStrengthListenerを実行する場合、このメソッドをお勧めしますか?ここではより多くのコンテキストは次のとおりです。stackoverflow.com/questions/36167719/...
JParks

「isRecursionEnable = true」を設定した場合、プロセスはどのように再度実行されますか?次に、「runInBackground()」の「run」メソッド内を呼び出しますが、関数の先頭にifステートメントを入力しないのですか?
ミッキー

23

一部のコードをバックグラウンドで継続的に実行してほしい。サービスでそれをしたくありません。他に可能な方法はありますか?

あなたが探している最も可能性の高いメカニズムはAsyncTaskです。バックグラウンドスレッドでバックグラウンドプロセスを実行するために直接指定されています。また、その主な利点は、Main(UI)スレッドで実行されるいくつかのメソッドを提供し、タスクの進行状況についてユーザーに通知したり、バックグラウンドプロセスから取得したデータでUIを更新したりする場合にUIを更新できるようにすることです。

ここから始める方法がわからない場合は、素晴らしいチュートリアルです。

注:また、使用する可能性があるIntentServiceResultReceiver同様にその作品は。


@ user2082987やってみましたか?
Simon Dorociak 2013年

asyncTaskのこれらのパラメーターは混乱を招きます
user2082987

とにかく、AsyncTaskはスレッドのラッパーにすぎないため、Androidがバックグラウンドでアプリケーションを強制終了するという問題は解決しません
Lassi Kinnunen

こんにちは@LassiKinnunen私が5年前にその回答を書きました。これですべてが変更され、メモリリークが安全でないため、現在AsyncTaskを使用していません。
Simon Dorociak

はい、私はそれを知っていますが、人々はまだグーグルを介してこれを見つけるでしょう、そして私がグーグルラッパーを使用することを勧める人々の非常に多くのコメントを見てきました。元の質問については、誰かが2018年に回答を探している場合は、サービスを作成して起動し、殺されない可能性を最大化したい場合は、通知でフォアグラウンドにあることを通知してください。実際に長時間実行されるプロセスは、ハンドラーまたは別のスレッドで処理できます。彼らが実際にそれをメモリリークセーフではないようにすることができたことに気づかなかったのですか?
Lassi Kinnunen

16

シンプルな3ライナー

私がすることによって、コメントとして見つけたこれを行うための簡単な方法@awardakブランドンルードの答え

new Thread( new Runnable() { @Override public void run() { 
  // Run whatever background code you want here.
} } ).start();

これが使用するよりも良いかどうか、どのように良いかはわかりませんが、うまくAsyncTask.executeいくようです。違いについてのコメントはいただければ幸いです。

ありがとう、@ awardak


handler.post()メソッドを使用して、スレッドのrunメソッド内のメインスレッドにポストバックします。
androidXP

2

AsyncTaskの代替はrobospiceです。https://github.com/octo-online/robospice

ロボスパイスのいくつかの機能。

1.非同期で(バックグラウンドAndroidServiceで)ネットワークリクエストを実行します(例:Spring Androidを使用したRESTリクエスト)。結果が準備できたら、UIスレッドでアプリに通知します。

2.強く型付けされています!POJOを使用してリクエストを作成し、リクエスト結果としてPOJOを取得します。

3.リクエストに使用されるPOJOにも、プロジェクトで使用するアクティビティクラスにも制約を適用しません。

4.結果をキャッシュします(JSONでJacksonとGsonの両方、またはXml、またはフラットテキストファイル、またはバイナリファイル、さらにORM Liteを使用)。

5.それらがまだ生きている場合にのみ、ネットワーク要求の結果をアクティビティ(またはその他のコンテキスト)に通知します

Androidローダーとは異なり、Android AsyncTasksがUIスレッドでアクティビティに通知するのとは異なり、メモリリークはまったくありません。

7.シンプルだが堅牢な例外処理モデルを使用します。

はじめにサンプル。https://github.com/octo-online/RoboSpice-samples

https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_resultにあるrobospiceのサンプル。


ネットワークから取得した配列をSQLiteに保存する方法は?基本的には、ネットワークからデータを取得してSQLiteに保存します。両方ともバックグラウンドスレッドで行い、次にUIに通知してListViewを更新します。通常はIntentServiceを使用しますが、RoboSpiceの方が入力の手間がかかりません。
Yar

@yarは、長時間実行オペレーションの場合にインテントサービスを使用できます。また、asynctaskを使用することもできますが、それが短時間の場合に限られます。スレッドを作成し、そこですべてのことを行うことができます。ロボスパイスを長い間使っていません。ボレーのような他のネットワークライブラリがあります...
ラグフナンダン2016年

わかりました。Robospiceを使用することを考えましたが、それは私のニーズにはあまり良くない(柔軟性がない)ようです。私はIntentServiceを長い間使用して成功しています。
2016年

2
class Background implements Runnable {
    private CountDownLatch latch = new CountDownLatch(1);
    private  Handler handler;

    Background() {
        Thread thread = new Thread(this);
        thread.start();
        try {
            latch.await();
        } catch (InterruptedException e) {
           /// e.printStackTrace();
        }
    }

    @Override
    public void run() {
        Looper.prepare();
        handler = new Handler();
        latch.countDown();
        Looper.loop();
    }

    public Handler getHandler() {
        return handler;
    }
}

5
StackOverflowへようこそ。コードのみを含む回答は「低品質」であるため、削除のフラグが付けられる傾向があります。質問への回答に関するヘルプセクションを読み、回答にコメントを追加することを検討してください。
Graham

0

異なるコードでスレッドを先延ばしに実行する必要がある場合は、ここに例があります。

リスナー:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

スレッドクラス

public class ESLThread extends AsyncTask<Void, Void, List> {


    private ESLThreadListener mListener;

    public ESLThread() {

        if(mListener != null){

            mListener.onBackground();
        }
    }

    @Override
    protected List doInBackground(Void... params) {

        if(mListener != null){

            List list = mListener.onBackground();

            return list;
        }

        return null;
    }

    @Override
    protected void onPostExecute(List t) {
        if(mListener != null){

            if ( t != null) {
                mListener.onPostExecute(t);
            }
        }

    }


    public void setListener(ESLThreadListener mListener){

        this.mListener = mListener;
    }
}

異なるコードを実行します。

  ESLThread thread = new ESLThread();
                        thread.setListener(new ESLThreadListener() {
                            @Override
                            public List onBackground() {
                                List<EntityShoppingListItems>  data = RoomDB.getDatabase(context).sliDAO().getSL(fId);

                                return data;

                            }

                            @Override
                            public void onPostExecute(List t) {

                                List<EntityShoppingListItems> data = (List<EntityShoppingListItems>)t;
                                adapter.setList(data);
                            }
                        });

                        thread.execute();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.