alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (StreamLoader.java)

This example Android source code file (StreamLoader.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

android, assertionerror, context, handler, headers, http, inputstream, internet, io, ioexception, loadlistener, msg_data, msg_end, msg_headers, msg_status, net, network, os, send, streamloader

The StreamLoader.java Android example source code

/*
 * Copyright (C) 2007 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.webkit;

import android.content.Context;
import android.net.http.EventHandler;
import android.net.http.Headers;
import android.os.Handler;
import android.os.Message;

import java.io.IOException;
import java.io.InputStream;

/**
 * This abstract class is used for all content loaders that rely on streaming
 * content into the rendering engine loading framework.
 *
 * The class implements a state machine to load the content into the frame in
 * a similar manor to the way content arrives from the network. The class uses
 * messages to move from one state to the next, which enables async. loading of
 * the streamed content.
 *
 * Classes that inherit from this class must implement two methods, the first
 * method is used to setup the InputStream and notify the loading framework if
 * it can load it's content. The other method allows the derived class to add
 * additional HTTP headers to the response.
 *
 * By default, content loaded with a StreamLoader is marked with a HTTP header
 * that indicates the content should not be cached.
 *
 */
abstract class StreamLoader implements Handler.Callback {

    private static final int MSG_STATUS = 100;  // Send status to loader
    private static final int MSG_HEADERS = 101; // Send headers to loader
    private static final int MSG_DATA = 102;  // Send data to loader
    private static final int MSG_END = 103;  // Send endData to loader

    protected final Context mContext;
    protected final LoadListener mLoadListener; // loader class
    protected InputStream mDataStream; // stream to read data from
    protected long mContentLength; // content length of data
    private byte [] mData; // buffer to pass data to loader with.

    // Handler which will be initialized in the thread where load() is called.
    private Handler mHandler;

    /**
     * Constructor. Although this class calls the LoadListener, it only calls
     * the EventHandler Interface methods. LoadListener concrete class is used
     * to avoid the penality of calling an interface.
     *
     * @param loadlistener The LoadListener to call with the data.
     */
    StreamLoader(LoadListener loadlistener) {
        mLoadListener = loadlistener;
        mContext = loadlistener.getContext();
    }

    /**
     * This method is called when the derived class should setup mDataStream,
     * and call mLoadListener.status() to indicate that the load can occur. If it
     * fails to setup, it should still call status() with the error code.
     *
     * @return true if stream was successfully setup
     */
    protected abstract boolean setupStreamAndSendStatus();

    /**
     * This method is called when the headers are about to be sent to the
     * load framework. The derived class has the opportunity to add addition
     * headers.
     *
     * @param headers Map of HTTP headers that will be sent to the loader.
     */
    abstract protected void buildHeaders(Headers headers);

    /**
     * Calling this method starts the load of the content for this StreamLoader.
     * This method simply creates a Handler in the current thread and posts a
     * message to send the status and returns immediately.
     */
    final void load() {
        synchronized (this) {
            if (mHandler == null) {
                mHandler = new Handler(this);
            }
        }

        if (!mLoadListener.isSynchronous()) {
            mHandler.sendEmptyMessage(MSG_STATUS);
        } else {
            // Load the stream synchronously.
            if (setupStreamAndSendStatus()) {
                // We were able to open the stream, create the array
                // to pass data to the loader
                mData = new byte[8192];
                sendHeaders();
                while (!sendData() && !mLoadListener.cancelled());
                closeStreamAndSendEndData();
                mLoadListener.loadSynchronousMessages();
            }
        }
    }

    public boolean handleMessage(Message msg) {
        if (mLoadListener.isSynchronous()) {
            throw new AssertionError();
        }
        if (mLoadListener.cancelled()) {
            closeStreamAndSendEndData();
            return true;
        }
        switch(msg.what) {
            case MSG_STATUS:
                if (setupStreamAndSendStatus()) {
                    // We were able to open the stream, create the array
                    // to pass data to the loader
                    mData = new byte[8192];
                    mHandler.sendEmptyMessage(MSG_HEADERS);
                }
                break;
            case MSG_HEADERS:
                sendHeaders();
                mHandler.sendEmptyMessage(MSG_DATA);
                break;
            case MSG_DATA:
                if (sendData()) {
                    mHandler.sendEmptyMessage(MSG_END);
                } else {
                    mHandler.sendEmptyMessage(MSG_DATA);
                }
                break;
            case MSG_END:
                closeStreamAndSendEndData();
                break;
            default:
                return false;
        }
        return true;
    }

    /**
     * Construct the headers and pass them to the EventHandler.
     */
    private void sendHeaders() {
        Headers headers = new Headers();
        if (mContentLength > 0) {
            headers.setContentLength(mContentLength);
        }
        buildHeaders(headers);
        mLoadListener.headers(headers);
    }

    /**
     * Read data from the stream and pass it to the EventHandler.
     * If an error occurs reading the stream, then an error is sent to the
     * EventHandler, and moves onto the next state - end of data.
     * @return True if all the data has been read. False if sendData should be
     *         called again.
     */
    private boolean sendData() {
        if (mDataStream != null) {
            try {
                int amount = mDataStream.read(mData);
                if (amount > 0) {
                    mLoadListener.data(mData, amount);
                    return false;
                }
            } catch (IOException ex) {
                mLoadListener.error(EventHandler.FILE_ERROR, ex.getMessage());
            }
        }
        return true;
    }

    /**
     * Close the stream and inform the EventHandler that load is complete.
     */
    private void closeStreamAndSendEndData() {
        if (mDataStream != null) {
            try {
                mDataStream.close();
            } catch (IOException ex) {
                // ignore.
            }
        }
        mLoadListener.endData();
    }
}

Other Android examples (source code examples)

Here is a short list of links related to this Android StreamLoader.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.