设计并实现一个LogService,应用开发时可以打印log到视图(TextView)中显示

来源:互联网 发布:淘宝自动发货订单 编辑:程序博客网 时间:2024/06/05 13:25

本文将设计并实现项目LogService,通过LogService,在开发应用时可以打印log到窗口中显示。

项目源码下载地址:http://download.csdn.net/detail/guggy/4998148

Log Watcher窗口截图:



LogService包括以下3个部分:

1. service 它负责接收客户应用的log信息,并把它发给activity显示。支持多个客户应用同时打log。在AndroidManifest.xml中声明为:

        <service            android:name=".LogService"            android:process=":remote" >            <intent-filter>                <!--                     These are the interfaces supported by the service, which                     you can bind to.                -->                <action android:name="cn.livelog.logservice.IRemoteService" />                <action android:name="cn.livelog.logservice.ILogy" />            </intent-filter>        </service>

2. activity 它的布局包含一个TextView,用来显示log,在AndroidManifest.xml中声明为:

       <activity android:name=".LogService$Binding"            android:configChanges="orientation|keyboardHidden|screenSize"            android:label="Log Watcher" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.DEFAULT" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>

3. cn-livelog-logservice-api.jar,提供接口给客户应用,编译时使用,接口包括:

    Logy.open(Context context)   打开log服务,打开后就可以通过Logy.d打印。

    Logy.close()                           关闭log服务,如果不调用,应用退出时会自动关闭log服务。

    Logy.d(String text)                  打印log,text为需要打印的字符串。


Logy.java文件如下:

public class Logy {    private static Context mContext = null;    private static ILogy mLogyService = null;    public static boolean open(Context context) {        boolean success = context.bindService(new Intent(ILogy.class.getName()), mLogyConnection,                Context.BIND_AUTO_CREATE);        if (success) {            mContext = context;        }        return success;    }    public static boolean close( ) {        if (mContext != null) {            mContext.unbindService(mLogyConnection);            mContext = null;            return true;        }        return false;    }    public static void d(String text) {        if (mLogyService != null) {            try {                mLogyService.printf(text);            } catch (RemoteException ex) {                ;            }        }    }    private static ServiceConnection mLogyConnection = new ServiceConnection() {        public void onServiceConnected(ComponentName className, IBinder service) {            // Connecting to a secondary interface is the same as any            // other interface.            mLogyService = ILogy.Stub.asInterface(service);        }        public void onServiceDisconnected(ComponentName className) {            mLogyService = null;        }    };}



客户应用使用接口的示例:

public class HelloActivity extends Activity {    Button mButton1, mButton2;    EditText mEditText;    private PowerManager mPowerManager;    /**     * Called with the activity is first created.     */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // Set the layout for this activity. You can find it        // in res/layout/hello_activity.xml        setContentView(R.layout.hello_activity);        Logy.open(this);  //打开log服务        mButton1 = (Button)findViewById(R.id.button1);        mButton1.setOnClickListener(new OnClickListener() {            public void onClick(View v) {                mEditText.setText("good morning!");                Logy.d("I am from www.livelog.cn\n");  //打印            }        });        mButton2 = (Button)findViewById(R.id.button2);        mButton2.setOnClickListener(new OnClickListener() {            public void onClick(View v) {                mEditText.setText("good evening!");                Logy.d("I am from www.hahatao.cn\n");  //打印            }        });        mEditText = (EditText)findViewById(R.id.text);    }}


LogService.java是该项目的核心文件,实现了LogService和Log显示界面。LogService和Activity分别运行在2个不同的进程中,Activity通过bindService来启动LogService,LogService从客户应用接收log后,通过binder回调显示到Activity的TextView中。

下面是源码:

public class LogService extends Service {    /**     * This is a list of callbacks that have been registered with the     * service.  Note that this is package scoped (instead of private) so     * that it can be accessed more efficiently from inner classes.     */    final RemoteCallbackList<IRemoteServiceCallback> mCallbacks            = new RemoteCallbackList<IRemoteServiceCallback>();    NotificationManager mNM;    @Override    public void onCreate() {        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);        // Display a notification about us starting.        showNotification();    }    @Override    public void onDestroy() {        // Cancel the persistent notification.        mNM.cancel(R.string.remote_service_started);        // Tell the user we stopped.        Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();        // Unregister all callbacks.        mCallbacks.kill();        // Remove the next pending message to increment the counter, stopping        // the increment loop.        mHandler.removeMessages(LOG_PRINT);    }    protected void sendMessage(int msgType, String obj) {        Message msg = Message.obtain(mHandler, msgType);        msg.obj = obj;        msg.sendToTarget();    }// BEGIN_INCLUDE(exposing_a_service)    @Override    public IBinder onBind(Intent intent) {        // Select the interface to return.  If your service only implements        // a single interface, you can just return it here without checking        // the Intent.        if (IRemoteService.class.getName().equals(intent.getAction())) {            return mBinder;        }        if (ILogy.class.getName().equals(intent.getAction())) {            return mLogyBinder;        }        return null;    }    /**     * The IRemoteInterface is defined through IDL     */    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {        public void registerCallback(IRemoteServiceCallback cb) {            if (cb != null) mCallbacks.register(cb);        }        public void unregisterCallback(IRemoteServiceCallback cb) {            if (cb != null) mCallbacks.unregister(cb);        }    };    /**     * A Log interface to the service.     */    private final ILogy.Stub mLogyBinder = new ILogy.Stub() {        public void printf(String text) {            sendMessage(LOG_PRINT, text);        }    };// END_INCLUDE(exposing_a_service)    @Override    public void onTaskRemoved(Intent rootIntent) {        Toast.makeText(this, "Task removed: " + rootIntent, Toast.LENGTH_LONG).show();    }    private static final int LOG_PRINT = 1;    /**     * Our Handler used to execute operations on the main thread.  This is used     * to schedule increments of our value.     */    private final Handler mHandler = new Handler() {        @Override public void handleMessage(Message msg) {            switch (msg.what) {                case LOG_PRINT: {                    // Up it goes.                    String text = (String)msg.obj;                    // Broadcast to all clients the new value.                    final int N = mCallbacks.beginBroadcast();                    for (int i=0; i<N; i++) {                        try {                            mCallbacks.getBroadcastItem(i).printCallback(text);                        } catch (RemoteException e) {                            // The RemoteCallbackList will take care of removing                            // the dead object for us.                        }                    }                    mCallbacks.finishBroadcast();                }                break;                default:                    super.handleMessage(msg);            }        }    };    /**     * Show a notification while this service is running.     */    private void showNotification() {        // In this sample, we'll use the same text for the ticker and the expanded notification        CharSequence text = getText(R.string.remote_service_started);        // Set the icon, scrolling text and timestamp        Notification notification = new Notification(R.drawable.stat_sample, text,                System.currentTimeMillis());        // The PendingIntent to launch our activity if the user selects this notification        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,                new Intent(this, Binding.class), 0);        // Set the info for the views that show in the notification panel.        notification.setLatestEventInfo(this, getText(R.string.remote_service_label),                       text, contentIntent);        // Send the notification.        // We use a string id because it is a unique number.  We use it later to cancel.        mNM.notify(R.string.remote_service_started, notification);    }    // ----------------------------------------------------------------------    /**     * Example of binding and unbinding to the remote service.     * This demonstrates the implementation of a service which the client will     * bind to, interacting with it through an aidl interface.</p>     *     * <p>Note that this is implemented as an inner class only keep the sample     * all together; typically this code would appear in some separate class.     */ // BEGIN_INCLUDE(calling_a_service)    public static class Binding extends Activity {        /** The primary interface we will be calling on the service. */        IRemoteService mService = null;        TextView mCallbackText;        private boolean mIsBound;        /**         * Standard initialization of this activity.  Set up the UI, then wait         * for the user to poke it before doing anything.         */        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.log_service_binding);            mCallbackText = (TextView)findViewById(R.id.callback);            bindService(new Intent(IRemoteService.class.getName()),                    mConnection, Context.BIND_AUTO_CREATE);            mIsBound = true;        }        /**         * Class for interacting with the main interface of the service.         */        private ServiceConnection mConnection = new ServiceConnection() {            public void onServiceConnected(ComponentName className,                    IBinder service) {                // This is called when the connection with the service has been                // established, giving us the service object we can use to                // interact with the service.  We are communicating with our                // service through an IDL interface, so get a client-side                // representation of that from the raw service object.                mService = IRemoteService.Stub.asInterface(service);                // We want to monitor the service for as long as we are                // connected to it.                try {                    mService.registerCallback(mCallback);                } catch (RemoteException e) {                    // In this case the service has crashed before we could even                    // do anything with it; we can count on soon being                    // disconnected (and then reconnected if it can be restarted)                    // so there is no need to do anything here.                }                // As part of the sample, tell the user what happened.                Toast.makeText(Binding.this, R.string.remote_service_started,                        Toast.LENGTH_SHORT).show();            }            public void onServiceDisconnected(ComponentName className) {                // This is called when the connection with the service has been                // unexpectedly disconnected -- that is, its process crashed.                mService = null;                // As part of the sample, tell the user what happened.                Toast.makeText(Binding.this, R.string.remote_service_stopped,                        Toast.LENGTH_SHORT).show();            }        };        private OnClickListener mBindListener = new OnClickListener() {            public void onClick(View v) {                // Establish a couple connections with the service, binding                // by interface names.  This allows other applications to be                // installed that replace the remote service by implementing                // the same interface.                bindService(new Intent(IRemoteService.class.getName()),                        mConnection, Context.BIND_AUTO_CREATE);                mIsBound = true;            }        };        private OnClickListener mUnbindListener = new OnClickListener() {            public void onClick(View v) {                if (mIsBound) {                    // If we have received the service, and hence registered with                    // it, then now is the time to unregister.                    if (mService != null) {                        try {                            mService.unregisterCallback(mCallback);                        } catch (RemoteException e) {                            // There is nothing special we need to do if the service                            // has crashed.                        }                    }                    // Detach our existing connection.                    unbindService(mConnection);                    mIsBound = false;                }            }        };        // ----------------------------------------------------------------------        // Code showing how to deal with callbacks.        // ----------------------------------------------------------------------        /**         * This implementation is used to receive callbacks from the remote         * service.         */        private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {            public void printCallback(String text) {                mHandler.sendMessage(mHandler.obtainMessage(LOG_PRINT, text));            }        };        private static final int LOG_PRINT = 1;        private Handler mHandler = new Handler() {            @Override public void handleMessage(Message msg) {                switch (msg.what) {                    case LOG_PRINT:                        String text = mCallbackText.getText().toString();                        mCallbackText.setText(text + (String)msg.obj);                        break;                    default:                        super.handleMessage(msg);                }            }        };    }// END_INCLUDE(calling_a_service)}





原创粉丝点击