3

In SF docs, we will get an example of transient variable getting recreated each time the action is done via button. It will help to reduce view state. Although if I used static keyword the view state will get reduced. What is the actual difference and advantage of both keyword on apex controller.

<apex:page controller="ExampleController">
Time1: {!t1} <br/><br/>
Time-Transient: {!t2} <br/><br/>
<apex:form >
<apex:commandLink value="Refresh"/>
</apex:form>
</apex:page>

public class ExampleController {

    DateTime t1;
    static DateTime t2;

    public String getT1() {
        if (t1 == null) t1 = System.now();
        return '' + t1;
    }

    public String getT2() {
        if (t2 == null) t2 = System.now();
        return '' + t2;
    }
}
2

The main difference between the two (static versus transient) is that static variables exist only once per transaction, but transient variables can exist many times. In other words, static variables have a global scope, while transient variables have a local scope. In many examples you've likely seen, you've probably only seen these variables used at the top level of a class, and the behavior seems identical (because in that case, they are functionally equivalent).

Let's take a look at a less-published variety of the use of transient:

public class Controller {
    public class Wrapper {
        public transient Integer transientRowNumber { get; set; }
        public Integer normalRowNumber { get; set; }
    }
    public Wrapper[] items { get; set; }
    public Controller() {
        items = new Wrapper[0];
        for(Integer i = 0; i < 10; i++) {
             Wrapper temp = new Wrapper();
             temp.transientRowNumber = temp.normalRowNumber = i;
             items.add(temp);
        }
    }
}

<apex:page controller="Controller">
    <apex:form>
        <table>
            <thead>
                <tr>
                    <th>
                        Transient
                    </th>
                    <th>
                        Non-Transient
                    </th>
                </tr>
            </thead>
            <tbody>
                <apex:repeat value="{!items}" var="item">
                    <tr>
                        <td>
                            {!item.transientRowNumber}
                        </td>
                        <td>
                            {!item.normalRowNumber}
                        </td>
                    </tr>
                </apex:repeat>
            </tbody>
        </table>
        <apex:commandButton value="Refresh" />
    </apex:form>
</apex:page>

In this code, you'll see the values loaded initially, but when you click the button, the left column will be cleared out. We did not store that column in our view state, so on the next round-trip to the server, those values do not persist. This is something you can't do with static variables, as only one static variable can exist at a time, and you can't put static variables inside an inner class.

This usage is rarer, but it might be helpful to know for certain kinds of algorithms, especially when you start using "wrapper" classes to organize data for display in a Visualforce page.

| improve this answer | |
2

Use the Transient keyword to declare instance variables that can't be saved and shouldn't be transmitted as part of the view state for a visualforce page. These variables will not persist across multiple transactions or when a visualforce page is refreshed. The latter is one very important thing to remember about them since they aren't contained in the view state and a new instance of the controller is created. You can learn more about them in the Apex Docs.

As an FYI:

Some Apex objects are automatically considered transient, that is, their value does not get saved as part of the page's view state. These objects include the following:

  • PageReferences
  • XmlStream classes
  • Collections automatically marked as transient only if the type of object that they hold is automatically marked as transient, such as a collection of Savepoints
  • Most of the objects generated by system methods, such as Schema.getGlobalDescribe. JSONParser class instances.

Static variables also do not get transmitted to the view state which is why you saw the earlier reduction in view state when you began using them. However, unlike transient variables, they do persist across the same transaction context. They'll persist when a page is refreshed.

| improve this answer | |
  • I think your last sentence is possibly confusing; static variables don't persist across VF page requests (commandButton/link/actionFunction/...). Static variables in controllers often should be coded using the lazy load pattern - test for null, if null, init, otherwise return current value – cropredy Oct 26 '19 at 19:06
  • @cropredy Often times static variables are used in helper classes. They typcially do persist across page action methods (within the class/controller) that involve partial page refreshes or those that don't involve a "new page", "new instance", "new record", etc. It greatly depends on the page and how it's written as to how long they're going to persist. – crmprogdev Oct 27 '19 at 14:57
  • i'll need to do an experiment as that would contradict my priors. Helper classes shouldn't make any difference – cropredy Oct 27 '19 at 14:59
  • See the link in the Apex Docs I made reference to in my answer. It has something to say on the issue that might be helpful. – crmprogdev Oct 27 '19 at 15:01
  • see my answer - I may have misread your original answer – cropredy Oct 28 '19 at 22:52
0

In addition to the sfdcfox answer, this simple example shows how static variables are not part of the viewstate, even if you are doing Ajax refreshes

But first, a word from the doc on static variables:

They aren’t transmitted as part of the view state for a Visualforce page.

Here's a controller with a static counter and an instance variable (viewstate) counter:

public with sharing class SFSE282798 {

    public static Integer staticCounter {
        get {
            if (staticCounter == null) {
                staticCounter = 0;}
            return staticCounter;
        }
        private set;
    }

    public Integer viewStateCounter {
        get {
            if (viewStateCounter == null) {viewStateCounter = 0;}
            return viewStateCounter;
        }
        private set;
    }

    public SFSE282798() {}

    public void doCount() {     //action method for VF page
        staticCounter++;
        viewStateCounter ++;
    }
}

and here's the VF page:

<apex:page id="SFSE282798" controller="SFSE282798">
    <apex:form>
        <apex:commandButton value="Count" action="{!doCount}">
            <apex:actionSupport reRender="counters" event="onclick"/>
        </apex:commandButton>
        <p></p>
        <apex:outputPanel id="counters">
            <apex:outputText value="static counter: {!staticCounter}"/>
            <p></p>
            <apex:outputText value="viewstate counter: {!viewStateCounter}"/>
        </apex:outputPanel>
    </apex:form>
</apex:page>

Now, the page looks like this when initially displayed:

enter image description here

click the button once ...

enter image description here

click a few more times

enter image description here

Since the static variable isn't part of the view state, each button click instantiates a new controller instance (i.e. static variable is null, init'd to zero when 'getters' execute, then incremented to 1 on action method invocation).

It doesn't matter if the static variable is in the controller or in a related class.

The viewstate is how VF communicates state of the interactions between the browser and the server. Salesforce limits viewstate size to optimize that interaction between the two remote computers.

The transaction scope is the life between when the controller action starts and the controller action returns.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.