【Android】《第一行代码—Android》第九章总结

前面几章介绍了ActivityBroadcastReceiverContentProvider等内容,本章对Android四大组件的最后一个组件Service进行了较为全面的讲解,涉及到Android多线程、Service的基本用法、Service生命周期的介绍等等东西,内容比较多,但都很好理解,我也是在一天之内就把这一章的内容全部看完的,所以趁现在夜深人静的时候,把总结尽可能详细的写下来,说做就做现在动手!

服务—Service—Android实现应用程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且还要长期运行的任务。需要注意的是,服务并不是运行在一个独立的进程之中的,而是依赖于创建服务时所在的应用程序进程。换句话说,当某个应用程序的进程被杀掉时,所有依赖于该进程的服务也会停止运行。

Android多线程编程

Android多线程编程无论从语法上,还是从使用技巧上都与Java多线程编程类似,有三种方式开启子线程。下面会分别介绍。方式一很常规,直接自定义Thread抽象类的实现类,重写父类的run()方法并在方法体内添加耗时处理逻辑,如下

class MyThread extends Thread {

    @Override
    public void run() {
        //耗时处理逻辑
    }
}

这样我们就只需要创建线程实现类的对象,通过对象调用器start()方法,这样run()方法体中的逻辑就会在子线程中运行了。如下

new MyThread().start();

鉴于方式一使用继承的方式,耦合性有点高。方式二主要使用实现Runnable()接口的方式来定义一个线程。如下

class MyThread implements Runnable {

    @Override
    public void run() {
        //处理具体逻辑
    }
}

Thread构造函数接收一个Runnable参数,我们正好可以传入new MyThread() 匿名对象作为参数,接着调用start()方法启动线程,如下

new Thread(new MyThread()).start();

方式三的写法更为常见,使用匿名类的方式,如下

new Thread(new Runnable() {

    @Override
    public void run() {
        //具体处理逻辑
    }
}).start();

接下来我们来尝试“通过子线程进行UI操作”,如果你真的以为子线程可以直接操作UI,程序会直接崩溃掉。事实上也确实如此,Android确实是不允许在子线程中进行UI操作的。但我们可以借助Android异步消息处理机制,完美解决面临的问题。先看代码如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button 
        android:id="@+id/change_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/change_text"
        />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/hello_world"
        android:textSize="20sp"
        />

</RelativeLayout>
package com.example.androidthreadtest;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {

    private static final int UPDATE_TEXT = 1;

    private TextView text;

    private Button changeText;

    private Handler handler = new Handler() {

        public void handleMessage(Message msg) {
            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);
        changeText = (Button) findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.change_text:
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Message message = new Message();
                    message.what = UPDATE_TEXT;
                    handler.sendMessage(message);   // 将Message对象发送出去
                }
            }).start();
            break;
        default:
            break;
        }
    }

}



上面分别给出了activity_main.xml布局文件和MainActivity.java文件的代码,我们可以通过点击按钮把hello world变成nice to meet you,那么处理的思路是什么呢?

首先Android的异步消息处理机制提供了一整套的消息处理流程,Handler既可以发送消息,又包含消息的处理逻辑。我们可以利用Handler对象调用其sendMessage()方法在子线程中发送出一条消息,这条消息就包含更新UI的指令,注意!这条消息是在子线程中发送出去的。很快主线程Handler对象就会接收到这条带有更新UI指令的消息,接着就会在主线程中完成对UI的更新操作。哈哈,到这里问题是不是解决很完美呢?其实上面的代码就是按照这个逻辑去写的。

Service基本用法

我们先要明确,服务的处理逻辑是独立于Activity之外的,换句话说,服务并不需要依赖于Activity而存在,所以自然的,定义Service的代码我们就用MyService类去实现,MyService类作为Service的实现类,不仅要继承自Service,还要实现Service的抽象方法。下面我们来看代码如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button 
        android:id="@+id/start_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/start_service"
        />

    <Button 
        android:id="@+id/stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/stop_service"
        />

    <Button 
        android:id="@+id/bind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/bind_service"
        />

    <Button 
        android:id="@+id/unbind_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/unbind_service"
        />

    <Button 
        android:id="@+id/start_intent_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/start_intentservice"
        />

</LinearLayout>
package com.example.servicetest;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

    private DownloadBinder mBinder = new DownloadBinder();

    class DownloadBinder extends Binder {

        public void startDownload() {
            Log.d("MyService", "startDownload executed");
        }

        public int getProgress() {
            Log.d("MyService", "getProgress executed");
            return 0;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        /*
         * 下面的notification部分写法Android官方已经不推荐这样用
         * 由于《第一行代码——Android》实在Android 4.0的基础上开发的
         * 所以会这样。
         * 
         * */
        Notification notification = new Notification(R.drawable.ic_launcher, "notification comes", System.currentTimeMillis());
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
        notification.setLatestEventInfo(this, "this is title", "this is content", pendingIntent);
        startForeground(1, notification);
        Log.d("MyService", "onCreate executed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "onStartCommand executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyService", "onDestroy executed");
    }


}
package com.example.servicetest;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService");   // 提供一个无参构造,在其内部调用其父类的有参构造函数
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntnetService", "onDestroy executed");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印当前线程的id
        Log.d("MyIntnetService", "thread id is " + Thread.currentThread().getId());
    }

}
package com.example.servicetest;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

    private Button startService;

    private Button stopService;

    private Button bindService;

    private Button unbindService;

    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 name) {

        }
    };

    private Button startIntentService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService = (Button) findViewById(R.id.start_service);
        stopService = (Button) findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
        startIntentService = (Button) findViewById(R.id.start_intent_service);
        startIntentService.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.start_service:
            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;
        case R.id.start_intent_service:
            // 打印主线程id
            Log.d("MainActivity", "thread id is " + Thread.currentThread().getId());
            Intent intentService = new Intent(this, MyIntentService.class);
            startService(intentService);
            break;
        default:
            break;
        }
    }

}

主要介绍了服务的创建、启动、销毁,以及可以自动销毁的服务—IntentService

Service实践:后台执行定时服务

实践这部分我只贴出代码如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>
package com.example.servicebestpractice;


import java.util.Date;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

public class LongRunningService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                Log.d("LongRunningService", "excuted at " + new Date().toString());
            }
        }).start();
        AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        int anHour = 1 * 1000;
        long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
        Intent i = new Intent(this, AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
        manager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
        return super.onStartCommand(intent, flags, startId);
    }

}
package com.example.servicebestpractice;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context, LongRunningService.class);
        context.startService(i);
    }

}
package com.example.servicebestpractice;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(this, LongRunningService.class);
        startService(intent);
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值