Every time we do visit a round which means the most outside elements in four steps.

- visit first row from firstCol to finalCol;
- visit final col from the firstRow + 1 to finalRow - 1
- If the first col is not equals to visited final col, then visit final row from finalCol to firstCol
- If the first row is not equals to visited first row, then visit first col from finalRow - 1 to firstRow + 1

Then go into next round from matrix[firstRow + 1][firstCol + 1].

Anyway, for the above four steps, you must get rid of visiting the visited elements.

Code is below:

```
public class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> result = new ArrayList<>();
if (matrix == null || matrix.length == 0) return result;
travel(matrix, 0, 0, 0, result);
return result;
}
private void travel(int[][] matrix, int startRow, int startCol, int level, List<Integer> result) {
int endRow = startRow + matrix.length - 2 * level,
endCol = startCol + matrix[0].length - 2 * level;
if (endRow <= startRow || endCol <= startCol) return;
for (int i = startCol; i < endCol; i ++) {
result.add(matrix[startRow][i]);
}
for (int i = startRow + 1; i < endRow - 1; i ++) {
result.add(matrix[i][endCol - 1]);
}
if (endRow - 1 > startRow)
for (int i = endCol - 1; i >= startCol; i --) {
result.add(matrix[endRow - 1][i]);
}
if (startCol < endCol - 1)
for (int i = endRow - 2; i > startRow; i --) {
result.add(matrix[i][startCol]);
}
travel(matrix, startRow + 1, startCol + 1, level + 1, result);
}
}
```