액티비티간 데이터를 넘길 때 intent.putExtra, getExtra를 이용해서 넘기는데

난 문자열이나 정수, 실수형 데이터만 넘겨지는 줄 알았다.


문득 객체도 전달 가능한지 궁금하여 검색하니 

역시나 객체도 전달 할 수 있었다.


Parcelable 인터페이스를 구현하는 객체를 만들어 전달하면 된다고 해서 따라해봤다.


////////////////////////////////////////////////////////////


먼저 Parcelable 인터페이스를 상속받아 넘길 객체의 클래스를 만든다


import android.os.Parcel;

import android.os.Parcelable;


public class SaleItem implements Parcelable{


    private String RNUM;

    private int PLNM_NO;


    public SaleItem() {


    }


    private SaleItem(Parcel in) {

        this.RNUM = in.readString();

        this.PLNM_NO = in.readString();

    }


    public static final Parcelable.Creator<SaleItem> CREATOR = new Parcelable.Creator<SaleItem>() {

        public SaleItem createFromParcel(Parcel in) {

            return new SaleItem(in);

        }

        public SaleItem[] newArray (int size) {

            return new SaleItem[size];

        }

    };


    @Override

    public int describeContents() {

        return 0;

    }


    @Override

    public void writeToParcel(Parcel dest, int flags) {

  //생성자에서 읽어오는 순서와 기록하는 순서가 같아야 한다고 한다!!!!!

        dest.writeString(this.RNUM);

        dest.writeInt(this.PLNM_NO);

    }

}


//////////////////////////////////////////////////////////


객체 넘길 때


Intent it = new Intent(context, SaleDetailActivity.class);
it.putExtra("sale_item", item);

context.startActivity(it);


//////////////////////////////////////////////////////////


객체 받을 때


SaleItem saleItem = (SaleItem) getIntent().getParcelableExtra("sale_item");


recyclerview 를 사용하던중 스크롤을 하는데 뭔가 스무스 하지 않는 현상이 일어났다.


스크롤을 내리는데 뭔가 답답하고 천천히 내려가는 느낌? 이다


///////////////////////////////////////////////////////


rvSaleList.setNestedScrollingEnabled(false);


setNestedScrollingEnabled(false); 를 리사이클뷰에 설정해주면 된다

에디트 텍스트를 클릭하면 키보드가 올라오는데

입력을 마치고 뒤로가기로 키보드를 내리지 않고 다른 버튼을 눌렀을 떄

키보드를 내리게 하고 싶다면


/////////////////////////////////////////////


private InputMethodManager imm;

imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);


이런식으로 InputMethodManager 를 선언한 후


키보드를 내리고 싶을 떄


imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);


요렇게 사용해주면 키보드가 내려간다..

fab이 구성되어있는 화면인데 editText를 누르면 보통 키보드가 올라온다.


그런데 문제는 키보드가 올라오면서 밑에있던 fab이 키보드 위로 올라와버린다

(키보드가 올라오면서 화면을 밀어올리는 듯한 현상)



요렇게... 밑에있던 fab이 키보드위로 올라와버림


//////////////////////////////////////////////////////////////////////////


해결방법을 찾던중 


AndroidManifest.xml 파일에서

해당 Activity에 android:windowSoftInputMode="adjustNothing" 을 추가해주면 된다고 하여 해보니 성공하였다!


<activity
android:name=".main.MainActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustNothing">
</activity>

요렇게 추가해주면 된다.


결과



공공데이터 API를 http request로 호출하였는데 반환형식이 xml 이었다.

내가 이니 만든 request 공통 모듈은 반환형식을 string 으로 받고 있었기 때문에

xml 이 그냥 쭉 스트링으로 저장되어 반환되었다.


string 으로 된 xml 을 파싱하려고하니 불편할것 같아서

string 을 xml에 다시 담은 뒤 xml을 파싱하려고 한다.


////////////////////////////////////////////////


//string -> xml


  //string을 xml로 바꾸어 넣을 곳

  XmlPullParser parser = Xml.newPullParser();


try {

 // http request 후 xml을 스트링값으로 받는 부분

            data = new JOAsyncTask().execute().get();


//스트링을  다시 xml로 

            parser.setInput(new StringReader(data));


        } catch (InterruptedException e) {

            e.printStackTrace();

        } catch (ExecutionException e) {

            e.printStackTrace();

        } catch (XmlPullParserException e){

            e.printStackTrace();

        }


return parser;



///////////////////////////////////////////////////

//xml 의 형태


<?xml version="1.0" encoding="UTF-8"?>


<response>



<header>


<resultCode>00</resultCode>


<resultMsg>NORMAL SERVICE.</resultMsg>


</header>



<body>



<items>


<item>


<RNUM>1</RNUM>


<CTGR_ID>10000</CTGR_ID>


<CTGR_NM>부동산</CTGR_NM>


<CTGR_HIRK_ID>1</CTGR_HIRK_ID>


<CTGR_HIRK_NM>ONBID</CTGR_HIRK_NM>


</item>



<item>


<RNUM>2</RNUM>


<CTGR_ID>11000</CTGR_ID>


<CTGR_NM>권리/증권</CTGR_NM>


<CTGR_HIRK_ID>1</CTGR_HIRK_ID>


<CTGR_HIRK_NM>ONBID</CTGR_HIRK_NM>


</item>



<item>


<RNUM>3</RNUM>


<CTGR_ID>12000</CTGR_ID>


<CTGR_NM>자동차/운송장비</CTGR_NM>


<CTGR_HIRK_ID>1</CTGR_HIRK_ID>


<CTGR_HIRK_NM>ONBID</CTGR_HIRK_NM>


</item>



</items>



<pageNo>1</pageNo>



<totalCount>22</totalCount>



<numOfRows>999</numOfRows>


</body>


</response>





//////////////////////////////////////////////////


//xml 파싱


public ArrayList<UseCodeTop> xmlData(XmlPullParser parser){


        ArrayList<UseCodeTop> list = new ArrayList<>();


        try {

            int eventType = parser.getEventType();


            UseCodeTop data = null;


            while (eventType != XmlPullParser.END_DOCUMENT) {

                switch (eventType) {


                    case XmlPullParser.START_TAG:


                        String startTag = parser.getName();


                        if ("item".equals(startTag)) {

                            data = new UseCodeTop();

                        } else if ("RNUM".equals(startTag)) {

                            data.setRNUM(parser.nextText());

                        } else if ("CTGR_ID".equals(startTag)) {

                            data.setCTGR_ID(parser.nextText());

                        } else if ("CTGR_NM".equals(startTag)) {

                            data.setCTGR_NM(parser.nextText());

                        }

                        break;


                    case XmlPullParser.END_TAG:

                        String endTag = parser.getName();

                        if ("item".equals(endTag)) {

                            list.add(data);

                        }

                        break;

                }

                eventType = parser.next();

            }


        } catch (XmlPullParserException e) {

            e.printStackTrace();

        } catch (IOException e) {

            e.printStackTrace();

        }


        Log.d("UseCodeTop_CNT", list.size() +"");


        //데이터 확인용

        /*Iterator<UseCodeTop> iterator = list.iterator();

        while (iterator.hasNext()) {

            UseCodeTop tmp = (UseCodeTop) iterator.next();

            Log.d("hohoho", tmp.getCTGR_NM().toString());

        }*/


        return list;


    }


공공데이터 (www.data.go.kr) 의 API를 쓸일이 있어서 회원가입도하고 순조롭게하고있는데

갑자기 막혀버렸다


인증키를 발급받는데 까지 후다닥왔는데

인증키를 받고 해당 사이트에서 미리 테스트 해볼수 있는데 

(상세기능정보 -> 미리보기 다운로드 실행 -> 샘플데이터 입력 후 미리보기 클릭)


결과 xml 에

resultCode 가 30으로 나오고

resultMsg 가 SERVICE_KEY_IS_NOT_REGISTERED_ERROR


이런식으로 나왔다 ㅡㅡ


//////////////////////////////////////////////////////////////////


http://www.data.go.kr/pubn/lab/gui/IrosDevGuide/openDataDetailPagePubc.do?pblonsipResrcePk=



찾아보니 등록되지 않은 서비스키라고 하길래

자세히 보니 인증키 발급 후 1시간 이후에 사용 가능하단다


그런데 난 3시간 정도 기다려도 안되더라...ㅡㅡ

기다리다 못해 인증키 재발급을 눌려놓고 재발급 받은 후

자고 일어나서 해보니 정상적으로 작동되었다.




swift로 앱만들기 예제를 따라하고 있는데


강의 내용에는 ++을 썼길래 나도 썻는데 나도 그대로 썼는데

에러는 아니지만 경고가 떴다.


이유를 찾아보니


swift 3.0 에서 ++ 과 -- (증감연산자)가 없어졌다고 한다.


i++ i += 1 요래 바꿔야 될 듯 싶다.


아래는 3.0에서 바뀐것들


https://swifter.kr/2016/06/17/swift-3-0%EC%9D%98-%EB%B3%80%EA%B2%BD%EC%82%AC%ED%95%AD/

  • SE-0002 : Removing currying func declaration syntax (커리 함수 선언 구문 삭제)
  • SE-0003 : Removing var from Function Parameters (함수의 매개변수에서 var 삭제)
  • SE-0004 : Remove the ++ and — operators (++/– 연산자 삭제)
  • SE-0005 : Better Translation of Objective-C APIs Into Swift (Objective-C API를 Swift에 최적화)
  • SE-0006 : Apply API Guidelines to the Standard Library (표준 라이브러리로 API의 지침 적용)
  • SE-0007 : Remove C-style for-loops with conditions and incrementersx (C-Style의 for문 제거)
  • SE-0008 : Add a Lazy flatMap for Sequences of Optionals (선택적 배열을 위한 Lazy flatMap 추가)
  • SE-0016 : Adding initializers to Int and UInt to convert from UnsafePointer and UnsafeMutablePointer (UnsafePointer과 UnsafeMutablePointer에서 변환하는 Int uint로 초기화 추가)
  • SE-0019 : Swift Testing (Swift 테스트)
  • SE-0023 : API Design Guidelines (API의 설계 지침)
  • SE-0029 : Remove implicit tuple splat behavior from function applications (암시적 튜플 스플랫 함수 삭제)
  • SE-0031 : Adjusting inout Declarations for Type Decoration (형 장식을 위한 inout 선언 조정)
  • SE-0033 : Import Objective-C Constants as Swift Types (Objective-C의 상수를 Swift형으로 가져오기)
  • SE-0037 : Clarify interaction between comments & operators (코멘트 / 오퍼레이터 표기규칙 명확)
  • SE-0039 : Modernizing Playground Literals (현대적인 Playground 리터럴)
  • SE-0040 : Replacing Equal Signs with Colons For Attribute Arguments (속성에서 =가 아닌 :을 사용)
  • SE-0043 : Declare variables in ‘case’labels with multiple patterns (여러가지 패턴의 “case”레이블 변수)
  • SE-0044 : Import as Member (Member 가져오기)
  • SE-0046 : Establish consistent label behavior across all parameters including first labels (첫번째 레이블을 포함한 모든 매개변수에서 일관된 레이블 실행 확립)
  • SE-0049 : Move @noescape and @autoclosure to be type attributes (@noescape에서 @autoclosure으로 이동)
  • SE-0053 : Remove explicit use of let from Function Parameters Function 매개 변수에서 let의 명시적인 사용을 제거
  • SE-0054 : Abolish ImplicitlyUnwrappedOptional type (ImplicitlyUnwrappedOptional형 폐지)
  • SE-0055 : Make unsafe pointer nullability explicit using Optional (안전하지 않은 포인터 NULL 값을 허용할지 여부를 Optional사용을 명시적으로)
  • SE-0057 : Importing Objective-C Lightweight Generics (Objective-C 경량화된 제네릭 가져오기)
  • SE-0059 : Update API Naming Guidelines and Rewrite Set APIs Accordingly (API 네이밍 지침과 Set API의 업데이트)
  • SE-0061 : Add Generic Result and Error Handling to autoreleasepool() (Generic Result와 autoreleasepool() 오류 처리 추가)
  • SE-0064 : Referencing the Objective-C selector of property getters and setters (Objective-C selector의 getter / setter 참조)
  • SE-0065 : A New Model For Collections and Indices (컬렉션과 인덱스의 새로운 모델)
  • SE-0069 : Mutability and Foundation Value Types (Mutability와 Foundation의 Value Types)
  • SE-0070 : Make Optional Requirements Objective-C-only (Objective-C 전용 Optional 요구 사항 생성)
  • SE-0071 : Allow (most) keywords in member references ((대부분의) 멤버 참고 키워드 허용)
  • SE-0072 : Fully eliminate implicit bridging conversions from Swift (Swift에서 완전히 암시적 브릿지 변환 제거)


물어 물어서 찾은 

swift 코드를 웹에서 컴파일 해볼수 있는 사이트 입니다.


//////////////////////////////////////////



https://swiftlang.ng.bluemix.net/#/repl


this.finish() 로 액티비티를 종료하는 동시에


나는 메소드가 그 시점에서 멈추고 끝내는 줄 알았다.ㅎㄷㄷ



예를 들어 다음과 같은 코드가 있는데


//onCreate

 protected void createActivity(Bundle savedInstanceState) {

        View view = this.setContainerView(R.layout.activity_main);

        getSupportActionBar().setTitle("경성대 헬퍼");


        if (getIntent().getExtras() != null && getIntent().getExtras().getString("state").equals("kill")) {

            final Intent intent = new Intent(this, SignupActivity.class);

            startActivity(intent);

            this.finish();

            //return;

        }

        checkChatId();

}



값을 받아서 값이 kill이면 액티비티를 종료후 다른 액티비티로 넘어가는 기능인데

this.finish()를 하면 밑에있는 checkChatId(); 를 실행하지 않고 액티비티가 종료 될것이라고 생각했는데

checkChatId(); 가 실행되었다.... 

완전 잘못생각하고있었던것 같다.


this.finish()를 한후 return을 해주니 밑에 함수들이 실행되지 않았다.


playground에서 소스 튜토리얼을 쳐보고있는데 갑자기 execute가 안되었다


unable to create target for stub executable ....


이런 에러가 뜨면서 런이 안되었는데


/////////////////////////////////////////////////


xcode를 리스타트 하니까 제대로 작동되었다.ㅎ

txt파일을 읽는데


1    홍길동    20000

2    임꺽정    21002

3    춘 향    122414

4    jamse lee    123123


이런식으로 txt가 되어있으면 띄어쓰기 단위로 읽으면

이름부분에서 잘못 읽힌다. (이름에 띄어쓰기가 들어갈 수 도 있으니까)


그래서 txt문서에 구분을 탭('\t') 으로 하고

읽을 때 한줄을 읽은다음 tab을 기준으로 스플릿해주면

각각 잘라 사용 할 수 있다.


//////////////////////////////////////////////////////////


private List<Product> saleList = new ArrayList<Product>();


public void loadMenu() {

File file = new File("test.txt");

String[] splitedStr = null;


try {

//한글 깨짐현상 때문에 인코딩

BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "euc-kr"));


String line = null;

splitedStr = null;


while ((line = reader.readLine()) != null) {


splitedStr = null;

splitedStr = line.split("\t");


for (int i = 0; i < splitedStr.length; i++) {

splitedStr[i] = splitedStr[i].trim();

}

//자른 데이터를 원하는 형식에 맞게 넣기

saleList.add(new Product(splitedStr[0], splitedStr[1], Integer.valueOf(splitedStr[2])));

}


reader.close();


} catch (FileNotFoundException fnf) {

fnf.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

참고용 예제


public void saveExcel() {


     String excelFile = "helllooo" + ".xlsx";

int rowNum = 0;


for (int i = 0; i < saleList.size(); i++) {

dayList.get(i).setCount(dayList.get(i).getCount() + saleList.get(i).getCount());

}


SXSSFWorkbook wb = new SXSSFWorkbook(100);


// 셀 스타일

CellStyle ct = wb.createCellStyle();

ct.setAlignment(CellStyle.ALIGN_CENTER);


Sheet sheet = wb.createSheet("First sheet");

if (sheet == null) {

System.out.println("sheet is null!");

return;

}


sheet.setColumnWidth(1, 9000);


Row row1 = sheet.createRow(rowNum);

rowNum++;


Cell cell_1 = row1.createCell(0);

cell_1.setCellValue("제품번호");

cell_1.setCellStyle(ct);

Cell cell_2 = row1.createCell(1);

cell_2.setCellValue("이름");

cell_2.setCellStyle(ct);

Cell cell_3 = row1.createCell(2);

cell_3.setCellValue("구매 개수");

cell_3.setCellStyle(ct);

Cell cell_4 = row1.createCell(3);

cell_4.setCellValue("가격");

cell_4.setCellStyle(ct);


for (int i = 0; i < dayList.size(); i++) {

Row row = sheet.createRow(rowNum);

for (int j = 0; j < 4; j++) {

Cell cel_1 = row.createCell(0);

cel_1.setCellValue(dayList.get(i).getSerial_no());

Cell cel_2 = row.createCell(1);

cel_2.setCellValue(dayList.get(i).getName());

Cell cel_3 = row.createCell(2);

cel_3.setCellValue(dayList.get(i).getCount());

cel_3.setCellStyle(ct);

Cell cel_4 = row.createCell(3);

cel_4.setCellValue(dayList.get(i).getPrice() * dayList.get(i).getCount());

}

rowNum++;

}


try {

FileOutputStream fileOut = new FileOutputStream(excelFile);

wb.write(fileOut);

fileOut.close();

wb.dispose();


JOptionPane.showMessageDialog(null, "엑셀로 저장 완료 (파일 이름 :" + excelFile + ")");

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

public String getCurrentTime(){

Calendar cd = Calendar.getInstance();

Date date = cd.getTime();

//밑의 데이트 포멧 부분은 원하는 포멧대로 수정하면 된다

String today =  (new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분").format(date));

return today;

}

public int getByteLength(String str) {


int strLength = 0;

char tempChar[] = new char[str.length()];


for (int i = 0; i < tempChar.length; i++) {

tempChar[i] = str.charAt(i);


if (tempChar[i] < 128) {

strLength++;

} else {

strLength += 2;

}

}


return strLength;

}

카카오톡 로그인을 사용하고 있는데 액티비티 구조가 이렇다...


1 . Login -> Main 하면서 Login액티비티 finish

2 . Main -> Setup 하면서 Main액티비티 finish하지 않음

3.  Setup액티비티에  앱 연결 해지 기능 있음

4.  앱 연결 해지 하면 Login 액티비티로 이동



여기서 문제가 발생했다.

앱 연결 해지 후 Login액티비티로 이동하는데 Main액티비티가 살아있어

뒤로가기하면 앱이 종료되는것이 아니라 Main액티비티로 이동해버린다...


///////////////////////////////////////////////////////////////////////////////////////


해결방법에는 여러가지가 있었는데

새로운 액티비티를 열때마다 액티비티를 저장해놓고 한꺼번에 종료시키는 방법

finishAffinity() 사용 등이 있었는데

나 같은 경우는 액티비티를 하나만 더 종료시켜주면 되니까 putExtra를 사용하기로 했다.


앱 연결 해지 버튼을 누르면


protected void redirectSignupActivity() {

        final Intent intent = new Intent(this, MainActivity.class);

        intent.putExtra("state", "kill");

        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        startActivity(intent);

        this.finish();

    }


이 메소드를 실행시키게 한다

이때 LoginActivity로 바로 인텐트 하지않고 Main액티비티를 거쳐 가게끔 한다

setFlags를 FLAG_ACTIVITY_CLEAR_TOP으로 줘서

기존에 쌓여있는 main액티비티만을 남기고 나머지 activity를 종료시킨다.

(FLAG_ACTIVITY_CLEAR_TOP 플래그를 주게되면 해당 Main액티비티가 OnCreate부터 다시 실행된다)


그리고 MainActivity의 OnCreate에


if (getIntent().getExtras() != null && getIntent().getExtras().getString("state").equals("kill")) {

            final Intent intent = new Intent(this, LoginActivity.class);

            startActivity(intent);

            this.finish();

        }


이렇게 해놓으면 "kill"값을 받고

LoginActivity를 띄운다음

MainActivity는 죽게된다.


그리고 LoginActivity에서 뒤로가기를 누르게되면 Main으로 넘어가지않고

앱이 종료되는것을 알 수 있다.

갑자기 안드로이드 스튜디오를 실행하여

VCS Update Project를 선택하여  학교에서 커밋한 프로젝트를

집에서 업데이트 받으려고 했는데

 이런 에러가 발생하였다.


Error:svn: E155004: Run 'svn cleanup' to remove locks (type 'svn help cleanup' for details)

svn: E155004: Working copy '[프로젝트경로...]' locked.

svn: E155004: '[프로젝트경로...]' is already locked.


svn에 뭔가 에러가 발생한거 같긴한데 구글을 검색하니

svn에 직접 접속하여 cleanup 명령어를 실행하라는 등 여러가지 해결방안이 있었는데

어떻게 해야하는지 이해도 되지 않고 헤깔렸다.


그런데 어떻게하다보니 너무 쉽게 해결되었다....


///////////////////////////////////////////////////////////////////////////////



VCS 메뉴에서 Cleanup Project를 클릭하니 바로 해결되었다...


개발하던 앱이 마쉬멜로우(M) 버전을 타겟으로 만들고 있었는데

M버전 이상 버전으로는 권한체크 방식이 달라졌다고 들어서


갤럭시 노트4(os 버전이 마쉬멜로우)를 빌려 그곳에 컴파일 해보았는데

해당 Dangerous permissions 을 사용하는 기능에서 

에러가 나면서 앱이 종료되버렸다.

(사실 앱이 종료까지 될 줄은 몰랐다. 해당 기능만 실행 안되고 말줄 았았는데

앱이 강제 종료되버렸다.)


내가 사용한 Dangerous permissions 에는 


ACCESS_FINE_LOCATION

CALL_PHONE

WRITE_EXTERNAL_STORAGE

GET_ACCOUNTS


요렇게 있었는데 해결 방법을 찾던 중

좋은 블로그를 발견해서 여기를 참고하여 해결했다.

http://gun0912.tistory.com/55



이 사이트에서는 라이브러리도 제공하는데

TedPermission 라이브러리를 이용하여

쉽게 권한문제를 해결했다.


https://github.com/ParkSangGwon/TedPermission


해당 Dangerous permissions 을 사용하는 곳에서 

기능을 사용하기전에 권한 체크를한 후

권한이 있을때 작업을 진행하는 구조인것 같다.


////////////////////////////////////////////////////////////////////////////


권한 체크 작업을 하던중 기존에 작동하던 기능이 안되는 부분을 발견하여 

확인해보았는데 



<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />


이 부분의 권한이 문제를 이르켰다.


푸쉬알람이 오면 앱안이든 앱밖이던 언제든지 윈도우 다이얼로그 팝업을 띄우려고(최상위 뷰) 사용한 권한인데

해당 기능에 퍼미션 문제를 이르키며 작동되지 않았다


TedPermission 라이브러리를 이용해서 처리해보려 했는데 해결되지 않았다.


확인해보니 해당 권한은 [앱] -> [설정] -> [권한] 에서 확인 하여 허용하는 권한이 아니라

[다른 앱 위에 그릴 수 있는 앱]이라는 설정 화면 에서 허용을 해줘야하는 권한이었다.


https://brunch.co.kr/@babosamo/49


그래서 해당 부분 권한은 따로 처리하였는데


public final static int REQUEST_CODE = 3333;


public void startOverlayWindowService(Context context) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) {

            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));

            startActivityForResult(intent, REQUEST_CODE);

        }

    }



@Override

protected void onActivityResult(int requestCode, int resultCode,  Intent data) {

    if (requestCode == REQUEST_CODE) {

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {

            if (Settings.canDrawOverlays(this)) {

                Toast.makeText(MainActivity.this, "오버레이 권한 확인 완료", Toast.LENGTH_SHORT).show();

            } else {

                Toast.makeText(MainActivity.this, "오버레이 권한이 없습니다.", Toast.LENGTH_SHORT).show();

            }

        }

    }

}


이런식으로 처리를 해주었다.

listview를 만드는데 adpater의 getview에서 onClickListener를 매겼다

그런데 처음 띄웠을때의 리스트 아이템은 제대로 값이 들어갔지만


스크롤하여 밑쪽 데이터를 누르니 다른 데이터가 나왔다...


///////////////////////////////////


if (convertView == null) {


}


이 안에 온클릭리스너를 잡아주었는데

이 안에서 데이터를 넣으면 안된다고한다

(convertView를 재사용하기 때문에 라고 한다)


if문 밖에서 리스너를 잡아주니 제대로 작동 되었다.


참고 사이트

http://myelf.egloos.com/2723978

액티비티가 아닌 곳에서 전화 걸기 화면으로 넘기기 위한 방법


////////////////////////////////


Context를 선언하여 생성자에서 context를 미리 받아놓자

(객체생성할때 this를 넘기자)


private Context mContext;


public 생성자(Context context){

mContext = context;

}


private void startCall(String num) {

        Intent it = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + num));

        it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        mContext.startActivity(it);

}


//////////////////////////////////


근데 저렇게 써왔던것 같은데 startActivity에서 에러가 났다 ㅡㅡ

에러 알림에서 해결방법을 클릭했더니


private void startCall(String num) {

        Intent it = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + num));

        it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {

            // TODO: Consider calling

            //    ActivityCompat#requestPermissions

            // here to request the missing permissions, and then overriding

            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,

            //                                          int[] grantResults)

            // to handle the case where the user grants the permission. See the documentation

            // for ActivityCompat#requestPermissions for more details.

            return;

        }

        mContext.startActivity(it);

    }


이런식으로 권한체크 if문이 추가되었다!!! 

마시멜로우 부터 권한 부분이 달라졌다고 들었는데 그 때문인것 같다. 

(마시멜로우 전에는 앱 설치시 모든 권한을 다 허가받고 설치를 했는데 

후 부터는 각 기능을 실행하기전에 권한을 확인한다고 한다??)


아무튼 권한여부를 이제 각각 체크해줘야 하는것 같은데 좀 더 알아보고 해야겠다.

참고할만한 사이트는 찾았다.


http://gun0912.tistory.com/55

fastScroll 작업때문에 첫번째 리스트 아이템의 첫번쨰 글자의 자음이 필요했다.


검색하여 간단하게 자음을 가져오는 방법을 알게됬다.


///////////////////////////



private static final char HANGUL_BEGIN_UNICODE = 44032; // 가

private static final char HANGUL_LAST_UNICODE = 55203; // 힣

private static final char HANGUL_BASE_UNIT = 588;//각자음 마다 가지는 글자수

private static final char[] INITIAL_SOUND = { 'ㄱ', 'ㄲ', 'ㄴ','ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ','ㅊ', 

'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' };


private char getInitialSound(char c) {

            int hanBegin = (c - HANGUL_BEGIN_UNICODE);

            int index = hanBegin / HANGUL_BASE_UNIT;

            return INITIAL_SOUND[index];

        }


String을 st.charAt(0) 으로 때서 함수에 넣어주면

자음을 반환해 준다.


ex)

String test = "테스트 입니다";


char result = getInitialSound(test.charAt(0));


or


String result = getInitialSound(test.charAt(0)) + "" ;


이렇게 하면 'ㅌ'가 나오게 된다.

액티비티에 editText를 사용하면

액티비티가 실행될 때 자동으로 editText가 포커싱 되면서

키보드가 자동으로 올라오게 된다.  

너무 보기안좋았다....


/////////////////////////////////////


해결방법


<activity

            android:name=".call.CallActivity"

            android:windowSoftInputMode="stateAlwaysHidden"

            android:screenOrientation="portrait" 

/>


요렇게 AndroidManifest.xml 에서  android:windowSoftInputMode="stateAlwaysHidden" 를 

액티비티 속성에 넣어주면 해당 엑티비티에서는 실행할때 에디트텍스트가 있어도 

키보드를 띄우지 않게된다. (그래도 포커싱은 된다)


다른방법으로는 강제로 다른 뷰에 포커싱을 줘버리면 된다.

볼리 라이브러리의 NetworkImageView 를 사용하는 중인데


불러올 이미지가 없을때 디폴트 이미지를 지정하기위해


<com.android.volley.toolbox.NetworkImageView

                android:id="@+id/niv_user_image"

                android:layout_width="match_parent"

                android:layout_height="match_parent"

                android:src="@drawable/ic_anonymous"

                android:scaleType="centerCrop" />


이런식으로 사용하였는데 src 부분이 먹질 않았다.


/////////////////////////////////////


검색해보니 java 소스상에서 밑에 내용을 추가해주면 디폴트이미지와 

이미지를 불러오기 실패했을 때의 기본이미지를 지정해 줄 수 있다.


userImage.setDefaultImageResId(R.drawable.kakao_default_profile_image);

userImage.setErrorImageResId(R.drawable.kakao_default_profile_image);

개발하다보니 NestedScrollView 안에 RecyclerView 를 넣게되었는데

스크롤 동작은 정상적으로 작동되었지만

RecyclerView부분이 화면밖으로 나갔을 떄 그쪽까지 스크롤이 되지 않거나

아에 뷰가 안생기는 현상을 확인하였다


대충 아래와같은 그림이었는데...


///////////////////////////////////////////


<LinearLayout>


<android.support.v4.widget.NestedScrollView>


<LinearLayout>


<android.support.v7.widget.CardView>

</android.support.v7.widget.CardView>


<android.support.v7.widget.RecyclerView>

</android.support.v7.widget.RecyclerView>


</LinearLayout>

</android.support.v4.widget.NestedScrollView>

</LinearLayout>


/////////////////////////////////////////////


생각해보니 RecyclerView의 height길이가 고정이 아니라 NestedScrollView의 전체길이에

포함되지 않아 RecyclerView 부분이 잘린것 같다고 생각이 들었다.


그래서 RecyclerView의 height 속성에 고정으로 박아주니 그 크기만큼 잘 표시되었다.

(ex) 

<android.support.v7.widget.RecyclerView

    android:id="@+id/rv_lost_comment_list"

          android:layout_width="match_parent"

          android:layout_height="300dp"

/>


하지만 나같은 경우는 리사이클뷰에 아이템이 없을수도있고, 많이있을수도 있는데

저렇게 300dp로 고정하게되니 없어도 무조껀 저만큼 생기게되어 옮바른 해결방법이 아니라 생각하였다.


/////////////////////////////////////////////////////////


그래서 찾게된 해결방법은

xml에서가 아니라 java소스상에서 리사이클뷰에 들어갈 아이템 개수가 정해지면

그때 리사이클뷰의 height에 고정 길이를 부여하면 될것같아서 해보았다.


private void resizeCommentList(int item_size){

        ViewGroup.LayoutParams params = rvLostCommentList.getLayoutParams();

        params.height = 200 * item_size;

        rvLostCommentList.setLayoutParams(params);

}

//여기서 rvLostCommentList 는 findviewbyid로 잡은 리사이클뷰


이런식으로 아이템 갯수가 정해지면

(아이템 갯수) X (아이템 하나에 해당하는 예상 고정 길이)

해서 나온 값을 리사이클뷰의 height 속성에 부여하게 되면

아이템 갯수에 따라 길이가 잘 조정되었다.


리스트뷰 대신에 RecyclerView 를 이용하여 게시판을 만들어보려고 하고있는데


화면에서 분명히 RecyclerView의 width를 match_parrent로 하여 옆으로 꽉차게 하였는데


적용되지가 않았다 (물론 item도 width는 match_parrent)


////////////////////////////////////////////////////////


검색해보니 어댑터 부분의 onCreateViewHolder 부분을 수정해주면 된다고 하여 수정해보았다.


원래 아래와같이 


   @Override

    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_lost, null);

        return new ViewHolder(v);

    }


이런식으로 작성하였었는데 아래와 같이 작성하니



   @Override

    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_lost, parent, false);

        return new ViewHolder(v);

    }


해결되었다.


원인은 


Parameters
resource ID for an XML layout resource to load (e.g., R.layout.main_page) root
view to be the parent of the generated hierarchy (if attachToRoot is true), or else simply an object that provides a set of LayoutParams values for root of the returned hierarchy (if attachToRoot is false.)
attachToRoot Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML. Returns The root View of the inflated hierarchy. If root was supplied and attachToRoot is true, this is root; otherwise it is the root of the inflated XML file.


It is important here to not supply true, but do supply the parent:


Supplying the parent View lets the inflater know what layoutparams to use. Supplying the falseparameter tells it to not attach it to the parent just yet. That is what the RecyclerView will do for you.


요렇다는데 아직 이해가 안간다. 시간날때 다시 해석해봐야겠다




문제
별첨 word1200.txt 파일의 1,200개 영어단어 해시 테이블 구성
세부 설명
1,200개의 영단어/해석 포인터 저장을 위한 배열[1200]을 선언
각 배열의 내용은 실제 단어/해석 자료구조가 저장된 곳의 포인터
자료구조에는 영단어, 해석 이외에 해시 충돌 시 다음 단어 저장을 위해 다음 자료구조
에 대한 포인터도 포함되어야 함
해시 함수를 스스로 만들고
1,200개를 모두 저장한 뒤 아래에 따라 성능을 평가
§적재밀도 = 저장에 사용된 배열 수/1200
실행 결과 보여주기
txt 파일을 읽어 해시 테이블을 구성하고 적재밀도를 출력

영어 단어를 입력하면 해석을 출력

//////////////////////////////////////////////////////////////////


#include <iostream>

#include <fstream>

#include <cstring>

#include <string>

#include <stdlib.h>


#pragma warning ( disable : 4996 )


using namespace std;


int hashGetIndex(char key[]);

void makeHash(char buffer[100]);

void searchWord();


//영어 단어 구조체

typedef struct english {

char word[50]; //단어

char mean[100]; //뜻

struct english* chain = NULL; //충돌을 대비한 체인 포인터

}ENGLISH;


//해시 탐색을 위한 포인터 배열 선언

ENGLISH* englishArray[1200] = {'\0'};


void main() {

int i = 0, index = 0;

ifstream file;

char buffer[100];

file.open("english1200.txt");


if (!file.is_open()) {

cout << "파일 열기 실패!" << endl;

}


while (!file.eof()) {

memset(buffer, 0, sizeof(buffer));

file.getline(buffer, 100);


makeHash(buffer);

}


searchWord();


//해당 인덱스에 저장 상태 체크

/*

ENGLISH *tt = englishArray[1069];


while (tt != NULL) {

cout << tt->word << endl;

cout << tt->word[7] << endl;

tt = tt->chain;

}

*/

file.close();

}


//해시 만들기

void makeHash(char buffer[100]) {


char* token = NULL;

char tk[] = "\t\n";

int index = 0;


ENGLISH *tmp = NULL;

ENGLISH *current = NULL;


tmp = (ENGLISH *)malloc(sizeof(ENGLISH));

memset(tmp, 0, sizeof(ENGLISH));


token = strtok(buffer, tk);

strcat(tmp->word, token);


//cout << tmp->word << "\n\n";


token = strtok(NULL, tk);

strcat(tmp->mean, token);


//cout << tmp->mean << endl;


tmp->chain = NULL;


index = hashGetIndex(tmp->word);



if (englishArray[index] == NULL) {

englishArray[index] = tmp;

}

else {


current = englishArray[index];


while (current->chain != NULL) {

current = current->chain;

}

current->chain = tmp;

}

}


//해시 알고리즘

int hashGetIndex(char key[]) {


int hashKey = 0;


int word1 = key[0]; //첫번째 글자의 아스키코드

int word2 = key[strlen(key) - 1]; //끝글자의 아스키코드

int word3 = strlen(key); //문자열의 길이

int word4 = key[strlen(key) / 2]; //가운데 글자의 아스키코드


//hashKey = ((word1 * 107) + (word2 * 31) + word3) % 1200; //556

//hashKey = ((word1*17) + (word2 * 31) + word3) % 1200;   //514

//hashKey = (((word1 + word2) * word3) * 17) % 1199; //312

//hashKey = (word1 + word2 * word3 * word4) % 1199; //695

//hashKey = (word1 * word2 * word3 * word4) % 1199; //537

//hashKey = (word1 * word2 + word3 - word4) % 1199; //628

//hashKey = (word1 * word2 / word3 - word4) % 1200; //698

//hashKey = (word1 * word2 / word3 * word4) % 1200; //540

//hashKey = (word1 * word2 / word3 * word4) % 1199; //648

//hashKey = (word1 * word2 / word3 - word4) % 1199; //693

//hashKey = (word1 * word2 * word3 * word4) % 1200; //275

//hashKey = ((word1 * word4) + word3 + word2) % 1200; //664

//hashKey = ((word1 * word4) / word3 + word2) % 1200; //705

//hashKey = ((word1 * word4) / word3 * word2) % 1200; //538

hashKey = ((word1 * word4) / word3 + word2) % 1200; //705


//해시키 분포도 보기

cout << hashKey << endl;


return hashKey;

}


//단어 검색 함수

void searchWord() {

char input[50] = {'\0'};

int index = 0;

ENGLISH *tmp = NULL;


while (1) {


cout << "\n\n검색할 단어를 입력해 주세요 (종료: exit) : ";

fflush(stdin);


cin.getline(input, 50);

if (strcmp(input, "exit") != 0) {

index = hashGetIndex(input);


if (englishArray[index] != NULL) {

tmp = englishArray[index];


while ((strcmp(tmp->word, input) != 0) && (tmp->chain != NULL)) {

tmp = tmp->chain;

}


if ((tmp->chain == NULL) && (strcmp(tmp->word, input) != 0)) {

cout << "일치하는 단어가 없습니다" << endl;

} else {

cout << "단어 = " << tmp->word << endl;

cout << "뜻 = " << tmp->mean << endl;

}

} else {

cout << "일치하는 단어가 없습니다" << endl;

}

} else {

cout << "종료합니다..." << endl;

exit(1);

}

}

}



data.txt

report2.cpp



대체 선택 알고리즘을 C++로 작성하시오
슬라이드 10쪽과 같이 생성과정을 보여줄 것
슬라이드 8쪽을 입력 데이터로 수행하여 실행


//////////////////////////////////////////////////////////////////////////////////////



#include <iostream>

#include <fstream>

#include<cstdlib>

#include <cstring>


/*

Microsoft visual studio 2015 에서 실행했습니다~~

*/


#pragma warning ( disable : 4996 )


#define MAX_MEMORY 3


using namespace std;


void saveMemory(int data);

bool checkFullMemory();

bool checkFrozen();

void makeRun();

void printMemory();

void Selectminimum();

void writeRunFile();

void lastDataClear();

void printRun();


int memory[MAX_MEMORY];

bool written[MAX_MEMORY];

bool frozen[MAX_MEMORY];

int lastData = 0;

int cnt_partition = 0;

int minIndex;



void main() {

ifstream file;

int i = 0;

int buf = 0;

file.open("data.txt");

if (!file.is_open()) {

cout << "파일 열기 실패!" << endl;

}


memset(memory, 0, MAX_MEMORY);

memset(written, false, MAX_MEMORY);

memset(frozen, false, MAX_MEMORY);


while (!file.eof()) {

file >> buf;


cout << "Input data = " << buf << endl;


saveMemory(buf); //메모리가 비어있으면 data를 메모리에 저장


if (!checkFullMemory()) {

continue;

makeRun();

//printRun();

}

file.close();


for (i = 0; i < MAX_MEMORY - 1; i++) {

lastDataClear();

}


printRun();

}


//비어있는 메모리에 입력값 저장

void saveMemory(int data) {

int i = 0;


for (i = 0; i < MAX_MEMORY; i++) {

if (written[i] == false) {

memory[i] = data;

written[i] = true;

break;

}

}


}


//메모리 상태 체크

bool checkFullMemory() {

//메모리에 데이터가 다 들어가 있으면 true, 없으면 false

int i = 0;

int cnt = 0;


for (i = 0; i < MAX_MEMORY; i++) {

if (written[i] == true) {

cnt++;

}

}


if (cnt != MAX_MEMORY) {

return false;

}

else {

return true;

}


}


//빙결상태 체크

bool checkFrozen() {

// 전체 빙결상태이면 true, 아니면 false

int i = 0;

int cnt = 0;


for (i = 0; i < MAX_MEMORY; i++) {

if (frozen[i] == true) {

cnt++;

}

}


if (cnt != MAX_MEMORY) {

return false;

}

else {

return true;

}


}


//런만들기

void makeRun() {


int i;


Selectminimum();


if (checkFrozen()) {

cout << "!!!!!!!!!!!!!!전체 빙결(분할 완료)!!!!!!!!!!!!!!!!!" << endl;

cnt_partition++;

lastData = 0;


for (i = 0; i < MAX_MEMORY; i++) {

frozen[i] = false;

}

Selectminimum();

}


writeRunFile();

}


//조건에 맞는 미니멈값 찾기

void Selectminimum() {

int i=0;

minIndex = 0;


//프로즌상태가 아니고, 라스트데이터보다 값이 크며, 현재 비교대상 메모리보다 작을 때 mindIndex 교체

for (i = 0; i < MAX_MEMORY; i++) {

if ((memory[i] < lastData)) {

frozen[i] = true;

}

}


//비교 대상 찾기 (프로즌 상태가 아닌 수)

i = 0;

while(i < MAX_MEMORY) {

if (frozen[i] != true) {

minIndex = i;

break;

}

i++;

}


//비교하면서 조건에 맞는 인덱스 찾기

for (i=0; i < MAX_MEMORY; i++) {

if ((frozen[i] == false) && (memory[i] > lastData) && (memory[minIndex] >= memory[i])) {

minIndex = i;

}

}


printMemory();

}


//파일에 런 쓰기입력

void writeRunFile() {

char file_name[20];

ofstream outfile;


//파일이름 설정

itoa(cnt_partition + 1, file_name, 10);

strcat(file_name, "_partition.txt");


outfile.open(file_name, ios::app);


//outfile << memory[minIndex] << " ";

outfile << " " << memory[minIndex];

lastData = memory[minIndex];


outfile.close();

written[minIndex] = false;

}


//현재 메모리에 들어가있는 값 출력

void printMemory() {

int i;


cout << "\n//////////////////////////////////////////////" << endl;


for (i = 0; i < MAX_MEMORY; i++) {

if (frozen[i] == true) {

cout << "(";

}

cout << memory[i];

if (frozen[i] == true) {

cout << ") ";

} else {

cout << " ";

}

}


cout << "\n//////////////////////////////////////////////" << endl;

}



//런파일들을 화면에 출력

void printRun() {

int i;

ifstream file;

int buf;

char file_name[20];


cout << "\n----------------------------------------------" << endl;


for (i = 0; i <= cnt_partition; i++) {

cout << i + 1 << "번 분할////" << endl;


memset(file_name, 0, sizeof(file_name));

itoa(i + 1, file_name, 10);

strcat(file_name, "_partition.txt");


file.open(file_name);


while (!file.eof()) {

file >> buf;

cout << buf << " ";

}

file.close();

cout << "\n////////////////////////////////////////" << endl;

}

cout << "\n----------------------------------------------" << endl;

}


//마지막 남은 데이터 처리

void lastDataClear() {

int i = 0;


while (i < MAX_MEMORY) {

if (written[i] == true) {

minIndex = i;

break;

}

i++;

}


for (i = 0; i < MAX_MEMORY; i++) {

if ((written[i] == true) && (memory[minIndex] > memory[i])) {

minIndex = i;

}

}


writeRunFile();


}




init_file()
§5명의 학생으로 구성된 마스터 파일 생성, 학번은 각각 10, 20, 30, 40, 50.  학생은 2과목씩 수강
§슬라이드 20쪽의 struct transaction 자료형으로
학번이 35이고 mode각 각각 C, D, I3개 트랜잭션 파일 생성
학번이 20이고 mode각 각각 C, D, I3개 트랜잭션 파일 생성
trans_insert(), trans_delete(), trans_correct()
§마스터 파일에 레코드를 추가, 삭제, 수정하는 함수
§슬라이드 26, 35 참고
main()에서는
§6개의 transaction 파일을 읽고 mode에 따라 위 3개 함수를 호출
report()

마스터 파일 내용 보여주기


//////////////////////////////////////////////////////////////////////////


#include <iostream>

#include <fstream>

#include <cstring>

#include <stdlib.h>

#include <vector>

#include <algorithm>


/*

Microsoft visual studio 2015 에서 실행했습니다~~

*/


#pragma warning ( disable : 4996 )


using namespace std;


// 과목 데이터 타입 선언 

typedef struct course_type {

char dept[10]; //부서

char course_name[20];//과목 이름

char prof_id[7]; //교수 id

int credit; //학점

}COURSE;


// 학생 레코드 구조 선언

typedef struct student {

int id; //학번

char name[20]; //이름

char address[50]; //주소

int no_of_courses; //과목의 갯수

course_type course[2]; // 한 학생이 최대 2강좌 수강 가능

}STUDENT;


typedef struct transaction {

STUDENT student;

char mode; // C: 갱신, D: 삭제, I: 추가 

}TRANSACTION;


int print_menu(); //메뉴 출력

void init_file(); //초기 마스터 파일 읽기, 예제 트랜잭션 생성

void run_trans(); //트랜잭션 실행

void trans_insert(STUDENT data); //트랜잭션 삽입 기능

void trans_delete(STUDENT data); //트랜잭션 삭제 기능

void trans_correct(STUDENT data); //트랜잭션 수정 기능

void make_trans(char mode, STUDENT data); //트랜잭션 파일 생성

void write_file(); //마스터 파일에 저장 쓰기

void report(); //마스터 파일 출력

void write_trans(); //생성할 트랜잭션 데이터 입력

void remove_trans(); //기존 생성한 트랜잭션 파일들 삭제 

bool id_compare(STUDENT a, STUDENT b); //정렬을 위한 비교 함수


vector<STUDENT> students;

int trans_cnt = 0;


void main() {


int menu = 0;

init_file();


while (1) {

menu = print_menu();


switch (menu)

{

case 1 :

report();

break;

case 2 :

write_trans();

break;

case 3:

run_trans();

break;

case 4:

remove_trans();

break;

default:

cout << "종료합니다...." << endl;

return;

break;

}

}

}


//메뉴 출력

int print_menu() {

int num = 0;


while (1) {

cout << "/////////////////////////////////////////////////////////////////" << endl;

cout << "-------------------------------------------------------------------" << endl;

cout << "|  1. 마스터 파일 보기   2. 새로운 트랜잭션 생성   3.트랜잭션 실행|" << endl;

cout << "|  4.기존 트랜잭션 삭제   5.종료                                  |" << endl;

cout << "-------------------------------------------------------------------" << endl;

cout << "/////////////////////////////////////////////////////////////////" << endl;

cout << "메뉴를 입력해 주세요 : ";

cin >> num;


if (num == 1 || num == 2 || num == 3 || num == 4 || num == 5) {

break;

}

else {

cout << "다시 입력해주세요." << endl;

}

}


return num;

}


//마스터파일 내용 출력

void report() {

int i = 0;


for (i = 0; i < students.size(); i++) {

cout << i + 1 << "번째 학생//////////////////" << endl;

cout << "학번: " << students[i].id << endl;

cout << "이름: " << students[i].name << endl;

cout << "주소: " << students[i].address << endl;

cout << "수강 강좌 수: " << students[i].no_of_courses << endl;

cout << "--------------------------------------" << endl;


if (students[i].no_of_courses >= 1) {

cout << "1번과목 종류: " << students[i].course[0].dept << endl;

cout << "1번과목 이름: " << students[i].course[0].course_name << endl;

cout << "1번과목 교수번호: " << students[i].course[0].prof_id << endl;

cout << "1번과목 학점: " << students[i].course[0].credit << endl;

}


if (students[i].no_of_courses == 2) {

cout << "--------------------------------------" << endl;

cout << "2번과목 종류: " << students[i].course[1].dept << endl;

cout << "2번과목 이름: " << students[i].course[1].course_name << endl;

cout << "2번과목 교수번호: " << students[i].course[1].prof_id << endl;

cout << "2번과목 학점: " << students[i].course[1].credit << endl;

}


cout << "/////////////////////////////////////////\n\n" << endl;

}

}


//파일 준비, 생성

void init_file() {


int i = 0, j=0;

ifstream file;

file.open("student_list.txt");

if (!file.is_open()) {

cout << "파일 열기 실패!" << endl;

}


//마스터 파일 읽기

while (!file.eof()) {

STUDENT tmp_data;

memset(&tmp_data, 0, sizeof(tmp_data));


file >> tmp_data.id;

file >> tmp_data.name;

file >> tmp_data.address;

file >> tmp_data.no_of_courses;


if (tmp_data.no_of_courses >= 1) {

file >> tmp_data.course[0].dept;

file >> tmp_data.course[0].course_name;

file >> tmp_data.course[0].prof_id;

file >> tmp_data.course[0].credit;

}


if (tmp_data.no_of_courses == 2) {

file >> tmp_data.course[1].dept;

file >> tmp_data.course[1].course_name;

file >> tmp_data.course[1].prof_id;

file >> tmp_data.course[1].credit;

}


students.push_back(tmp_data);

i++;

}


file.close();


////////////////////////트랜잭션 작성 (임시 6개 생성)


STUDENT temp_data_1;

memset(&temp_data_1, 0, sizeof(temp_data_1));



temp_data_1.id = 35;

strcpy(temp_data_1.name, "김영희");

strcpy(temp_data_1.address, "전라남도_전라시_중앙동");

temp_data_1.no_of_courses = 1;

strcpy(temp_data_1.course[0].dept, "교양");

strcpy(temp_data_1.course[0].course_name, "성문화와심리");

strcpy(temp_data_1.course[0].prof_id, "7777");

temp_data_1.course[0].credit = 2;


make_trans('I', temp_data_1);

make_trans('C', temp_data_1);

make_trans('D', temp_data_1);

/////////////////////////////////////

STUDENT temp_data_2;

memset(&temp_data_2, 0, sizeof(temp_data_2));


temp_data_2.id = 20;

strcpy(temp_data_2.name, "장수왕");

strcpy(temp_data_2.address, "경상남도_고성시_고룡동");

temp_data_2.no_of_courses = 2;

strcpy(temp_data_2.course[0].dept, "교양");

strcpy(temp_data_2.course[0].course_name, "성문화와심리");

strcpy(temp_data_2.course[0].prof_id, "7777");

temp_data_2.course[0].credit = 2;

strcpy(temp_data_2.course[1].dept, "전공");

strcpy(temp_data_2.course[1].course_name, "경영학개론");

strcpy(temp_data_2.course[1].prof_id, "121212");

temp_data_2.course[1].credit = 3;


make_trans('I', temp_data_2);

make_trans('C', temp_data_2);

make_trans('D', temp_data_2);


}


void remove_trans() {

char file_name[20];


//기존 트랜잭션파일 삭제

for (int i = 0; i < trans_cnt; i++) {

memset(file_name, 0, sizeof(file_name));

itoa(i + 1, file_name, 10);

strcat(file_name, "_trans.txt");

remove(file_name);

}

trans_cnt = 0;

}


//트랜잭션 데이터 입력.

void write_trans() {

TRANSACTION trs;


memset(&trs, 0, sizeof(trs));


cout << "//////////////////////////////////////////" << endl;

cout << "트랜잭션을 추가합니다..." << endl;

cout << "모드를 입력해주세요 (I : 삽입, C : 수정, D : 삭제) = ";

cin >> trs.mode;

cout << "학번을 입력하세요 = ";

cin >> trs.student.id;

fflush(stdin);

if (trs.mode == 'D') {

make_trans(trs.mode, trs.student);

return;

}

cout << "이름을 입력하세요 = ";

cin >> trs.student.name;

cout << "주소를 입력하세요(띄어쓰기는 _언더바로 해주세요) = ";

cin >> trs.student.address;

cout << "수강 갯수를 입력하세요(최대 2개) = ";

cin >> trs.student.no_of_courses;


if (trs.student.no_of_courses >= 1) {

cout << "과목1의 종류를 입력하세요 = ";

cin >> trs.student.course[0].dept;

cout << "과목1의 이름을 입력하세요 = ";

cin >> trs.student.course[0].course_name;

cout << "과목1의 교수id를 입력하세요 = ";

cin >> trs.student.course[0].prof_id;

cout << "과목1의 학점을 입력하세요 = ";

cin >> trs.student.course[0].credit;


if (trs.student.no_of_courses == 2) {

cout << "과목2의 종류를 입력하세요 = ";

cin >> trs.student.course[1].dept;

cout << "과목2의 이름을 입력하세요 = ";

cin >> trs.student.course[1].course_name;

cout << "과목2의 교수id를 입력하세요 = ";

cin >> trs.student.course[1].prof_id;

cout << "과목2의 학점을 입력하세요 = ";

cin >> trs.student.course[1].credit;

}


make_trans(trs.mode, trs.student);

}



//트랜잭션 파일 생성

void make_trans(char mode, STUDENT data) {


char file_name[20];

ofstream outfile;


//파일이름 설정

itoa(trans_cnt+1, file_name, 10);

strcat(file_name, "_trans.txt");


//파일 생성

outfile.open(file_name, ios::trunc);


outfile << mode << '\t';

outfile << data.id << '\t';

outfile << data.name << '\t';

outfile << data.address << '\t';

outfile << data.no_of_courses;


if (data.no_of_courses >= 1) {

outfile << '\t' << data.course[0].dept << '\t';

outfile << data.course[0].course_name << '\t';

outfile << data.course[0].prof_id << '\t';

outfile << data.course[0].credit;

}


if (data.no_of_courses == 2) {

outfile << '\t' << data.course[1].dept << '\t';

outfile << data.course[1].course_name << '\t';

outfile << data.course[1].prof_id << '\t';

outfile << data.course[1].credit;

}


outfile.close();


trans_cnt++;

}


//트랜잭션 실행

void run_trans() {

int i = 0;

char file_name[20];


while (i < trans_cnt) {

ifstream file;


memset(file_name, 0, sizeof(file_name));

itoa(i + 1, file_name, 10);

strcat(file_name, "_trans.txt");


file.open(file_name);

if (!file.is_open()) {

cout << "트랜잭션 파일 열기 실패!" << endl;

}


cout << "트랜잭션 파일 : " << file_name;


while (!file.eof()) {

TRANSACTION tmp_data;

file >> tmp_data.mode;

file >> tmp_data.student.id;

file >> tmp_data.student.name;

file >> tmp_data.student.address;

file >> tmp_data.student.no_of_courses;


if (tmp_data.student.no_of_courses >= 1) {

file >> tmp_data.student.course[0].dept;

file >> tmp_data.student.course[0].course_name;

file >> tmp_data.student.course[0].prof_id;

file >> tmp_data.student.course[0].credit;

}


if (tmp_data.student.no_of_courses == 2) {

file >> tmp_data.student.course[1].dept;

file >> tmp_data.student.course[1].course_name;

file >> tmp_data.student.course[1].prof_id;

file >> tmp_data.student.course[1].credit;

}


if (tmp_data.mode == 'I') {

trans_insert(tmp_data.student);

}

else if (tmp_data.mode == 'D') {

trans_delete(tmp_data.student);

}

else if (tmp_data.mode == 'C') {

trans_correct(tmp_data.student);

}

}


file.close();


i++;

}


sort(students.begin(), students.end(), id_compare);

write_file();

}



//트랜잭션 추가

void trans_insert(STUDENT data) {

int i = 0;

int cnt = 0;


for (i = 0; i < students.size(); i++) {

if (students[i].id == data.id) {

cnt++;

}

}


if (cnt == 0) {

students.push_back(data);

cout << "[INSERT SUCCESS]" << endl;

} else {

cout << "[INSERT FAIL] 이미존재하는 학생입니다." << endl;

}

}


//트랜잭션 삭제

void trans_delete(STUDENT data) {

int i = 0;

int flag = 0;


for (i = 0; i < students.size(); i++) {

if (students[i].id == data.id) {

students.erase(students.begin() + i);

flag = 1;

break;

}

}


if (flag == 1) {

cout << "[DELETE SUCCESS]" << endl;

} else {

cout << "[DELETE FAIL] 존재하지 않는 학생입니다." << endl;

}

}


//트랜잭션 수정

void trans_correct(STUDENT data) {

int i = 0;

int flag = 0;


for (i = 0; i < students.size(); i++) {

if (students[i].id == data.id) {

students.erase(students.begin() + i);

students.push_back(data);

flag = 1;

break;

}

}


if (flag == 1) {

cout << "[CORRECT SUCCESS]" << endl;

}

else {

cout << "[CORRECT FAIL] 존재하지 않는 학생입니다." << endl;

}

}


//마스터파일에 저장

void write_file() {

ofstream outfile;

int i;


outfile.open("student_list.txt", ios::trunc);


for (i = 0; i < students.size(); i++) {

outfile << students[i].id << '\t';

outfile << students[i].name << '\t';

outfile << students[i].address << '\t';

outfile << students[i].no_of_courses;


if (students[i].no_of_courses >= 1) {

outfile << '\t' << students[i].course[0].dept << '\t';

outfile << students[i].course[0].course_name << '\t';

outfile << students[i].course[0].prof_id << '\t';

outfile << students[i].course[0].credit;

}


if (students[i].no_of_courses == 2) {

outfile << '\t' << students[i].course[1].dept << '\t';

outfile << students[i].course[1].course_name << '\t';

outfile << students[i].course[1].prof_id << '\t';

outfile << students[i].course[1].credit;

}


if (i != students.size() - 1) {

outfile << '\n';

}

}

outfile.close();

cout << "마스터 파일에 저장 완료!" << endl;

}


//정렬을 위한 비교 함수

bool id_compare(STUDENT a, STUDENT b)

{

return a.id < b.id;

}

갑자기 android studio 에서 에러가 발생했다


FILE 메뉴의 project structure 메뉴를 클릭했는데 에러가 발생하면서 

실행도 안되고


오후 3:33:32 IllegalArgumentException: Multiple entries with same key: Google Inc.:

Google APIs (x86 System Image):19=Google APIs (x86 System Image) (API 19) and 

Google Inc.:Google APIs (x86 System Image):19=Google APIs (x86 System Image) (API 19)


이런 에러를 띄웠다


//////////////////////////////////////////////////////


sdk 19 를 지웠다가 다시 설치하니 정상 작동되었다 ㅡㅡ;;


다시 설치안하고 지우기만해도 정상 작동된다...

약 60개의 버튼이 필요해서 

버튼을 만들고 각각 findviewbyId를 하고 onclickListener를 주려고 생각하고 

노가다로 막 만들던 중 배열을 써서 하면 편하겠다고 생각하여 다시 해보았다.



/////////////////////////////////////////////////////////////


private Button[][] btnTime = null;
///////////////////////////////////

btnTime = new Button[5][11];
int[][] btnId = { {R.id.btn_mon_1, R.id.btn_mon_2, R.id.btn_mon_3, R.id.btn_mon...... },

    {생략},

생략

}


for(int i = 0; i < 5; i++){
for(int j = 0; j < 11; j++){
this.btnTime[i][j] = (Button) findViewById(btnId[i][j]);
}
}

for(int i = 0; i < 5; i++){
for(int j = 0; j < 11; j++){
this.btnTime[i][j].setOnClickListener(btnListener);
}
}
///////////////////////////////////////////////
private View.OnClickListener btnListener = new View.OnClickListener() {

@Override
public void onClick(View v) {

for(int i = 0; i < 5; i++){
for(int j = 0; j < 11; j++){
if(v.getId() == btnTime[i][j].getId()) {
btnTime[i][j].setText(i + " " + j);
}
}
}
}
};

////////////////////////////////////////////


R.id 들을 int배열에 담고 마찬가지로 button도 배열로 담아놓은뒤에

반복문을 이용해 findviewbyid를 해주고

클릭 리스너도 마찬가지로 반복문을 이용해 set해줍니다

다음지도를 사용하려고 sdk를 다운받아 app에 넣고

구현하고 있는데 


맵의 중심점을 변경하려고 다음지도에서 해당 위치의 좌표를 구하려고 했는데

찾을 수 없었다. (옛날에는 지원해줬다는데 좌표보여주는 기능을 없앴다고 한다...)


그래서 찾은 방법은 구글지도에서 해당 위치를 검색해서

거기서 나온 좌표값을 이용하면 되길래 그렇게 사용하고 있다.


////////////////////////////////////////////////////////////////////


구글지도에서 좌표찾는 방법 = http://isntyet.tistory.com/28



위에서 찾은 좌표를 아래와 같이 적용시키면 된다


// 중심점 변경
mapView.setMapCenterPoint(MapPoint.mapPointWithGeoCoord(37.53737528, 127.00557633), true);


////////////////////////////////////////////////////////////////////////

추가


좌표를 바로 보여주는 사이트

http://mygeoposition.com/

+ Recent posts