Home>

Object creation is never free. A general-purpose garbage collector that uses a thread allocation pool can make the allocation of temporary objects cheaper. But allocating memory is always more expensive than not allocating.So it is important to avoid creating unnecessary objects.

Foreword

As more objects are allocated in the app,You have to implement regular mandatory garbage collection,Will cause a small stutter in the user experience.The concurrent garbage processor was introduced in android 2.3, but unnecessary work should always be avoided,So you should avoid creating object instances when you don't need them.

In programming development,Memory usage is a reality we often face,The usual direction of memory tuning is to minimize memory usage.

Android devices don't have enough memory like pc,And the memory occupied by a single app is actually relatively small.So avoiding creating unnecessary objects is especially important for android development.

This article will introduce some common scenarios and methods to avoid creating objects,Some of them are micro-optimized,Some are coding techniques,Of course, there are ways to make a significant difference.

Use singleton

Singleton is our common design pattern,Using this model,We can provide only one object for global invocation.So singletons are a way to avoid creating unnecessary objects.

Easy to use in singleton mode,But there are many issues to be aware of,The most important thing is to ensure the uniqueness of the singleton in the case of multi-threaded concurrency.Of course there are many ways,Like hungry,Lazy Mandouble-check and so on.

Here is a very geeky way to write a singleton.

public class singleinstance {
 private singleinstance () {
 }
 public static singleinstance getinstance () {
   return singleinstanceholder.sinstance;
 }
 private static class singleinstanceholder {
   private static singleinstance sinstance=new singleinstance ();
 }
}

In java, the static initialization of a class is triggered when the class is loaded,We use this principle,Can use this feature,Combined with inner classes,Can implement the above code,Create lazy examples.

Avoid implicit boxing

Autoboxing is a feature introduced in Java 5,That is, the original type of data is automatically converted into the corresponding reference type.For example, changingint tointeger and so on.

This characteristic,Greatly reduces the trivial work of coding,But a little carelessness may create unnecessary objects.For example, the following code

integer sum=0;
for (int i=1000;i<5000;i ++) {
  sum +=i;
}

The above codesum +=i can be seen assum=sum + i , but the + operator is not applicable to integer objects. First, sum is used for automatic unboxing.Perform numerical addition,Finally, the automatic boxing operation is converted into an integer object.

Its internal changes are as follows

int result=sum.intvalue () + i;
integer sum=new integer (result);

Since the sum we declared here is of type integer, nearly 4000 useless integer objects will be created in the above loop. In such a huge loop,Will reduce the performance of the program and increase the workload of garbage collection.So when we program,Need to note this,Declare the variable type correctly,Avoid performance issues caused by autoboxing.

In addition, when values ​​of primitive data types are added to the collection,Autoboxing also happens,Therefore, objects are created during this process.Avoid this if necessary,Can choosesparsearray ,sparsebooleanarray ,sparselongarray and other containers.

Choose containers carefully

Java and Android provide many edited container collections to organize objects.E.g.arraylist ,contentvalues ,hashmap and so on.

However, although this container is convenient to use,But there are some problems,Is that they will expand automatically,This is not creating a new object,Instead, create a larger container object.This means that it will take up more memory space.

Take hashmap as an example, when weput key andvalue , it will detect if it needs to expand,Double capacity if needed

@override public v put (k key, v value) {
    if (key == null) {
      return putvaluefornullkey (value);
    }
    //some code here
    //no entry for (non-null) key is present;create one
    modcount ++;
    if (size ++&threshold;threshold) {
      tab=doublecapacity ();
      index=hash & (tab.length-1);
    }
    addnewentry (key, value, hash, index);
    return null;
  }

On the issue of capacity expansion,There are usually the following methods

1. Estimate a larger capacity value,Avoid multiple expansions

2. Find alternative data structures,Ensure a balance between time and space

Make good use of launchmode

Mention that launchmode is necessarily related to activity. Under normal circumstances we declare the activity in the manifest, if you do not set launchmode, use the default standard mode.

Once set to standard, a new activity instance will be created whenever there is an intent request. for example,If there are 10 intents to compose emails, then 10 instances of composemailactivity are created to handle these intents. The results are obvious,This pattern creates multiple instances of an activity.

If for a search function activity, actually keep an activity example,Using standard mode will cause excessive creation of activity instances,So bad.

To ensure common sense,Use launchmode properly to reduce activity creation.

activity handling onconfigurationchanged

This is another related to the creation of activity objects,Because the cost of activity creation is much higher than other objects.

by default,When we rotate the screen,The original activity will be destroyed and a new activity will be created.Of course, this is the default method of the system.When we develop controllable situations,We can avoid recreating the activity.

Take screen switching as an example.When the activity is declared, add

<activity
  android:name=". mainactivity"
  android:label="@ string/app_name"
  android:theme="@ style/apptheme.noactionbar"
  android:configchanges="orientation"
>

Then rewrite theof the activity onconfigurationchanged method

public void onconfigurationchanged (configuration newconfig) {
  super.onconfigurationchanged (newconfig);
  if (newconfig.orientation == configuration.orientation_portrait) {
    setcontentview (r.layout.portrait_layout);
  } else if (newconfig.orientation == configuration.orientation_landscape) {
    setcontentview (r.layout.landscape_layout);
  }
}

Note string concatenation

This string is perhaps the most inconspicuous one.The main thing here is the concatenation of strings

log.i (logtag, "oncreate bundle =" + savedinstancestate);

This should be our most common way to log,However, the stitching of strings actually generatesstringbuilder objects, and then append them one by one until the last call tostring method.

Here is the code of a code loop,This is obviously very bad,Because a lot ofis created in this stringbuilder object.

public void implicitusestringbuilder (string [] values) {
 string result="";
 for (int i=0;i<values.length;i ++) {
   result +=values ​​[i];
 }
 system.out.println (result);
}

Ways to reduce string splicing are

1. Replace with string.format

2. If it is circular stitching,It is recommended to explicitly create the stringbuilder for use outside the loop

Reduce layout hierarchy

Too many layout levels,Not only causes the inflate process to be time consuming,Also created extra auxiliary layouts.So it is necessary to reduce the auxiliary layout.You can try other layout methods or custom views to solve this kind of problem.

Check in advance,Reduce unnecessary exceptions

For programs,Normally,Then the exception code is actually very high,Because it needs to collect field data stacktrace. But there are some measures to avoid exception throwing,That is to do some advance inspection.

For example, we want to print each line of a file in a file,The code without checking is as follows,Is presentfilenotfoundexception throws possible.

private void printfilebyline (string filepath) {
  try {
    fileinputstream inputstream=new fileinputstream ("textfile.txt");
    bufferedreader br=new bufferedreader (new inputstreamreader (inputstream));
    string strline;
    //read file line by line
    while ((strline=br.readline ())!=null) {
      //print the content on the console
      system.out.println (strline);
    }
    br.close ();
  } catch (filenotfoundexception e) {
    e.printstacktrace ();
  } catch (ioexception e) {
    e.printstacktrace ();
  }
}

If we check if the file exists,Throwsfilenotfoundexception will reduce the probability a lot,

private void printfilebyline (string filepath) {
    if (! new file (filepath) .exists ()) {
      return;
    }
    try {
      fileinputstream inputstream=new fileinputstream ("textfile.txt");
      bufferedreader br=new bufferedreader (new inputstreamreader (inputstream));
      string strline;
      //read file line by line
      while ((strline=br.readline ())!=null) {
        //print the content on the console
        system.out.println (strline);
      }
      br.close ();
    } catch (filenotfoundexception e) {
      e.printstacktrace ();
    } catch (ioexception e) {
      e.printstacktrace ();
    }
  }

The above check is a good coding technique.Suggested adoption.

Don't create too many threads

In android, we should try to avoid performing time-consuming operations in the main thread,Therefore need to use other threads.

private void testthread () {
  new thread () {
    @override
    public void run () {
      super.run ();
      //do some io work
    }
  } .start ();
}

Although these work,But the cost of creating threads is much higher than ordinary objects.is recommended handlerthread orthreadpool to replace.

Use annotations instead of enums

Enumeration is a method we often use as a value qualification.Using enums is more reliable than simple constant conventions.Then the essence of enumeration is to create objects.Fortunately, android provides related annotations,So that the value is qualified at compile time,This reduces stress during operation.Related annotations are intdef and stringdef.

The following uses intdef as an example to introduce how to use

Declare as follows in a file

public class appconstants {
  public static final int state_open=0;
  public static final int state_close=1;
  public static final int state_broken=2;
  @intdef ((state_open, state_close, state_broken))
  public @interface doorstate {}
}

Then set the writing method

private void setdoorstate (@ appconstants.doorstate int state) {
  //some code
}

You can only usewhen calling methods state_open ,state_close andstate_broken . Using other values ​​causes compilation reminders and warnings.

Select Object Pool

There are many pool concepts in android,Such as the thread pool,connection pool. Including our long-usedhandler.message is the technology that uses pools.

For example, we want to send a message using a handler,You can usemessage msg=new message () ormessage msg=handler.obtainmessage () . Using a pool does not create new objects every time,Instead, objects are taken from the pool first.

Need to pay attention to using the object pool

1. Put the object back in the pool,Pay attention to the data of the initialization object,Prevent dirty data

2. Reasonably control the growth of the pool,Avoid being too big,Cause many objects to be idle

Carefully initialize the application

Android applications can support the opening of multiple processes. The usual approach is this

<service android:name=". Networkservice"
  android:process=":network"
/>

Usually we do a lot of initialization operations in the application's oncreate method.But each process needs to execute this oncreate method.In order to avoid unnecessary initialization,It is recommended to initialize according to the process (by judging the current process name).

public class myapplication extends application {
  private static final string logtag="myapplication";
  @override
  public void oncreate () {
    string currentprocessname=getcurrentprocessname ();
    log.i (logtag, "oncreate currentprocessname =" + currentprocessname);
    super.oncreate ();
    if (getpackagename (). equals (currentprocessname)) {
      //init for default process
    } else if (currentprocessname.endswith (":network")) {
      //init for netowrk process
    }
  }
  private string getcurrentprocessname () {
    string currentprocessname="";
    int pid=android.os.process.mypid ();
    activitymanager manager=(activitymanager) this.getsystemservice (context.activity_service);
    for (activitymanager.runningappprocessinfo processinfo:manager.getrunningappprocesses ()) {
      if (processinfo.pid == pid) {
        currentprocessname=processinfo.processname;
        break;
      }
    }
    return currentprocessname;
  }
}

to sum up

  • Previous java selenium operation browser instance
  • Next Android ScrollView sliding to achieve QQ space title bar gradient