이 블로그 검색

2011년 10월 30일 일요일

이미지 한장으로 커스텀 프로그레시브 바 만들기

<intro.xml>  ======  intro.xml  -> 이 인트로 화면에 들어가는 프로그레시브 바의 배경이 이미지 단 한장짜리이다.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/intro_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/intro_bg"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="38.2dp" android:layout_alignParentBottom="true"> <TextView android:id="@+id/intro_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="6.5dp" android:textSize="13.5dp" android:textColor="#303030" android:textStyle="bold" android:text="@string/intro_greetings" android:gravity="center_horizontal" /> <TextView android:id="@+id/intro_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="13.5dp" android:textSize="12dp" android:textColor="@color/txt_100_9" android:text="@string/intro_text" android:gravity="center_horizontal" />
<ProgressBar android:id="@+id/intro_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminateDrawable="@drawable/progress_custom" android:layout_gravity="center_horizontal" android:visibility="invisible" /> 
 </LinearLayout>
</RelativeLayout>

==============================================================================


<progress_custom.xml>  ====== progress_custom.xml 파일이다. 
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/loading"    --> 1장 짜리 이미지 파일 
    android:pivotX="50%"
    android:pivotY="50%"
  />

==============================================================================

특정 이미지(뷰)만 셀렉터를 안 먹게 하는 방법

커스텀 리스트 뷰 같은 곳에서
list_detail_item.xml 의 background 속성에 셀렉터를 넣으면
전체가 전부 셀렉터가 먹는다.

이 때  list_detail_item 안의 특정 뷰에는 셀렉터를 안 먹게 할려면
그 이미지만 별도의 셀렉터를 설정해, 그 셀렉터를 setVisibility 에서 Gone 처리 하면 된다.

예컨데,
list_detail_item.xml 에 아래와 같이 여러개의 뷰가 있고, 전체 백그라운데 셀렉터를 넣은 상태에서 이중 View2 만 셀렉터를 안먹게 하려면

android:background="@drawable/list_item_selector"
<View 1>
<View 2>
<View 3>


View2 를 따로 imageView 로 떠서,
View2에 android:background="@drawable/list_item_View2_selector" 라는 셀렉터를 만든 후,
(이 셀렉터는 위의 list_detail_item 셀렉터와 동일하게 해 주면 된다.)
이 셀렉터를 Gone 처리해 주면, 셀렉터가 적용 되지 않는다.
왜냐하면 배경 셀렉터보다 직접 해당 뷰에 해주는 셀렉터가 위에 먹기(우선 순위가 높기) 때문이다. 따라서 해당 뷰에 직접 따로 셀렉터를 해 주면 그 배경이 되는 셀럭터 자체는 무시되는 듯 하다.

 

[토크게임엔진] onCollison

두 객체 A,B 의 충돌 처리 시

B::onCollision(){ .... A.XXX } 와 같이

B객체의 onCollison 메서드 내에서 A의 충돌 처리를 하면
충돌이 일어난 후 A.XXX 가 동작한다.

따라서 충돌이 일어나기 전 객체의 행동을 제어하려면

A::onCollison(){ ..... A.XXX} 와 같이 A객체 onCollision 메서드 내에서
처리를 해 줘야 한다.

[토크게임엔진] %this 로 받기

같은 객체에 이름을 중복해서 줘도 상관없지만,
보장할 수 없다.

각각의 객체의 값을 구현하려면 ,

onlevelloaded(%this){
%this.XXXX
} 와 같이 %this로 주고 받아야 한다.

2011년 10월 25일 화요일

WebView 컴포넌트 : WebActivity

아래의 웹액티비티로 Intent의 putExtra로 URL만 인자값으로 날려주면 됨.

Ex)

Intent intent = new Intent(DiscoverSearchActivity.this, WebActivity.class);
try {
// intent.putExtra("Discover_search", searchKey);
Util.log(">>>>>>>>>>>>>>>>>>>>>>>" + Define.audibleURL+searchKey);
intent.putExtra("url", Define.audibleURL+searchKey);
startActivity(intent);

**********************************************

<WebActivity.java>

package com.lge.readersworld.activity;

import com.lge.readersworld.R;
import com.lge.readersworld.util.Util;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.CookieSyncManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class WebActivity extends Activity {

public WebView webview;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
   setContentView(R.layout.web);

webview = (WebView) findViewById(R.id.webview);
webview.getSettings().setJavaScriptEnabled(true);

   String url = getIntent().getStringExtra("url");
   Util.log("WEBVIEW URL = "  + url);
    webview.loadUrl(url);
   
   webview.setWebViewClient(new WebViewClient(){
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url)  {
    view.loadUrl(url);
    return true;
    }
   
    @Override
    public void onPageFinished(WebView view, String url){
        CookieSyncManager.getInstance().sync();
        }
    });

   webview.setOnKeyListener(new View.OnKeyListener() {

@Override
public boolean onKey(View arg0, int arg1, KeyEvent arg2) {

return false;
}
});

     
     
}

@Override
public void onResume() {
        super.onResume();
     
}

@Override
public void onPause() {
        super.onPause();
     
        if (CookieSyncManager.getInstance() != null) {

        CookieSyncManager.getInstance().stopSync();

        }
}

@Override
public void onDestroy() {

super.onDestroy();
}

}

2011년 10월 23일 일요일

서버 연동 컴포넌트

package com.lge.readersworld.async;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

import com.lge.readersworld.util.Define;
import com.lge.readersworld.util.RWDeviceUtil;
import com.lge.readersworld.util.RWPreference;
import com.lge.readersworld.util.Util;

public class RWServerNetwork {

public static final int HTTP_TIMEOUT = 5000;

private String xmlValue = null;
private String fileLength = null;
private String fileName = null;

public static HashMap<String, String> getHeader(Context context) {

Display defaultDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = defaultDisplay.getWidth();
int height = defaultDisplay.getHeight();

HashMap<String, String> header = new HashMap<String, String>();
    header.put("x-lg-accept", "text/xml");
//     header.put("x-lg-language", "EN");
//     header.put("x-lg-country", "AU");
//     header.put("x-lg-model", "GW820");    
    // jh.lee : 선택한 국가에 맞춰서 Header를 보낸다.
    header.put("x-lg-language", RWPreference.getInstance(context).getData(Define.SHARED_LOGIN_LANGUAGECODE, "EN"));
    header.put("x-lg-country", RWPreference.getInstance(context).getData(Define.SHARED_LOGIN_COUNTRYCODE, "US"));
    header.put("x-lg-model", RWDeviceUtil.getModelInfo());
    //-------------------------------------------------------------------------------------------------------------------

    header.put("x-lg-agent", "LGRW;1.0.0.1;id");
    header.put("x-lg-platform", "AN"+Build.VERSION.RELEASE);

    if (RWDeviceUtil.isLandscape(context)) {
    header.put("x-lg-resolution", width + "X" + height);
    } else {
    header.put("x-lg-resolution", height + "X" + width);
    }

return header;
}

/**
* Carrier 코드를 출력한다.
*
* @param context
* @return
*/
public static String getCRCode(Context context) {
return "NET_2015";
}

/**
* XML에서 원하는 값을 추출한다. Level1만 지원함.
* @param str
* @return
*/
public String parser(String str) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream istream = new ByteArrayInputStream(xmlValue.getBytes("utf-8"));
Document doc = builder.parse(istream);

Element order = doc.getDocumentElement();
NodeList items = order.getElementsByTagName(str);
Node item = items.item(0);
if (item==null) return null;
Node text = item.getFirstChild();
String ItemName = text.getNodeValue();

return ItemName;

} catch (Exception e) {
Util.logError(e);
}
return null;
}

public Element getParser() {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream istream = new ByteArrayInputStream(xmlValue.getBytes("utf-8"));
Document doc = builder.parse(istream);

Element order = doc.getDocumentElement();
return order;

} catch (Exception e) {
Util.logError(e);
}
return null;
}

public static Element getParser(String filename) {
try {
String xmlValue = Util.getFileContent(filename);
if (xmlValue==null) return null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream istream = new ByteArrayInputStream(xmlValue.getBytes("utf-8"));
Document doc = builder.parse(istream);

Element order = doc.getDocumentElement();
return order;

} catch (Exception e) {
Util.logError(e);
}
return null;
}

@SuppressWarnings("unchecked")
public String getData(String url, Map<String, String> headers, Map<String, String> params, boolean isPostType) throws Exception {
return getData(url, headers, new Map[]{params}, isPostType);
}

public String getData(String url, Map<String, String> headers, Map<String, String>[] params, boolean isPostType) throws Exception {

StringBuilder sb = new StringBuilder();
InputStream is = null;
DefaultHttpClient httpclient = null;
BufferedReader reader = null;
try {
httpclient = new DefaultHttpClient();

HttpParams httpParams = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, HTTP_TIMEOUT);
HttpConnectionParams.setSoTimeout(httpParams, HTTP_TIMEOUT);

HttpResponse response = null;

if (params != null && isPostType) {
HttpPost httpPost = new HttpPost(url);
    ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();

    for (int i=0;i<params.length;i++) {
for (Map.Entry<String, String> entry: params[i].entrySet()) {
        nameValuePairs.add(new BasicNameValuePair(entry.getKey(), (String)entry.getValue()));
        Util.log("param :: "+ entry.getKey() +"="+entry.getValue());
}
    }
    UrlEncodedFormEntity entityRequest = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
    httpPost.setEntity(entityRequest);
    if (headers != null) {
       for (Map.Entry<String, String> entry2: headers.entrySet()) {
        httpPost.addHeader(entry2.getKey(), entry2.getValue());
        Util.log("header :: "+entry2.getKey()+"="+ entry2.getValue());
       }
}
    response = httpclient.execute(httpPost);
} else {
if (params != null) {
if (params[0].entrySet().size() > 0) url += "?";
for (Map.Entry<String, ?> entry : params[0].entrySet()) {
if (entry.getValue() instanceof String[]) {
String[] values = (String[]) entry.getValue();
for (int i = 0; i < values.length; i++) {
url += entry.getKey() + "=" + values[i] + "&";
}
} else {
url += entry.getKey() + "=" + entry.getValue() + "&";
}
}
}

       HttpGet httpget = new HttpGet(url);
       Util.log("network", "url = "+url);
if (headers != null) {
       for (Map.Entry<String, String> entry2: headers.entrySet()) {
        httpget.addHeader(entry2.getKey(), entry2.getValue());
       }
}
response = httpclient.execute(httpget);
}

is = response.getEntity().getContent();

reader = new BufferedReader(new InputStreamReader(is, "utf-8"), 8);

String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}

} catch (Exception e) {
Util.logError(e);
throw e;
} finally {
try {
if (is != null) is.close();
if (reader != null) reader.close();

} catch (Exception e) {throw e;}
}

xmlValue = sb.toString();
Log.d("debug", "url = " + url);
Log.d("debug", xmlValue);
return xmlValue;
}

public InputStream getDownload(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
InputStream is = null;
DefaultHttpClient httpclient = null;
try {

if (params != null) {
url +="?";
       for (Map.Entry<String, String> entry: params.entrySet()) {
           url += entry.getKey()+"="+URLEncoder.encode(entry.getValue())+"&";
       }
}
Util.log("network", "url = "+url);
HttpGet httppost = new HttpGet(url);

if (headers != null) {
       for (Map.Entry<String, String> entry: headers.entrySet()) {
        httppost.addHeader(entry.getKey(), entry.getValue());
       }
}
httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(httppost);
Header[] rheaders = response.getAllHeaders();
for (int i=0;i<rheaders.length;i++) {
if (rheaders[i].getName().toLowerCase().equals("result")) {
boolean tmp = "700".equals(rheaders[i].getValue());
if (tmp==false) throw new Exception("Server Error.");
}

if (rheaders[i].getName().toLowerCase().equals("content-length")) {
fileLength = rheaders[i].getValue();
}
if (rheaders[i].getName().toLowerCase().equals("content-disposition")) {
String tmp = rheaders[i].getValue();
fileName = tmp.substring(tmp.indexOf("filename=")+9);
}

Util.log("debug", "headers["+i+"] "+ rheaders[i].getName()+"="+rheaders[i].getValue());
}
is = response.getEntity().getContent();
return is;

} catch (Exception e) {
Util.logError(e);
throw e;
}
}

public int getFileLength() {
int size = 0;
try {
size = Integer.parseInt(fileLength);
}catch (Exception e) {}
return size;
}

public String getFileName() {
return fileName;
}

}

2011년 10월 19일 수요일

안드로이드 Text 속성에서 Ellipsize

글자가 뷰 사이즈를 넘칠 때 텍스트를 표시하는 방법을 정하는 속성

start : 처음 시작할 때 ....... 으로 시작
middle : 중간에  .......
end: 끝에 ....... 으로 끝
marque: 글자가 좌에서 우로 움직임.

안드로이드 비동기 처리 기법 - AsyncTask

1. 객체.execute() 메서드로 시작한다. 
2. doInBackGround 에서 서버 연동이나 다운로드 등의 작업을 한다. (Thread에서 run() 함수)
3. onPostExecute 에서 UI 업데이트 작업을 한다. (Handler의 handleMessage() 함수)

 new AsyncTask<String, Integer, String>() {

/* doInBackGround 에서 백데이터 작업(다운로드 등)을 한다. - 분리된 쓰레드에서 작업  
protected String doInBackground(String... arg0) {
RWServerNetwork network = new RWServerNetwork();
HashMap<String, String> params = new HashMap<String, String>();
params.put("recommend_count", "15");
params.put("best_count", "15");

try {
network.getData(Define.SERVER_URL_FEATUREDLIST,        RWServerNetwork.getHeader(FeaturedActivity.this), params, false);
if (network.parser("result")!=null && network.parser("result").equals("700")) {
Element e = network.getParser();
int cnt = Util.parseXmlDocument(e, "recommend").length;
recommendInfoList.clear();
for (int i=0;i<cnt;i++) {
recommendInfoList.add(new Book(e,"recommend", i));
}

cnt = Util.parseXmlDocument(e, "best").length;
bestInfoList.clear();
for (int i=0;i<cnt;i++) {
bestInfoList.add(new Book(e,"best", i));
}
return "";
}
}catch (Exception e) {
Util.logError(e);
}
return null;
}
*/ 분리된 쓰레드에서 작업

/* onPostExecute 에서 최종 UI갱신 작업 - UI (main)쓰레드에서 작업
protected void onPostExecute(String tempData) {
RWDialog.closeProgress(FeaturedActivity.this);
if (tempData == null) {
RWDialog.showDialog(FeaturedActivity.this, RWDialog.SERVER_CONNECT_ERROR);
}
refreshData();
}
}.execute();   <-- 시작

2011년 10월 18일 화요일

안드로이드 DB 컴포넌트

 아래의 형태의 DB 컴포넌트를 따로 만들어서, DB를 사용을 객체를 통해 이루어지게 한다.
이렇게 하면 DB 사용이 깔끔해 진다.

Ex)

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_bar);

dbAdapter = new DiscoverDbAdapter(getApplicationContext());
dbAdapter.open();
                ....................
                ..................
      }
    ............
    ............

     dbAdapter.insearchKeyword(dateFormat.format(calendar.getTime()), keyword);   
     ..................................


     ArrayList<String> lstHistory = dbAdapter.getHistory();
      ........................
      ........................
      dbAdapter.close();


}



public class DiscoverDbAdapter {
private static final String DATABASE_NAME = "discover_history.db";
private static final String TABLE_NAME = "search_history_discover";

private static final String HISTORY_DATE = "history_date";
private static final String HISTORY_SEARCH = "search_keyword";

private DatabaseHelper dbHelper;
private SQLiteDatabase db = null;
private Context context = null;

public DiscoverDbAdapter(Context context){
this.context = context;
}

/* open 메써드를 만들어서 dbHelper를 생성하고, 읽기&쓰기 속성을 준다.

public DiscoverDbAdapter open() throws SQLException{
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();

return this;
}

/* close 메써드를 만들어서 helper와 db 객체를 닫는다.

public void close(){
if(dbHelper != null) dbHelper.close();
if(db != null) db.close();
}

/* helper 클래쓰를 내부에 만든다.

private class DatabaseHelper extends SQLiteOpenHelper{

public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1); //version
}

/* 생성 함수 - Create Table
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(_id INTEGER PRIMARY KEY, " + HISTORY_DATE + " CHAR(14), " + HISTORY_SEARCH + " VARCHAR(30));");
}

/* Upgade 는 옵션
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

}

}

/* 각종 DB를 사용하는 여러 Function 들(inSearchKeyWord(), getHistory(), ... 등등)을 메서드로 Adapter 내부에 선언해서,
객체를 호출 한 뒤, 메서들 사용하는 방식으로 쓴다. */
public void insearchKeyword(String date, String keyword){
Cursor c = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);
if(c.getCount() > 9){
deleteHistory();
}
if(!keyword.trim().equals(""))
db.execSQL("INSERT INTO " + TABLE_NAME + "(" + HISTORY_DATE + ", " + HISTORY_SEARCH + ") values('" + date + "', '" + keyword + "');");
c.close();
}

private void deleteHistory(){
db.execSQL("DELETE FROM " + TABLE_NAME + " WHERE " + "_id" +"=(SELECT " + "_id" + " FROM " + TABLE_NAME + " ORDER BY " + HISTORY_DATE + " ASC LIMIT 1);");
}

public ArrayList<String> getHistory(){
ArrayList<String> lstHistory = new ArrayList<String>();

Cursor c = db.rawQuery("SELECT * FROM " + TABLE_NAME + " ORDER BY " + HISTORY_DATE + " DESC", null);
while(c.moveToNext()){
lstHistory.add(c.getString(c.getColumnIndex(HISTORY_SEARCH)));
}
c.close();
return lstHistory;
}
}

안드로이드 getTag(), setTag(object) 사용

커스텀 뷰를 만들 때,
커스텀 뷰에 객체의 Data를 집어 넣을 때 일일히 setXX, getXX 을 쓰지 않고,
setTag(dataObj), cView.getTag() 하면 된다.

Ex)
* setTag
mLayout.setTag(bookInfo);  // bookInfo 는 Book형의 인스턴스이고 mLayout은 커스텀 뷰이다.

// 예컨데 Book 형이 다음과 같다면,
class Book{
   String title;
   String author;
   String ISBN;
   int version;
}

mLayout에 title, author, ISBN, version 등의 값을 bookInfo에 넘겨서 한번에 넘겨 줄 수 있다.

* getTag
Book bookInfo = (Book)mLayout.getTag();

요렇게 하면 mLayout에 set 되어 있던 book 형 값들을 가져올 수 있다.

update, delete 구문

일일히 루프 돌면서 작업 안해줘도 where 조건 없으면 모든 Table의 item에 적용 됨.
이런 간단한 것도 모르면, 엄청 해멘다..

Ex)
  db.execSQL("update WishList set deleteCheck = 'false' ");

모든 WishList Table의 deleteCheck 필드의 값을 전부 false 로 바꾼다.
일일히 커서로 돌리면서 바꿀 필요 없다.

쓰레드 사용 - ANR 방지

기본적인 쓰레드 사용
1. new Thread(new Runnable()).

2. run() 안쪽에 멀티 쓰레드로 처리할(메인 쓰레드에서 뺄 작업) 로직 삽입.
3. Handler 객체에 sendEmptyMessage()로 전달
4. 핸들러 객체 따로 구현, handleMessage() 내에 UI 작업 삽입.


<싱글 쓰레드의 경우>
----> 싱글 쓰레드(main 쓰레드) ---> 입력 UI --> [Data 처리 - Ex)서버 연동, DB 연동 etc ] --> 화면 출력 이 과정에서 ANR 발생 (UI무응답)


<멀티 쓰레드를 이용하는 경우>
----> 싱글 쓰레드(main 쓰레드) ---> 입력 UI --> --> 화면 출력
멀티 쓰레드 ---> [Data 처리 - Ex)서버 연동, DB 연동 etc ]


public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     
        setContentView(R.layout.act_setup_friendrecommend);

        dialog1 = DialogUtils.createProgressDialog(this, "gringphone06_01");

new Thread(new Runnable(){
public void run(){
init();   <-- Data 처리 등 시간이 많이 걸리는 부분
mHandler.sendEmptyMessage(0);
}
}).start();
    }


Handler mHandler = new Handler()
{
public void handleMessage(Message msg)
{
switch(msg.what)
{
case 0:
btnRecommend.setText(StringUtils.getString(Act_Setup_FriendRecommend.this, "recommend"));
lvSelectList.setAdapter(selectPersonListAdapter);    <-- UI 처리 부분

break;
}
}
};

2011년 10월 11일 화요일

딜레이 주기

Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
        public void run()
        {
        Util.log("delay"); 
        }
       }, 500); //Delay time

2011년 10월 10일 월요일

프로그래밍 문제 해결 팁 1

거의 비슷한 뷰를 복사해서 쓴 적이 있는데
플리킹이 한 쪽은 되고 한 쪽은 되지 않은 적이 있었다.

이 문제를 해결하느라 엄청 삽질을 했느데,
결국 해결의 실마리는 로그캣에 많은 로그를 남기는 것이었다.
전혀 상관없어 보이는 코드에도 로그를 쓰고 비교를 해보니...
문제가 생긴 쪽에는 플리킹을 할 때마다
getView 호출하는 코드를 더 추가적으로 넣은 것을 알았다.
따라서 플리킹을 할 때마다 계속해서 getView를 호출하다 보니 이미지들이 움직일 수가
없는 것이었다.

로그가 없었으면 이 문제를 발견할 수 없었을 듯 하다.
정 안될 때는 상관없어 보이는 코드에도 밑져야 본전이니 로그를 남겨둬 보자..
자신이 전혀 짐작하지 못한 의외에 곳에서 한 실수를 찾을 수 있다.

2011년 10월 9일 일요일

안드로이드 리스트 복사

각종 리스트(ArrayList 등 포함)를 통째로 똑같이 복사하려면
addAll 메써드를 써야 한다.

예를들어,
ArrayList<String>sList = new ArrayList<String>();
sList.add("a");
sList.add("b");
sList.add("c");
sList.add("d");
 
ArrayList<String>tList = new ArrayList<String>();

tList = sList; (X) <-- 이런식으로 하면 안된다.. 왜냐면 tList가 변함에 따라 sList도 변한다.

tList.addAll(sList); (O)  <--- 이렇게 해야 한다. 

tList.add("e");  <-- 이럼에 따라, sList에도 "e","f" 가 추가된다.
tList.add("f");          왜냐면 tList = sList 하면 두 리스트의 주소값을 공유하게 되기 때문이다.