How develop Applications for Smartphones and PC - java

i am writing an application for android but i am planning to build this for the pc, too. So i want to reuse as much code as possible. But there are some cases where i have to use platform-specific functions. For example for logging-output and loading resources.
I am searching for an easy solution to abstract these features. My current solution is that i have written this class
public class LoggerAndroid{
public static void debug(String tag, String msg) {
Log.d(tag, msg);
}
public static void error(String tag, String msg) {
Log.e(tag, msg);
}
public static void info(String tag, String msg) {
Log.i(tag, msg);
}
public static void warn(String tag, String msg) {
Log.w(tag, msg);
}
}
and this one
public class Logger extends LoggerAndroid{
}
In my code i use expressions like
Logger.info("test", "HelloWorld");
and for writing the pc application i write another log class with the same methods and let Logger inherit from that one.
So there are very few changes to make and using the log-methods is still easy. But i think maintaining the code and be quite heavy-handed.
Are there better solutions for that?

I think an interface would operate better.
Take a look at this code:
public interface ILogger {
public void debug(String tag, String msg);
public void error(String tag, String msg);
public void info(String tag, String msg);
public void warn(String tag, String msg);
}
public class AndroidLogger implements ILogger {
#Override
public void debug(String tag, String msg) {
Log.d(tag, msg);
}
#Override
public void error(String tag, String msg) {
Log.e(tag, msg);
}
#Override
public void info(String tag, String msg) {
Log.i(tag, msg);
}
#Override
public void warn(String tag, String msg) {
Log.w(tag, msg);
}
}
Then, all you have to do is:
ILogger log = new AndroidLogger();
And in windows, that'd be:
ILogger log = new WindowsLogger();
This code makes it have no difference at all.
Is this what you meant in your question?

Favor Composition over Inheritance. Use Inversion of Control and the Strategy Pattern to hot swap out the Logger instance. For an illuminating example, see this on the related concept of toString().

Related

Is it possible to create one class that handle all log code in android (ex. Log.d(TAG,message) )

I want to find a way if it's possible in my case like this :
I have many java class:
First :
class A{
A(){
Log.d(TAG,"message construct A");
}
public void myMethod(){
Log.d(TAG,"message A");
}
public void myAnotherMethod(){
Log.d(TAG,"message another A");
}
}
Second :
class B{
B(){
Log.d(TAG,"message construct B");
}
public void myBMethod(){
Log.d(TAG,"message B");
}
public void myAnotherBMethod(){
Log.d(TAG,"message another B");
}
}
it's quite a waste of time if i want to delete all the Log within 300 class that I have created and if I want to re-create the Log again will be very tiring for jumping from one class to another class..
I wonder if it's possible for some kind of this Log Management design :
A.class
class A{
A(){
//my code
}
public void myMethod(){
//my code
}
public void myAnotherMethod(){
//my code
}
}
B.class
class B{
B(){
//my code
}
public void myBMethod(){
//my code
}
public void myAnotherBMethod(){
//my code
}
}
and the log class management :
class Log {
onObjectCreated(){
if(object == A) Log.d(TAG,"construct A");
else Log.d(TAG,"construct B");
}
onMethodCall(){
Log.d(TAG,"message A");
}
onMethodBCall(){
Log.d(TAG,"message B");
}
}
So, in future development if I want to remove or add some Log code, I just need to manage it within one class
Is there any way for that in Native Java Android ?
Thank you.
Try it , I think will helpful for you.
Logger.i(TAG, AppConst.EACH_PAGE_FOR_LOG);
Logger Example:
public class Logger {
public static void d(String tag, String data){
if(BuildConfig.DEBUGGABLE) {
Log.d(tag, data);
}
}
public static void i(String tag, String data){
if(BuildConfig.DEBUGGABLE) {
Log.i(tag, data);
}
}
public static void e(String tag, String data){
if(BuildConfig.DEBUGGABLE) {
Log.e(tag, data);
}
}
public static void e(String tag, String data, Throwable t){
if(BuildConfig.DEBUGGABLE) {
Log.e(tag, data, t);
}
}
public static void w(String tag, String data){
if(BuildConfig.DEBUGGABLE) {
Log.w(tag, data);
}
}
public static void wtf(String tag, String data){
if(BuildConfig.DEBUGGABLE) {
Log.wtf(tag, data);
}
}
public static boolean isDebugEnabled(String tag) {
return BuildConfig.DEBUGGABLE;
}
}
Yes you can create a separate class for LOGS containing static methods with a flag and disable the flag when you don't need that.
Maybe it will help to make your task easier for all in one class
import android.util.Log;
public class AppLogClass {
public void e(String tag, String msg){
if (BuildConfig.DEBUG) {
Log.e(tag, msg);
}
}
public void d(String tag, String msg){
if (BuildConfig.DEBUG) {
Log.d(tag, msg);
}
}
}
Aside from creating own logger, you can alternatively use proguard to remove all log calls of your choice (or all) without a need to altering your sources. See this question: Removing Log call using proguard

Java: Extend functionality of listener method from another class

I thought of creating a separate class for all of the smack's basic methods like connecting, login, sending message, receiving messages.
So, there's a listener method which receives messages.
static ChatManagerListener chatManagerListener = new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean createdLocally) {
chat.addMessageListener(
new ChatMessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
System.out.println("MESSAGE RECEIVED: "+message.toString());
messageReceived(message);
}
});
}
};
Message is received and passed to messageReceived() method.
SITUATION:
Now, when I import this class into other, I would like to extend the functionality of this messageReceived() method, so the whole process remains abstract and the developer only deals with incoming messages. Or, somehow this messageReceived() method push the message to that other class.
Basically you need to define another listner to manage the message.
This is a working snippet example (of a prototype, so it's ugly and without any pattern) to update the GUI of reciver user.
If you'll need something else keep in mind that you'll need plugins (PacketInterceptor) on server side.
/*MessageGuiUpdate.java*/
public interface MessageGuiUpdate {
public void displayMessage(String body);
}
/*XmppManager.java*/
public void init() throws XMPPException, SmackException, IOException {
private MessageGuiUpdate guiUpdate;
//FOO
//BAR
/* init() */
this.chatManager = ChatManager.getInstanceFor(connection);
this.chatManager.addChatListener(
new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean createdLocally)
{
if (!createdLocally)
{
chat.addMessageListener(new IncomingMessageListener());;
}
}
});
}
/*nested class*/
class IncomingMessageListener implements ChatMessageListener {
#Override
public void processMessage(Chat arg0, Message message) {
String from = message.getFrom();
String body = message.getBody();
if (body != null)
{
System.out.println(String.format("============ Received message '%1$s' from %2$s\n============", body, from));
guiUpdate.displayMessage(body);
}
}
}
/*CustomGui.java*/
public class CustomGui implements MessageGuiUpdate {
//foo
#Override
public void displayMessage(String message) {
System.out.println("I've just recived: "+message);
}
}

Android log4j Logging Multiple times

Hi Guys got a issue here using Log4j.
My code is
public class MyLogger{
private static Logger mLogger = LoggerFactory.getLogger(MyLogger.class);
public static void configure() {
LogConfigurator logConfigurator = new LogConfigurator();
logConfigurator.setFileName(getLogPath());
logConfigurator.setRootLevel(Level.DEBUG);
logConfigurator.setLevel("com.**", Level.ALL);
logConfigurator.setMaxFileSize(1024 * 1024 * 5);
logConfigurator.configure();
}
public static void info(String msg) {
mLogger.info(msg);
}
public static void warn(String msg) {
mLogger.warn(msg);
}
public static void debug(String msg) {
mLogger.debug(msg);
}
public static void error(String msg) {
mLogger.error(msg);
}
This code works but as I noticed it is logged multiple times. I tried reading some tutorial here and they say that I need to add additivity="false" but that function is not available on Jar file.
Each enabled logging request for a given logger will be forwarded to all the appenders in that logger, as well as the appenders higher in the hierarchy.
Check log4j.properties and make the change to have it set to false :
log4j.additivity.com.javacodegeeks.examples.log4jadditivity.theClass=false

Flexible enable/disable logging in Android app

For performance wise, some people suggest use the following method, e.g.
public class MyActivity extends Activity {
private static final String TAG = "MyApp";
private static final boolean D = true;
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(D) Log.e(TAG, "MyActivity.onCreate debug message"); }
But this is non-senese when are working on a large project, because when you debug, you need to update many files for the debug flag, are there any better method?
You can check the DEBUG boolean in your BuildConfig:
if (BuildConfig.DEBUG) {
// Do what you need
}
Or else, you can have a debug variable, but instead or keeping it in every activity, declare it in you Application class, and check it's value whenever you need.
If your purpose of that variable is for logging, is a good practice to wrap your loggings into another class, which checks the DEBUG variable:
public class LogUtils {
public static void LOGD(final String tag, String message) {
if (BuildConfig.DEBUG) {
Log.d(tag, message);
}
}
public static void LOGV(final String tag, String message) {
if (BuildConfig.DEBUG) {
Log.v(tag, message);
}
}
public static void LOGI(final String tag, String message) {
if (BuildConfig.DEBUG) {
Log.i(tag, message);
}
}
public static void LOGW(final String tag, String message) {
if (BuildConfig.DEBUG) {
Log.w(tag, message);
}
}
public static void LOGE(final String tag, String message) {
if (BuildConfig.DEBUG) {
Log.e(tag, message);
}
}
}
Then, make log calls to this class:
LogUtils.LOGD(TAG, "MyActivity.onCreate debug message");
I strongly recommend what Google guys developed at their open source app iosched. Among other reasons it keeps in mind BuildConfig and checks to see whether or not a log for the specified tag is loggable at the specified level with isLoggable. It's a must for my projects.
/*
* Copyright 2012 Google Inc.
*
* 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 com.google.android.apps.iosched.util;
import com.google.android.apps.iosched.BuildConfig;
import android.util.Log;
/**
* Helper methods that make logging more consistent throughout the app.
*/
public class LogUtils {
private static final String LOG_PREFIX = "iosched_";
private static final int LOG_PREFIX_LENGTH = LOG_PREFIX.length();
private static final int MAX_LOG_TAG_LENGTH = 23;
public static String makeLogTag(String str) {
if (str.length() > MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH) {
return LOG_PREFIX + str.substring(0, MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH - 1);
}
return LOG_PREFIX + str;
}
/**
* WARNING: Don't use this when obfuscating class names with Proguard!
*/
public static String makeLogTag(Class cls) {
return makeLogTag(cls.getSimpleName());
}
public static void LOGD(final String tag, String message) {
if (Log.isLoggable(tag, Log.DEBUG)) {
Log.d(tag, message);
}
}
public static void LOGD(final String tag, String message, Throwable cause) {
if (Log.isLoggable(tag, Log.DEBUG)) {
Log.d(tag, message, cause);
}
}
public static void LOGV(final String tag, String message) {
//noinspection PointlessBooleanExpression,ConstantConditions
if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.VERBOSE)) {
Log.v(tag, message);
}
}
public static void LOGV(final String tag, String message, Throwable cause) {
//noinspection PointlessBooleanExpression,ConstantConditions
if (BuildConfig.DEBUG && Log.isLoggable(tag, Log.VERBOSE)) {
Log.v(tag, message, cause);
}
}
public static void LOGI(final String tag, String message) {
Log.i(tag, message);
}
public static void LOGI(final String tag, String message, Throwable cause) {
Log.i(tag, message, cause);
}
public static void LOGW(final String tag, String message) {
Log.w(tag, message);
}
public static void LOGW(final String tag, String message, Throwable cause) {
Log.w(tag, message, cause);
}
public static void LOGE(final String tag, String message) {
Log.e(tag, message);
}
public static void LOGE(final String tag, String message, Throwable cause) {
Log.e(tag, message, cause);
}
private LogUtils() {
}
}
Another solution is found in one of the answers to this somewhat related question. You can override the Log class like this:
public class Log {
static final boolean LOG = false;
public static void i(String tag, String string) {
if (LOG) android.util.Log.i(tag, string);
}
public static void e(String tag, String string) {
if (LOG) android.util.Log.e(tag, string);
}
public static void d(String tag, String string) {
if (LOG) android.util.Log.d(tag, string);
}
public static void v(String tag, String string) {
if (LOG) android.util.Log.v(tag, string);
}
public static void w(String tag, String string) {
if (LOG) android.util.Log.w(tag, string);
}
}
This way, you don't need the if statement every time you use log. Just change the boolean in your overridden Log class. When you're ready to publish, you can use a tool like ProGuard to strip all the references to Log for performance.
Strip out Log.v and Log.d messages using ProGuard
An alternative approach, with less code, is to have these stripped out for the final release app using ProGuard.
Basically, in the app\proguard-rules.pro file, define the methods of the android.util.Log class that you want stripped out. The following addition to the proguard-rules.pro file will cause the v (verbose) and d (debug) methods to be stripped out at build time:
# This tell Proguard to assume Log.v and Log.d have no side effects (even
# though they do since they write to the logs) and thus can be removed
# during optimization:
-assumenosideeffects class android.util.Log {
public static int v(...);
public static int d(...);
}
This avoids the need for if (BuildConfig.DEBUG)-style checks peppered throughout the code.
Also see: Disable LogCat Output COMPLETELY in release Android app?
I've written a LogWrapper class which is simple and looks something like this:
public class LogWrapper {
private static final String DEBUG_TAG = "some-tag"
private static boolean logsEnabled;
public static void e(String msg) {
if (logsEnabled) {
Log.e(DEBUG_TAG, msg);
}
}
// other Log methods
}
You can use it instead of Log class, modifying the boolean variable as you wish in one place. Hope this helps.
I had the same problem recently, and I don't think that stripping off the classes with Proguard is a good idea to disable logs. So I ended up writing a simple drop-in replacement for the standard Android Log class
https://github.com/zserge/log
It allows you to control the log levels. It also gives you a lot of "sugar" for logging multiple values, for log tags and even more, and it all comes with only 200 lines of code available on Maven Central/JCenter.

How create log4j wrap and get correct logs

I have multithreaded application and i want add some text information in every log message
I create factory and extend class, it works fine
...
protected Logger logger = Logger.getLogger("Test", new MyLog4JFactory());
...
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggerFactory;
public class MyLog4JFactory implements LoggerFactory{
#Override
public Logger makeNewLoggerInstance(String arg0) {
return new MyLogger(arg0);
}
}
import org.apache.log4j.Logger;
public class MyLogger extends Logger{
protected MyLogger(String name) {
super(name);
}
private String getMessage(Object msg){
StringBuffer sb = new StringBuffer();
return sb.append(msg).append(" ").append("My text").toString();
}
#Override
public void debug(Object message) {
super.debug(getMessage(message));
}
#Override
public void error(Object message) {
super.error(getMessage(message));
}
#Override
public void fatal(Object message) {
super.fatal(getMessage(message));
}
#Override
public void info(Object message) {
super.info(getMessage(message));
}
#Override
public void warn(Object message) {
super.warn(getMessage(message));
}
}
but! in the logs I see the wrapper class
all logs print as
2011-09-08 10:45:49,359 DEBUG MyLogger (35) - Test1 My text
What should I do to the log file shows a classes (with line number) calls my logger?
I know this is an old question, but I would like to share a nice solution I found:
Add FQCN to your class,
call Logger.log method and pass it your FQCN
like so:
public class MyLogger extends Logger{
private static String FQCN = MyLogger.class.getName();
...
#Override
public void debug(Object message) {
super.log(FQCN, org.apache.log4j.Level.DEBUG,message, null);
}
#Override
public void debug(Object message,Throwable t) {
super.log(FQCN, org.apache.log4j.Level.DEBUG,message, t);
}
}
(same will work for creating a wrapper...)
In your log4j.properties file, remove the %l specifier from the line that looks something like this:
log4j.appender.A1.layout.ConversionPattern=<...>
ConversionPattern could be PatternLayout or something else. This will prevent the fully qualified calling class name and line number from being displayed.
More information on the specifiers can be found here.

Categories