「コードの最初の行」第 10 章: サービス

1. 子スレッドで UI を更新します。

1. 新しいプロジェクトを作成し、レイアウト コードを変更します

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <Button
       android:id="@+id/change_text"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="改变文本"/>
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="hello world"
        android:textSize="20sp"/>
</RelativeLayout>

2. アクティビティ内のコードを変更します。

public class MainActivity extends AppCompatActivity  implements View.OnClickListener{
    
    
    private TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text=(TextView) findViewById(R.id.text);
        Button changeText=(Button) findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
    
    
        switch(view.getId()){
    
    
            case R.id.change_text:
                //创建一个子进程
                new Thread(new Runnable() {
    
    
                    @Override
                    public void run() {
    
    
                        //run中执行的就是子进程中的代码
                        text.setText("hellosdfsdfs");
                    }
                }).start();
                break;
            default:
                break;
        }
    }
}

子スレッドで ui を直接変更することはできません。
場合によっては、サブスレッドで操作を実行し、その結果に基づいて UI を更新する必要があるでしょうか。

3. Android の非同期メッセージ処理

public class MainActivity extends AppCompatActivity  implements View.OnClickListener{
    
    
    public static final int UPDATE_TEXT=1;
    private TextView text;
    private  Handler handler=new Handler(){
    
    
        @Override
        public void handleMessage(@NonNull Message msg) {
    
    
            //接收到message并处理
            switch(msg.what){
    
    
                case UPDATE_TEXT:
                    //这里可以进行ui的操作
                    text.setText("NICE TO MEET YOU");
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text=(TextView) findViewById(R.id.text);
        Button changeText=(Button) findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
    
    
        switch(view.getId()){
    
    
            case R.id.change_text:
                //创建一个子进程
                new Thread(new Runnable() {
    
    
                    @Override
                    public void run() {
    
    
                        Message message=new Message();
                        message.what=UPDATE_TEXT;
                        //将message对象发送出去
                        handler.sendMessage(message);
                    }
                }).start();
                break;
            default:
                break;
        }
    }
}

メッセージを使用して正常に更新します。これは Android の非同期メッセージ処理の基本的な方法です。

次に、非同期メッセージ処理メカニズムを分析します。

Android の非同期メッセージ処理は、主に Message Handler、MessageQueue、Looper の 4 つの部分で構成されます。このうち、Message と Handler については前のセクションで説明しましたが、MessageQueue と Looper についてはまだ新しい概念ですが、以下ではこれら 4 つの部分について簡単に説明します。

1,メッセージ

メッセージはスレッド間で渡されるメッセージであり、異なるスレッド間でデータを交換するために少量の情報を内部的に運ぶことができます。前のセクションでは、メッセージの what フィールドを使用しましたが、さらに、arg1 および arg2 フィールドを使用して整数データを伝送したり、obi フィールドを使用してオブジェクト オブジェクトを伝送したりすることもできます。

2. ハンドラー

ハンドラーはその名前が示すようにプロセッサーを意味し、主にメッセージの送信と処理に使用されます。メッセージの送信には通常、ハンドラーの sendMessage() メソッドが使用され、送信されたメッセージは一連の処理の後、ハンドラーの handleMessage() メソッドに渡されます。

3.メッセージキュー

MessageQueue はメッセージ キューを意味し、主にハンドラーを介して送信されるすべてのメッセージを格納するために使用されます。メッセージのこの部分は常にメッセージ キューに存在し、処理されるのを待っています。MessageQueue オブジェクトはスレッドごとに 1 つだけ存在します。

4.ルーパー

Looper は、各スレッドの MessageQueue のスチュワードです。Looper の Loop() メソッドを呼び出した後、無限ループに入り、MessageQueue でメッセージが見つかると、そのメッセージが取り出され、Handler の handleMessage() メソッドに渡されます。Looper オブジェクトはスレッドごとに 1 つだけ存在します。

まず、メインスレッドで Handler オブジェクトを作成し、handleMessage() メソッドをオーバーライドする必要があります。次に、UI 操作を子スレッドで実行する必要がある場合、Message オブジェクトが作成され、メッセージは Handler を通じて送信されます。その後、メッセージは処理のために MessageQueue キューに追加され、Looper は常に MessageQueue から保留中のメッセージを取り出し、最終的にそれをハンドラーの handleMessage() メソッドに配布しようとします。Handler はメイン スレッドで作成されるため、handleMessage() メソッドのコードもこの時点でメイン スレッドで実行されるため、ここで安心して UI 操作を実行できます。
ここに画像の説明を挿入

3番目に、AsynTaskを使用します

まずはAsyncTaskの基本的な使い方ですが、AsyncTaskは抽象クラスなので、利用する場合はそれを継承するサブクラスを作成する必要があります。継承時にAsyncTaskクラスの汎用パラメータを3つ指定できますが、これら3つのパラメータの用途は以下の通りです。

Params:在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
progress。后台任务执行时,如果需要在界面上示当前的的进度。则使用这里指定的泛型1作为进度单位。
Resut:当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为哦返回值类型。

したがって、最も単純なカスタム AsynTask は次のように記述できます。

class DownLoadTask extends AsynTask<void,Integer,Boolean>{
    
    
	...
}

現時点では、カスタム DownLoadTask はまだ空のタスクであり、実際の操作を実行できません。また、タスクのカスタマイズを完了するには、AsynTask のいくつかのメソッドを書き直す必要があります。よく使われるのは次の 4 つです。

1.onPreExecute()
这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。
2.doInBackground(Params...)
这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务旦完成就可以通过return 语来将任务的执行结果返回,如果AsyncTask 的第三个泛型参数指定的是 Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行 UI操作的,如果需要更新 UI 元素,比如说反馈当前任务的执行进度,可以调用 publishProgress(Progress...)方法来完成。
3.onProgressUpdate(Progress...)
当在后台任务中调用了 publishProgress(Progress...)方法后,onProgressUpdate(Progress...)方法就会很快被调用,该方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对 UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
4.onPostExecute(Result)
当后台任务执行完毕并通过 return 语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些 UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。

簡単に言えば、AsyncTask を使用するコツは、時間のかかる特定のタスクを doInBackground() メソッドで実行し、UI 操作を onProgressUpdate() メソッドで実行し、いくつかの仕上げタスクを onPostExecute() メソッドで実行することです。
このタスクを開始したい場合は、次のコードを記述するだけです。

new DownloadTask().execute();

第四に、サービスの基本的な使い方

1. サービスを定義する

新しい ServiceTest プロジェクトを作成し、com.example.servicetest-new-Service-Service を右クリックし、[OK] をクリックしてサービスを作成します。

public class MyService extends Service {
    
    
    public MyService() {
    
    
    }

    @Override
    public IBinder onBind(Intent intent) {
    
    
        //唯一的抽象方法,必须在子类中进行实现
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
    
    
        //服务创建时调用
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    
    
        //服务启动的时候调用
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
    
    
        //服务销毁的时候调用
        super.onDestroy();
    }
}

次に、AS が自動的にメニフェストに登録します。

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AndroidThreadTest">
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>
    </application>

そんなサービスが生まれています。

2. サービスの開始と停止

インテントは主にサービスの開始と停止に使用されます。
レイアウトを変更します。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <Button
       android:id="@+id/start_serivce"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="启动服务"/>
    <Button
        android:id="@+id/stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="停止服务"/>
</LinearLayout>

対応するアクティビティ コードを変更し、インテントを使用してサービスを開始および停止します。

public class MainActivity extends AppCompatActivity  implements View.OnClickListener{
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService=(Button) findViewById(R.id.start_serivce);
        Button stopService=(Button) findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
    
    
       switch(view.getId()){
    
    
           case R.id.start_serivce:
               Intent startIntent=new Intent(this,MyService.class);
               startService(startIntent);
               break;
           case R.id.stop_service:
                Intent stopIntent=new Intent(this,MyService.class);
                stopService(stopIntent);
               break;
           default:
               break;
       }
    }
}

次に、サービス コードを変更します。

public class MyService extends Service {
    
    
    public MyService() {
    
    
    }

    @Override
    public IBinder onBind(Intent intent) {
    
    
        //唯一的抽象方法,必须在子类中进行实现
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
    
    
        //服务第一次创建时调用
        super.onCreate();
        Log.d("TAG", "onCreate: ");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    
    
        //服务每次启动的时候调用
        Log.d("TAG", "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
    
    
        //服务销毁的时候调用
        super.onDestroy();
        Log.d("TAG", "onDestroy: ");
    }
}

3. コミュニケーションのためのイベントやサービス

上記では、アクティビティ内でサービスを開始および停止しましたが、実際にはアクティビティ内でサービスと対話しませんでした。
たとえば、現在、MyService にダウンロード機能を提供したいと考えています。そうすれば、いつダウンロードを開始するかを決定し、アクティビティ中にいつでもダウンロードの進行状況を確認できるようになります。これを実現するためのアイデアは、ダウンロード機能を管理する特別な Binder オブジェクトを作成し、MyService のコードを次のように変更することです。

public class MyService extends Service {
    
    
    private DownloadBinder mBinder=new DownloadBinder();
    class DownloadBinder extends Binder {
    
    
        public void startDownload(){
    
    
            Log.d("TAG", "startDownload: ");
        }
        public int getProgress(){
    
    
            Log.d("TAG", "getProgress: ");
            return 0;
        }
    }
    public MyService() {
    
    
    }

    @Override
    public IBinder onBind(Intent intent) {
    
    
        //唯一的抽象方法,必须在子类中进行实现
        return mBinder;
    }
 }

このようにして、サービス内のコードが記述され、レイアウトが変更されます。

    <Button
        android:id="@+id/bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="绑定服务"/>
    <Button
        android:id="@+id/unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="取消绑定服务"/>

次に、アクティビティ内でサービスをバインドする必要があります。アクティビティがサービスにバインドされると、サービス内で Binder によって提供されるメソッドを呼び出すことができます。MainActiviyty のコードを変更します。

public class MainActivity extends AppCompatActivity  implements View.OnClickListener{
    
    
    private MyService.DownloadBinder downloadBinder;
    private ServiceConnection connection =new ServiceConnection() {
    
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
    
    
            downloadBinder=(MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
    
    }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService=(Button) findViewById(R.id.start_serivce);
        Button stopService=(Button) findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        //新增通信服务
        Button bindService=(Button) findViewById(R.id.bind_service);
        Button unbindService=(Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
    
    
       switch(view.getId()){
    
    
           case R.id.start_serivce:
               Intent startIntent=new Intent(this,MyService.class);
               startService(startIntent);
               break;
           case R.id.stop_service:
                Intent stopIntent=new Intent(this,MyService.class);
                stopService(stopIntent);
               break;
           case R.id.bind_service:
               Intent bindIntent=new Intent(this,MyService.class);
               bindService(bindIntent,connection,BIND_AUTO_CREATE);//绑定服务
               break;
           case R.id.unbind_service:
               unbindService(connection);//解绑服务
               break;
           default:
               break;
       }
    }
}

おすすめ

転載: blog.csdn.net/weixin_42349568/article/details/129284127