계속 업데이트중입니다.


플랫폼 버전API 레벨버전 코드참고
Android 10.029Q플랫폼 하이라이트
Android 928P플랫폼 하이라이트
Android 8.127O_MR1플랫폼 하이라이트
Android 8.026O플랫폼 하이라이트
Android 7.1.1
Android 7.1
25N_MR1플랫폼 하이라이트
Android 7.024N플랫폼 하이라이트
Android 6.023M플랫폼 하이라이트
Android 5.122LOLLIPOP_MR1플랫폼 하이라이트
Android 5.021LOLLIPOP
Android 4.4W20KITKAT_WATCH웨어러블 기기 전용 KitKat
Android 4.419KITKAT플랫폼 하이라이트
Android 4.318JELLY_BEAN_MR2플랫폼 하이라이트
Android 4.2, 4.2.217JELLY_BEAN_MR1플랫폼 하이라이트
Android 4.1, 4.1.116JELLY_BEAN플랫폼 하이라이트
Android 4.0.3, 4.0.415ICE_CREAM_SANDWICH_MR1플랫폼 하이라이트
Android 4.0, 4.0.1, 4.0.214ICE_CREAM_SANDWICH
Android 3.213HONEYCOMB_MR2
Android 3.1.x12HONEYCOMB_MR1플랫폼 하이라이트
Android 3.0.x11HONEYCOMB플랫폼 하이라이트
Android 2.3.4
Android 2.3.3
10GINGERBREAD_MR1플랫폼 하이라이트
Android 2.3.2
Android 2.3.1
Android 2.3
9GINGERBREAD
Android 2.2.x8FROYO플랫폼 하이라이트
Android 2.1.x7ECLAIR_MR1플랫폼 하이라이트
Android 2.0.16ECLAIR_0_1
Android 2.05ECLAIR
Android 1.64DONUT플랫폼 하이라이트
Android 1.53CUPCAKE플랫폼 하이라이트
Android 1.12BASE_1_1
Android 1.01BASE



출처 : http://developer.android.com/intl/ko/guide/topics/manifest/uses-sdk-element.html








php에서 array_search()는 단일 array에서만 사용이 가능하고 다중 array의 경우에 false를 반환한다.


다음과 같이 foreach를 이용하여 다중 array에서도 사용가능하다.



1
2
3
4
5
6
7
8
9
10
11
12
<?php    
    function searchForId($id$array) {
        foreach ($array as $key => $val) {
            if ($val['uid'=== $id) {
                return $key;
            }
        }
        return null;
    }
 
?>
 
cs




php 5.5이상에서는 다음과 같이 쓰면 된다.


1
2
3
4
<?php    
    $key = array_search('100', array_column($userdb'uid'));
?>
 
cs





HttpURLConnection을 사용하여 Multipart Upload를 수행하고 그 과정을 ProgressBar로 보여주기를 하는 코드이다.


다음 순서대로 작성하고 적용하면 끝.





1. 인터페이스 생성



1
2
3
4
public interface ProgressListener { 
   void onProgressUpdate(int progress);
}
 
cs




2. MultipartUpload 클래스



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
 
public class MultipartUpload {
 
    private final String boundary;
    private final String tail;
    private static final String LINE_END = "\r\n";
    private static final String TWOHYPEN = "--";
    private HttpURLConnection httpConn;
    private String charset;
    private PrintWriter writer;
    private OutputStream outputStream;
    private static final String TAG = "MultipartUtility";
    int maxBufferSize = 1024;
    private ProgressListener progressListener;
    private long startTime;
 
    public MultipartUpload(String requestURL, String charset) throws IOException {
        this.charset = charset;
 
        boundary = "===" + System.currentTimeMillis() + "===";
        tail = LINE_END + TWOHYPEN + boundary + TWOHYPEN + LINE_END;
        URL url = new URL(requestURL);
        httpConn = (HttpURLConnection) url.openConnection();        
        httpConn.setDoOutput(true); 
        httpConn.setDoInput(true);
        httpConn.setRequestProperty("Content-Type""multipart/form-data; boundary=" + boundary);
    }
 
    public void setProgressListener(ProgressListener progressListener) {
        this.progressListener = progressListener;
    }
 
    public JSONObject upload(HashMap<StringString> params, HashMap<StringString> files) throws IOException {
        String paramsPart = "";
        String fileHeader = "";
        String filePart = "";
        long fileLength = 0;
        startTime = System.currentTimeMillis();
 
        ArrayList<String> paramHeaders = new ArrayList<>();
        for (Map.Entry<StringString> entry : params.entrySet()) {
 
            String param = TWOHYPEN + boundary + LINE_END
                    + "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINE_END
                    + "Content-Type: text/plain; charset=" + charset + LINE_END
                    + LINE_END
                    + entry.getValue() + LINE_END;
            paramsPart += param;
            paramHeaders.add(param);
        }
 
        ArrayList<File> filesAL = new ArrayList<>();
        ArrayList<String> fileHeaders = new ArrayList<>();
 
        for (Map.Entry<StringString> entry : files.entrySet()) {
            
            File file = new File(entry.getValue());
            fileHeader = TWOHYPEN + boundary + LINE_END
                    + "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + file.getName() + "\"" + LINE_END
                    + "Content-Type: " + URLConnection.guessContentTypeFromName(file.getAbsolutePath()) + LINE_END
                    + "Content-Transfer-Encoding: binary" + LINE_END
                    + LINE_END;
            fileLength += file.length() + LINE_END.getBytes(charset).length;
            filePart += fileHeader;
 
            fileHeaders.add(fileHeader);
            filesAL.add(file);
        }
        String partData = paramsPart + filePart;
 
        long requestLength = partData.getBytes(charset).length + fileLength + tail.getBytes(charset).length;
        httpConn.setRequestProperty("Content-length""" + requestLength);
        httpConn.setFixedLengthStreamingMode((int) requestLength);
        httpConn.connect();
 
        outputStream = new BufferedOutputStream(httpConn.getOutputStream());
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset), true);
 
        for (int i = 0; i < paramHeaders.size(); i++) {
            writer.append(paramHeaders.get(i));
            writer.flush();
        }
 
        int totalRead = 0;
        int bytesRead;
        byte buf[] = new byte[maxBufferSize];
        for (int i = 0; i < filesAL.size(); i++) {
            writer.append(fileHeaders.get(i));
            writer.flush();
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filesAL.get(i)));
            while ((bytesRead = bufferedInputStream.read(buf)) != -1) {
 
                outputStream.write(buf, 0, bytesRead);
                writer.flush();
                totalRead += bytesRead;
                if (progressListener != null) {
                    float progress = (totalRead / (float) requestLength) * 100;
                    progressListener.onProgressUpdate((int) progress);
                }
            }
            outputStream.write(LINE_END.getBytes());
            outputStream.flush();
            bufferedInputStream.close();
        }
        writer.append(tail);
        writer.flush();
        writer.close();
 
        JSONObject jObj = null;
        StringBuilder sb = new StringBuilder();
        // checks server's status code first
        int status = httpConn.getResponseCode();
        if (status == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), "UTF-8"), 8);
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            reader.close();
            httpConn.disconnect();            
        } else {
            throw new IOException("Server returned non-OK status: " + status + " " + httpConn.getResponseMessage());
        }
        try {
            jObj = new JSONObject(sb.toString());
        } catch (JSONException | NullPointerException e) {
            e.printStackTrace();
        }
        return jObj;
 
    }
 
}
cs





3. 사용법



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class UploadAsync extends AsyncTask<Object, Integer, JSONObject> implements ProgressListener {
 
    private ProgressDialog progressDialog;
    private Context mContext;    
    private HashMap<StringString> param;
    private HashMap<StringString> files;
 
    public UploadAsync(Context context, HashMap<StringString> param, HashMap<StringString> files) {
        mContext = context;
        this.param = param;
        this.files = files;
    }
 
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        startTime = System.currentTimeMillis();
        progressDialog = new ProgressDialog(mContext);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setMessage(mContext.getString(R.string.wait));
        progressDialog.setMax(100);
        progressDialog.setCancelable(false);
        progressDialog.show();
    }
 
    @Override
    protected JSONObject doInBackground(Object... params) {
        JSONObject json = null;
        try {
        
            String url = "http://요청할 URL";
            MultipartUpload multipartUpload = new MultipartUpload(url, "UTF-8");
            multipartUpload.setProgressListener(this);
            json = multipartUpload.upload(param, files);            
 
        } catch (IOException e) {
            e.printStackTrace();
        }
        return json;
 
    }
 
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        if (progressDialog != null && progressDialog.isShowing()) {
            if (values[1== 1) {
                progressDialog.setProgress(values[0]);
            } else {
                progressDialog.setProgress(values[0]);
            }
        }
    }
 
    @Override
    protected void onPostExecute(JSONObject result) {
        super.onPostExecute(result);
        if (progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
 
        if (result != null) {
            try {
                if (result.getInt("success"== 1) {                            
                    Toast.makeText(mContext, R.string.success, Toast.LENGTH_SHORT).show();
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        } else {
            Toast.makeText(mContext, R.string.conntection_error, Toast.LENGTH_SHORT).show();
        }
    }
 
    @Override
    public void onProgressUpdate(int progress) {
        publishProgress(progress, 0);
    }
}
 
cs


  네트워크 작업이므로 반드시 스레드 안에서 실행해야 한다.


  생성자로 접속할 url과 캐릭터셋을 넣고,  프로그레스를 받을 인터페이스 리스너를 등록 한 후 파라미터 파트와 파일 파트를 HashMap으로 구성하여 인자로 넘겨준다. 


  한가지 문제점은 실제로 접속하여 파일을 전송하는 과정이 progress되지 않는다는 점이다. MultipartUpload 클래스에 보면 outputstream에 쓰는 과정을 progress로 보여주는데 사실 이것이 파일이 전송됨을 의미하지는 않는다는 점이다. 단지 버퍼에서 읽는 부분일뿐.. 실제 예제를 만들어 progress가 100%가 후에 전송을 시작하여 마치 앱이 멈춘것 처럼 동작한다. 파일 크기가 작으면 전송이 빨리되어 약간의 딜레이가 생기겠지만 파일이 큰 경우 오류난것 처럼 보인다. 


  버퍼에 쓴다음 바로 flush를 해줘도 똑같다. setFixedLenghStreamingMode를 해주면 된다고는 하는데 안된다! 이거 실제 전송되는 부분 아시는분은 알려주시면 감사하겠습니다. 


용량 확인


1. df : 디스크의 남은 용량을 확인 

df -k : KB단위

df -m : MB단위

df -h : 크기에 맞춰 알아서 바꿔줌

df . : 현재 디렉토리가 포함된 파티션의 남은 용량


[root@kserver112-222 ~]# df -h

Filesystem            Size  Used Avail Use% Mounted on

/dev/sda3             222G   45G  166G  22% /

/dev/sdb1             226G   11G  204G   5% /data

/dev/sda1              99M   23M   72M  24% /boot

tmpfs                1008M     0 1008M   0% /dev/shm


[root@kserver112-222 ~]# df . -h

Filesystem            Size  Used Avail Use% Mounted on

/dev/sda3             222G   45G  166G  22% /

-> 단위조합이 가능하다.





2. du : 현재 디렉토리에서 서브디렉토리까지의 사용량을 확인 

du -a : 현재 디렉토리 파일의 크기를 확인

du -s : 현재 디렉토리 전체 크기

du -h : 크기에 맞춰 알아서 바꿔줌 

du -sh * : 하위 디렉토리를 제외하고 파일만 보여줌 


[root@kserver112-222 ~]# du -h

140K    ./paco-2.0.7/doc

72K     ./paco-2.0.7/lib/paco/.deps

1.1M    ./paco-2.0.7/lib/paco

12K     ./paco-2.0.7/lib/paco-log/.deps

96K     ./paco-2.0.7/lib/paco-log/.libs

200K    ./paco-2.0.7/lib/paco-log

1.3M    ./paco-2.0.7/lib

72K     ./paco-2.0.7/gpaco/.deps

348K    ./paco-2.0.7/gpaco

220K    ./paco-2.0.7/paco/.deps

4.0K    ./paco-2.0.7/paco/.libs

3.0M    ./paco-2.0.7/paco

72K     ./paco-2.0.7/scripts

672K    ./paco-2.0.7/build

6.6M    ./paco-2.0.7

8.0K    ./vnstat-1.13/examples/upstart

8.0K    ./vnstat-1.13/examples/systemd

8.0K    ./vnstat-1.13/examples/launchd

8.0K    ./vnstat-1.13/examples/init.d/debian

8.0K    ./vnstat-1.13/examples/init.d/redhat

20K     ./vnstat-1.13/examples/init.d

64K     ./vnstat-1.13/examples

744K    ./vnstat-1.13/src

8.0K    ./vnstat-1.13/cfg

48K     ./vnstat-1.13/man

136K    ./vnstat-1.13/tests

1.1M    ./vnstat-1.13

9.1M    .







안드로이드 RecyclerView에서 drag&drop과 swipe-to-dismiss를 구현한 예제는 많지만 View.OnDragListener를 이용한 경우가 많다. 이것은 예전 버전을 사용한 경우이고

새로운 API를 사용하거나 GestureDetector나 onIterceptTouchEvent를 이용하여 복잡아게 구현한 경우가 많다. 이번 포스트 에서는 Android Support Library를 이용하여

간단히 drag&drop과 swipe-to-dismiss를 구현한 방법을 알아보고자 한다.





ItemTouchHelper

ItemTouchHelper는 drag&drop과 swipe-to-dismiss를 구현하기에 매우 적합한 class이다. RecyclerView.ItemDecoration의 subclass이기 때문에 대부분의 LaoutManager와 Adapter에서 

쉽게 사용이 가능하다.


RecyclerView를 사용하려면 다음과 같이 build.gradle에 dependency를 추가해야 한다.


compile 'com.android.support:recyclerview-v7:22.2.0'





ItemTouchHelper와 ItemTouchHelper.Callback 사용


ItemTouchHelper를 사용하기 위해서는 ItemTouchHelper.Callback을 생성해야 한다.

이것은 "move"와 "swipe" 이벤트를 받을 수 있는 interface이다. 또한 기본 animation과 view의 선택된 상태를 제어할 수 있다.

기본적인 API로 이미 구현이 되어있지만 학습하는 과정이므로 새로운 SimpleCallback class를 만들어 보도록 한다.


callback class는 반드시 다음 3가지 메소드를 override해야 한다.


getMovementFlags(RecyclerView, ViewHolder)

onMove(RecyclerView, ViewHolder, ViewHolder)

onSwiped(ViewHolder, int)


다음 2가지도 사용한다.


isLongPressDragEnabled()

isItemViewSwipeEnabled()



이제 각각 메소드에 대해 하나씩 살펴보자.


1
2
3
4
5
6
7
@Override
public int getMovementFlags(RecyclerView recyclerView, 
        RecyclerView.ViewHolder viewHolder) {
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
    return makeMovementFlags(dragFlags, swipeFlags);
}
cs


ItemTouchHelper는 이벤트의 방향(direction)을 쉽게 찾을 수 있게 한다. 어떠한 방향으로 drag 혹은 swipe 되었는지 알려면 getMovementFlags() 를 반드시 override 해야 한다.

return 값으로 ItemTouchHelper.makeMovementFlags(int, int)를 사용하여 dragging 과 swiping를 양쪽 방향으로 사용할 수 있다.




1
2
3
4
5
6
public interface ItemTouchHelperAdapter {
 
    void onItemMove(int fromPosition, int toPosition);
 
    void onItemDismiss(int position);
}
cs


onMove() 와 onSwiped()는 데이터 변화에 따라 호출된다. 이러한 interface를 구성하여 각각 class를 연결시킨다.




1
2
3
4
@Override
public boolean isLongPressDragEnabled() {
    return true;
}
cs

ItemTouchHelper drag 없이 swipe 용도로만 사용가능하다(반대도 가능). RecyclerView item 에서 long press를 통해 drag 시점을 알기 위해서는 isLongPressDragEnabled()에서 true를 return 해야만 한다.

대신에 ItemTouchHelper.startDrag(RecyclerView.ViewHolder)를 사용할 수도 있지만 추후에 다루도록 한다.



1
2
3
4
@Override
public boolean isItemViewSwipeEnabled() {
    return true;
}
cs

View 안에서 touch 이벤트로 부터 swiping을 입력받게 하려면 isItemViewSwipeEnabled()에서 위와 마찬가지로 true를 반환해야 한다.

ItemTouchHelper.startSwipe(RecyclerView.ViewHolder)로 drag 이벤드를 시작할 수 있다.




위의 interface를 adapter에 적용시키면 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class RecyclerListAdapter extends 
        RecyclerView.Adapter<ItemViewHolder> 
        implements ItemTouchHelperAdapter {
...
 
@Override
public void onItemDismiss(int position) {
    mItems.remove(position);
    notifyItemRemoved(position);
}
 
@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(mItems, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(mItems, i, i - 1);
        }
    }
    notifyItemMoved(fromPosition, toPosition);
    return true;
}
cs


adapter 안에서 데이터의 변화는 notifyItemRemoved()와 notifyItemMoved()를 통하여 알 수 있다. 한가지 중요한 것은  데이터의 변화는 drag를 시작하고 drop 될 때 변화 하는것이 아니라 item이 움직일 때 마다 변화한다는 것이다.

그러므로 item이 움직일때 마다 adapter안에서 데이터의 변화가 일어나게 된다는 것을 명심하고 있어야 한다. 



다음으로 SimpleItemTouchHelperCallback에 onMove()와 onSwiped()를 orverride 해 줘야 한다. 생성자에 다음과 같이 adapter field를 추가한다.


1
2
3
4
5
6
private final ItemTouchHelperAdapter mAdapter;
 
public SimpleItemTouchHelperCallback(
        ItemTouchHelperAdapter adapter) {
    mAdapter = adapter;
}
cs



다음으로 onMove()와 onSwiped()를 추가한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public boolean onMove(RecyclerView recyclerView, 
        RecyclerView.ViewHolder viewHolder, 
        RecyclerView.ViewHolder target) {
    mAdapter.onItemMove(viewHolder.getAdapterPosition(), 
            target.getAdapterPosition());
    return true;
}
 
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, 
        int direction) {
    mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
}
cs



Callback class의 최종 코드는 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
 
    private final ItemTouchHelperAdapter mAdapter;
 
    public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        mAdapter = adapter;
    }
    
    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }
 
    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }
 
    @Override
    public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }
 
    @Override
    public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, 
            ViewHolder target) {
        mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }
 
    @Override
    public void onSwiped(ViewHolder viewHolder, int direction) {
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }
 
}
cs



이렇게 생성된 class들은 Activity나 Fragment에서 다음과 같이 사용한다. 


1
2
3
ItemTouchHelper.Callback callback =  new SimpleItemTouchHelperCallback(adapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(recyclerView);
cs










php에서는 Java에서 처럼 startWith 이나 endWith 기능을 하는 함수가 없으므로 만들어서 써야한다. 다음과 같이 간단히 쓸 수 있다.



1. 함수



1
2
3
4
5
6
7
function startsWith($haystack, $needle){
    return strncmp($haystack, $needle, strlen($needle)) === 0;
}
 
function endsWith($haystack, $needle){
    return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
cs



2. 결과


startsWith("abcdef", "ab") -> true

startsWith("abcdef", "cd") -> false

startsWith("abcdef", "ef") -> false

startsWith("abcdef", "") -> true

startsWith("", "abcdef") -> false


endsWith("abcdef", "ab") -> false

endsWith("abcdef", "cd") -> false

endsWith("abcdef", "ef") -> true

endsWith("abcdef", "") -> true 

endsWith("", "abcdef") -> false







1. 언제쓰이나?


· Service : UI없이 실행될 수 있지만 매우 길지 않아야 한다. 만약 오래걸리는 작업을 Service에서 실행하고자 한다면 Service 안에서 스레드를 사용해야 한다.


· IntentService : 오래걸리지만 메인스레드와 관련이 없는 작업을할 때 주로 이용한다. 만약 메인 스레드와 관련된 작업을 해야 한다면 메인스레드 Handler나 Boradcast intent를 이용해야 한다.




2. 어떻게 실행시키나?


· Service : startService() 메소드에 의해 실행된다.


· IntentService : Intent사용에 의해 실행된다. 새로운 스레드가 생성되며 onHandleIntent()가 불린다.





3. 불리는 위치


· ServiceIntentService 모두 아무 스레드에서 생성되고 , 액티비티 뿐만 아니라 다른곳에서도 실행가능하다.





4. 실행중인 위치


· Service : 백드라운드에서 동작하지만 메인스레드에 포함된다.


· IntentService : 새로운 스레드에서 동작한다.





5. 어떻게 멈추나


· Service : 순전히 사용자의 몫이다. stopSelf()나 stopService()에 의해 동작이 멈춘다. Service Binding의 경우 필요없음.


· IntentService : onHandleIntent() 내의 모든 동작이 수행되면 멈춘다. 멈추기 위한 다른 메소드 호출이 불필요한다.





6. 단점?


· Service : 메인스레드에 포함되므로 무거운 작업일때 메인스레드에 영향을주어 느려지거나 할 수 있다.


· IntentService : 병렬적으로 수행될 수 없으므로 연속적인 Intent 호출에 관해서 순차적으로 처리된다.





 





리눅스에서 crontab은 시간마다 일정한 스크립트를 수행하기 위해 사용되고,


/etc/rec.d/init.d/crond 데몬에의해 관리된다.




1. crontab list 홧인


crontab -l



2. crontab 편집


crontab -e



3. 실행, 중지, 재시작


service crond start(stop|restart)



4. 등록 내용 설정


crontab -e를 통해서 들어온 편집기에 다음과 같은 형태로 저장한다.


# +---------------- 분 (0 - 59)

# |  +------------- 시 (0 - 23)

# |  |  +---------- 일 (1 - 31)

# |  |  |  +------- 월 (1 - 12)

# |  |  |  |  +---- 요일 (0 - 6) (일요일=0 or 7)

# |  |  |  |  |

  *  *  *  *  *  실행될 명령


의 형태로 작성한다.



5. 등록 내용 설정 심화



* * * * * => 매분마다 실행

  

5-59/20 * * * *  => 5분에서 59분 사이 20분간격 실행 -> 5분, 25분, 45분


1-59/2 * * * *  => 매 홀수분마다 실행


5 */2 * * *  => 매일 2시간간격으로 5분에


초단위로 실행은 불가함.



6. crontab 사용 권한


=> /etc/cron.allow : 허용할 사용자 ID 목록
=> /etc/cron.deny  : 거부할 사용자 ID 목록

cron.allow 파일이 있으면 이 파일에 들어있는 ID만 사용 가능
cron.deny  파일이 있으면 이 파일에 들어있는 ID는 사용 불가



7. 기타


 > /dev/null  2>&1 이란?


예를들어


ls > /dev/null 2>&1 와 같을때 


>는 리다이렉션 기호이다. ls > /dev/null 은 결과값에 대한 표준 출력을 /dev/null로 넣으라는 뜻이고 


2>&1 에서 2> 라는 말은 표준 에러를 리다이렉션 한다는 뜻임. &1 은 /dev/null 을 가리키는 표시이다.


위와 같이 안하고 ls > /dev/null 만 하게 되면 에러가 없는 결과값이 /dev/null 로 출력되어 화면에는 아무런 표시가 되지 않지만, 에러가 발생했을때에는 화면에 표시된다.


뒤에 2>&1 은 에러출력도 &1 (/dev/null )로 출력하라는 뜻으로 결과적으로 명령어에 대한 실행결과에 상관없이 아무것도 표시안하게 된다(성공이든 에러든).





+ Recent posts