Android 中即时聊天或者后台任务需要发送消息的一种解决方案.

原创 2015年11月17日 16:32:21

    

    在即时聊天中可能会存在一个隐藏的Bug,这个Bug根据手机的网速和性能有关系,比如你即时聊天中,你发送一消息,你的网络情况不是很好,这个时候你发送的消息一直处于发送状态,然后你不想看了,就按退出,这个时候Activity或者Fragment被销毁的时候就导致了这个消息被强行GC了,所以为了解决这个方案,我们可以使用IntentService,什么是IntentService?

/*IntentService is a base class for {@link Service}s that handle asynchronous 
requests (expressed as {@link Intent}s) on demand. Clients send requests 
through {@link android.content.Context#startService(Intent)} calls; the 
service is started as needed, handles each Intent in turn using a worker 
thread, and stops itself when it runs out of work.*/


    从这个解释中可以看出来是一个异步服务,而且不用担心他自己的生命周期.所以我们就可以使用它去发送消息,当然消息发送完毕后,我们肯定要通知界面更新UI,这个时候我们就需要使用广播比较方便些.我们可以这样写一个IntentService:

package com.softtanck.intentservicedemo.service;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;

import com.softtanck.intentservicedemo.MainActivity;

/**
 * Created by winterfell on 11/17/2015.
 */
public class UpLoadImgService extends IntentService {


    public UpLoadImgService() {
        super("ceshi");
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public UpLoadImgService(String name) {
        super(name);
    }


    public static void startUploadImg(Context context, String path) {
        Intent intent = new Intent(context, UpLoadImgService.class);
        intent.setAction(MainActivity.UPLOAD_IMG);
        intent.putExtra(MainActivity.EXTRA_IMG_PATH, path);
        context.startService(intent);
    }


    @Override
    protected void onHandleIntent(Intent intent) {

        if (null != intent) {
            String action = intent.getAction();

            if (action.equals(MainActivity.UPLOAD_IMG)) {
                //UpLoad file
                uploadImg(intent.getStringExtra(MainActivity.EXTRA_IMG_PATH));
            }
        }

    }

    private void uploadImg(String path) {
        try {
            Thread.sleep(2000);
            Intent intent = new Intent(MainActivity.UPLOAD_IMG);
            intent.putExtra(MainActivity.EXTRA_IMG_PATH, path);
            sendBroadcast(intent);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


    然后在需要的地方去调用:

UpLoadImgService.startUploadImg(MainActivity.this, "/sdcard/cache/com.softtanck.intentservice/1.png");



    还有就是IntentService是继承的Service,那么它是怎么实现异步线程的.?我们先粗略看一下它的源码:

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.app;

import android.annotation.WorkerThread;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;

/**
 * IntentService is a base class for {@link Service}s that handle asynchronous
 * requests (expressed as {@link Intent}s) on demand.  Clients send requests
 * through {@link android.content.Context#startService(Intent)} calls; the
 * service is started as needed, handles each Intent in turn using a worker
 * thread, and stops itself when it runs out of work.
 *
 * <p>This "work queue processor" pattern is commonly used to offload tasks
 * from an application's main thread.  The IntentService class exists to
 * simplify this pattern and take care of the mechanics.  To use it, extend
 * IntentService and implement {@link #onHandleIntent(Intent)}.  IntentService
 * will receive the Intents, launch a worker thread, and stop the service as
 * appropriate.
 *
 * <p>All requests are handled on a single worker thread -- they may take as
 * long as necessary (and will not block the application's main loop), but
 * only one request will be processed at a time.
 *
 * <div class="special reference">
 * <h3>Developer Guides</h3>
 * <p>For a detailed discussion about how to create services, read the
 * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
 * </div>
 *
 * @see android.os.AsyncTask
 */
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     * with your preferred semantics.
     *
     * <p>If enabled is true,
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
     * and the intent redelivered.  If multiple Intents have been sent, only
     * the most recent one is guaranteed to be redelivered.
     *
     * <p>If enabled is false (the default),
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
     * dies along with it.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");//创建了一个HandlerThread
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null. 
     * @see android.app.Service#onBind
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     */
    @WorkerThread
    protected abstract void onHandleIntent(Intent intent);
}


    从源码中可以看出在OnCreat的时候初始化了一个HandlerThread,然后通过Looper的Loop去从消息队列里面去,建立了Handler的通信,而HandlerMessage中调用一个抽象的方法就是我们继承IntentService中的要实现的方法,该方法就是在线程中的,所以不需要再去开启线程.它的生命周期也是由Service是管理的.

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Android 中即时聊天或者后台任务需要发送消息的一种解决方案.

版权声明:本文为博主原创文章,未经博主允许不得转载。          在即时聊天中可能会存在一个隐藏的Bug,这个Bug根据手机的网速和性能有关系,比如你即时聊天中,你发送一消息,你的网...

后台任务稳定运行方案--不受终端关闭或者远程(ssh等)连接失败影响

我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断开...

后台任务稳定运行方案--不受终端关闭或者远程(ssh等)连接失败影响

我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断开...

Android 开发即时聊天工具 YQ :(五) 发送消息

服务器端转发消息功能上节已经实现,只需将消息转发给消息包中的接收人即可, if(m.getType().equals(YQMessageType.COM_MES)){//如果是普通消息包 ...

openfire+smack 简单的 发送消息 demo及各种错误解决方案。

昨天搭建好了,openfire准备用写一个smack写一个发送消息的demo,为了方便接收端使用Spark。 使用eclipse的同学注意,创建项目时注意要吧smack与smackx两个包都导进来,...

基于Netty实现的Android 消息推送(即时通信)的解决方案

根据Netty框架实现消息推送(即时聊天)功能. Netty框架,TCP长连接,心跳,阻塞消息队列,线程池处理消息发送, 基于Google ProtoBuf自定义的消息协议, TCP粘包/拆包......

eclipse cleanup svn时卡死或者失败的一种解决方案

经常遇到一种情况,在进行pull或者push时,svn报错,提示你应该cleanup一下,但当你cleanup时,要么就卡死,要么就报错,说是在cleanup过程中需要等待其他操作。这种情况可能是由于...

Android 后台任务(八)内存泄露

Android 后台任务(七)内存泄露 翻译自:http://www.androiddesignpatterns.com/2013/04/activitys-threads-memory-leaks...

Android开发_后台任务task管理_allowTaskReparenting alwaysRetainTaskState clearTaskOn

1.android:allowTaskReparenting 这个属性用来标记一个Activity实例在当前应用退居后台后,是否能从启动它的那个task移动到有共同affinity的task,“tr...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)