이제 결과를 받아왔으니

적절하게 꾸며야지


27개의 Todo가 있다.


<!--TODO (1) Add a string stating that an error has occurred-->

strings.xml 부터 error 발생 시 보여줄 message 추가

<resources>
    <string name="app_name">GithubSearch</string>

    <string name="search">Search</string>

    <!--TODO (1) Add a string stating that an error has occurred-->
    <string name="error_message">
        Failed to get results. Please try again.
    </string>
</resources>


<!--TODO (2) Wrap the ScrollView in a FrameLayout-->
<!--TODO (3) Make the width and height of the FrameLayout match_parent-->
activity_main.xml 에 scrollview를 FrameLayout으로 감싸준다.

    <!--TODO (2) Wrap the ScrollView in a FrameLayout-->
    <!--TODO (3) Make the width and height of the FrameLayout match_parent-->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp">
            <TextView
                android:id="@+id/tv_github_search_results_json"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Make a search!"
                android:textSize="18sp" />
        </ScrollView>
    </FrameLayout> 


<!--TODO (4) Add a TextView to display an error message-->
<!--TODO (5) Set the text size to 22sp-->
<!--TODO (6) Give the TextView an id of @+id/tv_error_message_display-->
<!--TODO (7) Set the layout_height and layout_width to wrap_content-->
<!--TODO (8) Add 16dp of padding to the error display -->
<!--TODO (9) Use your strings.xml error message to set the text for the error message-->
<!--TODO (10) Set the visibility of the view to invisible-->
<!--TODO (11) Make this TextView a child of the FrameLayout that you added above-->

error message를 화면에 보여줄 수 있도록 Textview를 추가한다.

        <TextView
            android:id="@+id/tv_error_message_display"
            android:textSize="22sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="@string/error_message"
            android:visibility="invisible" /> 


<!--TODO (18) Add a ProgressBar to indicate loading to your users-->
<!--TODO (19) Give the ProgressBar an id of @+id/pb_loading_indicator-->
<!--TODO (20) Set the layout_height and layout_width to 42dp-->
<!--TODO (21) Set the layout_gravity to center-->
<!--TODO (22) Set the visibility of the ProgressBar to invisible-->
<!--TODO (23) Make this ProgressBar a child of the FrameLayout the you added above-->

처리되는 동안 표시 될 Progressbar를 추가한다.

        <ProgressBar
            android:id="@+id/pb_loading_indicator"
            android:layout_height="42dp"
            android:layout_width="42dp"
            android:layout_gravity="center"
            android:visibility="invisible" /> 


MainActivity를 수정한다.

순서상으로는 12(TextView 추가) 후 24(Progressbar 추가) 이나 xml을 먼저 정의 해 놓은 다음 처리했다.

// TODO (12) Create a variable to store a reference to the error message TextView
// TODO (24) Create a ProgressBar variable to store a reference to the ProgressBar

import android.widget.ProgressBar;
...
    // TODO (12) Create a variable to store a reference to the error message TextView
    private TextView mErrorMessageDisplay;
    // TODO (24) Create a ProgressBar variable to store a reference to the ProgressBar
    private ProgressBar mLoadingIndicator; 


// TODO (13) Get a reference to the error TextView using findViewById
// TODO (25) Get a reference to the ProgressBar using findViewById

onCreate method에 xml값과 변수를 매핑시킨다.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSearchBoxEditText = (EditText) findViewById(R.id.et_search_box);
        mUrlDisplayTextView = (TextView) findViewById(R.id.tv_url_display);
        mSearchResultsTextView = (TextView) findViewById(R.id.tv_github_search_results_json);

        // TODO (13) Get a reference to the error TextView using findViewById
        mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message_display);
        // TODO (25) Get a reference to the ProgressBar using findViewById
        mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
    } 


// TODO (14) Create a method called showJsonDataView to show the data and hide the error
// TODO (15) Create a method called showErrorMessage to show the error and hide the data

jsonData를 보여줄 method 추가, errorMessage를 보여줄 method 추가

    // TODO (14) Create a method called showJsonDataView to show the data and hide the error
    private void showJsonDataView() {
        // First, make sure the error is invisible
        mErrorMessageDisplay.setVisibility(View.INVISIBLE);
        // Then, make sure the JSON data is visible
        mSearchResultsTextView.setVisibility(View.VISIBLE);
    }


    // TODO (15) Create a method called showErrorMessage to show the error and hide the data
    private void showErrorMessage() {
        // First, hide the currently visible data
        mSearchResultsTextView.setVisibility(View.INVISIBLE);
        // Then, show the error
        mErrorMessageDisplay.setVisibility(View.VISIBLE);
    } 


// TODO (16) Call showErrorMessage if the result is null in onPostExecute       
// TODO (17) Call showJsonDataView if we have valid, non-null results

inner class인 GithubQueryTask 의 onPostExecute에 결과를 보여주도록 추가

        @Override
        protected void onPostExecute(String githubSearchResults) {
            if (githubSearchResults != null && !githubSearchResults.equals("")) {
                // TODO (17) Call showJsonDataView if we have valid, non-null results
                showJsonDataView();
                mSearchResultsTextView.setText(githubSearchResults);
            } else {
                // TODO (16) Call showErrorMessage if the result is null in onPostExecute
                showErrorMessage();
            }
        } 


// TODO (26) Override onPreExecute to set the loading indicator to visible

inner class인 GithubQueryTask 의 onPreExecute 재정의(onPostExecute아님)

        // TODO (26) Override onPreExecute to set the loading indicator to visible
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            mLoadingIndicator.setVisibility(View.VISIBLE);
        } 


// TODO (27) As soon as the loading is complete, hide the loading indicator

loading이 끝나자마다 indicator를 숨기도록 처리

onPostExecute 의 최종 결과임

    @Override
    protected void onPostExecute(String githubSearchResults) {
        // TODO (27) As soon as the loading is complete, hide the loading indicator
        mLoadingIndicator.setVisibility(View.INVISIBLE);
       
        if (githubSearchResults != null && !githubSearchResults.equals("")) {
            // TODO (17) Call showJsonDataView if we have valid, non-null results
            showJsonDataView();
            mSearchResultsTextView.setText(githubSearchResults);
        } else {
            // TODO (16) Call showErrorMessage if the result is null in onPostExecute
            showErrorMessage();
        }
    } 



댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

이번에는 동기화를 진행하여 네트워크를 통한 조회결과를 가져오는 부분이다.


// TODO (1) Create a class called GithubQueryTask that extends AsyncTask<URL, Void, String>
// TODO (2) Override the doInBackground method to perform the query. Return the results. (Hint: You've already written the code to perform the query)
// TODO (3) Override onPostExecute to display the results in the TextView

MainActivity 에 inner class로 GithubQueryTask를 추가
GithubQueryTask의 doInBackground method에서 쿼리를 날리고 결과를 받는다.

GithubQueryTask의 onPostExecute method에서 가져온 결과를 TextView에 보여준다.


import android.os.AsyncTask;

...

     // TODO (1) Create a class called GithubQueryTask that extends AsyncTask<URL, Void, String>
    public class GithubQueryTask extends AsyncTask<URL, Void, String> {

        // TODO (2) Override the doInBackground method to perform the query. Return the results. (Hint: You've already written the code to perform the query)
        @Override
        protected String doInBackground(URL... params) {
            URL searchUrl = params[0];
            String githubSearchResults = null;
            try {
                githubSearchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return githubSearchResults;
        }


        // TODO (3) Override onPostExecute to display the results in the TextView
        @Override
        protected void onPostExecute(String githubSearchResults) {
            if (githubSearchResults != null && !githubSearchResults.equals("")) {
                mSearchResultsTextView.setText(githubSearchResults);
            }
        }
    }


// TODO (4) Create a new GithubQueryTask and call its execute method, passing in the url to query

makeGithubSearchQuery 에서 쿼리를 날릴 때 변경한 GithubQueryTask를 사용하도록 한다.(기존것은 주석처리)

//        String githubSearchResults = null;
//        try {
//            githubSearchResults = NetworkUtils.getResponseFromHttpUrl(githubSearchUrl);
//            mSearchResultsTextView.setText(githubSearchResults);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        // TODO (4) Create a new GithubQueryTask and call its execute method, passing in the url to query
        new GithubQueryTask().execute(githubSearchUrl); 


App을 실행시켜서 'queen'이라는 단어로 쿼리를 날리면

먼저 url을 화면에 보여주고 잠시 후에 쿼리 결과가 나타난다.


네트워크를 통한 요청을 했을 때 응답을 받을 때까지 대기하도록 해야하기 때문임.

응답받기전에 결과를 처리하려고 한 T02.04는 에러가 날 수 밖에 없음.

댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

이번에는 네트워크를 통하여

github 검색을 하는 것인데


이번 예제의 실행결과는 무조건 실패다.

solution project를 실행시켜도 app 에러가 난다.

다음예제인 T02.05에서 해결이 되는 것이니 TODO 설정을 제대로 한 뒤에 다음 강좌로 넘어가기 바란다.



<!--TODO (1) Add the INTERNET permission-->

AndroidManifest.xml 에 internet을 사용하는 권한 추가


// TODO (2) Call getResponseFromHttpUrl and display the results in mSearchResultsTextView
// TODO (3) Surround the call to getResponseFromHttpUrl with a try / catch block to catch an IOException

MainActivity의 makeGithubSearchQuery method 에서 쿼리조회를 하고 결과를 가져온다.

network을 사용할 때 오류가 날 수 있으니 IOException으로 감싸준다.

import java.io.IOException;

...

     private void makeGithubSearchQuery() {
        String githubQuery = mSearchBoxEditText.getText().toString();
        URL githubSearchUrl = NetworkUtils.buildUrl(githubQuery);
        mUrlDisplayTextView.setText(githubSearchUrl.toString());

        // TODO (2) Call getResponseFromHttpUrl and display the results in mSearchResultsTextView
        // TODO (3) Surround the call to getResponseFromHttpUrl with a try / catch block to catch an IOException
        String githubSearchResults = null;
        try {
            githubSearchResults = NetworkUtils.getResponseFromHttpUrl(githubSearchUrl);
            mSearchResultsTextView.setText(githubSearchResults);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


---

실행시켜보면 앱이 바로 종료된다.

Lotcat에서 확인해보면

 2019-01-13 13:22:41.295 3960-3960/com.example.android.datafrominternet E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.android.datafrominternet, PID: 3960
    android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1448)
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:102)
        at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
        at java.net.InetAddress.getAllByName(InetAddress.java:787)
        at com.android.okhttp.Dns$1.lookup(Dns.java:39)
        at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:175)
        at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:141)
        at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:83)
        at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
        at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
        at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:407)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:244)
        at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
        at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(Unknown Source:0)
        at com.example.android.datafrominternet.utilities.NetworkUtils.getResponseFromHttpUrl(NetworkUtils.java:76)
        at com.example.android.datafrominternet.MainActivity.makeGithubSearchQuery(MainActivity.java:63)
        at com.example.android.datafrominternet.MainActivity.onOptionsItemSelected(MainActivity.java:80)
        at android.app.Activity.onMenuItemSelected(Activity.java:3435)


로그는 거꾸 읽어가는 것임.

먼저 onMenuItemSelect에서 버튼클릭이 있어났고

onOptionsItemSelectd 에서 어떤버튼인지 확인한 다음.

makeGithubsearchQuery method 에서 NetworkUtils를 호출한다.

그 와중에 getInputStream 에서 최종 에러가 난 것이다.


위 에러가 나면 다음강좌로 넘어간다.

network 사용시에는 동기화라는 것이 필요한데 설정이 되어있지 않아서 발생하는 것임.

댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

이번에는 network 을 살펴본다



// TODO (1) Fill in this method to build the proper Github query URL

1. buildUrl method를 완성시킨다.

utilities 라는 package를 새로 생성.  NetworkUtils 라는 class도 생성

AS-IS : 껍데기만 있음

    public static URL buildUrl(String githubSearchQuery) {
        // TODO (1) Fill in this method to build the proper Github query URL
        return null;
    } 

-> TO-BE : 동작

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;

import java.net.MalformedURLException;
import java.net.URL;

final static String GITHUB_BASE_URL = "https://api.github.com/search/repositories";

final static String PARAM_QUERY = "q";

final static String PARAM_SORT = "sort";

final static String sortBy = "stars";

    public static URL buildUrl(String githubSearchQuery) {
        // COMPLETED (1) Fill in this method to build the proper Github query URL
        Uri builtUri = Uri.parse(GITHUB_BASE_URL).buildUpon()
                .appendQueryParameter(PARAM_QUERY, githubSearchQuery)
                .appendQueryParameter(PARAM_SORT, sortBy)
                .build();

        URL url = null;
        try {
            url = new URL(builtUri.toString());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        return url;
    } 


// TODO (2) Create a method called makeGithubSearchQuery
// TODO (3) Within this method, build the URL with the text from the EditText and set the built URL to the TextView
MainActivity 에서 method 추가한 뒤에 내용을 넣는다.

사용자가 입력한 EditText의 내용으로 github에 조회할 전체경로를 TextView에 보여준다.

    private void makeGithubSearchQuery() {
        String githubQuery = mSearchBoxEditText.getText().toString();
        URL githubSearchUrl = NetworkUtils.buildUrl(githubQuery);
        mUrlDisplayTextView.setText(githubSearchUrl.toString());
    } 


// TODO (4) Remove the Toast message when the search menu item is clicked
// TODO (5) Call makeGithubSearchQuery when the search menu item is clicked

클릭버튼 동작유무를 확인하기 위한 ToastMessage를 제거하고

makeGithubSearchQuery를 호출한다.

@Override
public boolean onOptionsItemSelected(MenuItem item){
    int itemThatWasClickedId = item.getItemId();

    if (itemThatWasClickedId == R.id.action_search) {
        // COMPLETED (4) Remove the Toast message when... is clicked
//            Context context = MainActivity.this;
//            String textToShow = "Search clicked";
//            Toast.makeText(context, textToShow, Toast.LENGTH_SHORT).show();


        // COMPLETED (5) Call makeGithubSearchQuery when... clicked
        makeGithubSearchQuery();

        return true;
    } 


앱을 실행시켜보면

queen이라는 단어 입력 후 Search버큰을 클릭하면

github로 날릴 조회쿼리가 표시된다.

아직 실제로 쿼리를 날린것이 아니므로 결과는 안나온다




댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

수영 중 부상

2019.01.11 14:59
화요일에 무릎이 까지는 부상(?)을 입었다

스타트 후 접영인데 깊숙히 들어가서 바닥까지 내려간 뒤 잠영으로 킥을 몇 번했는데
바닥 타일에 긁혔다. 양쪽 무릎 다 상처가 났는데

목요일 다시 같은 코스에서 또 깊숙히 들어가서 바닥을 쳤는데
무릎에 딱지가 생긴곳을 딱 때리면서
맞은데 또 맞듯이 순간적으로 고통이 꽤 컸다.
 일어나서 뒤에 오는 사람 비켜주자 옆레인 강사가 괜찮냐고 해서 그냥 부딪힌 거라고
반대쪽에 와서 잠시 쉬고
다리를 살짝 절며 걸어서 스타트 지점으로 온 다음 나머지 수영을 마무리했다
25미터 2번을 못채웠다.

딱지 생긴데가 다시까지면서 피가 좀 나데
샤워 끝나고 관리 아저씨에게 얘기해서 밴드하나 얻어 붙였다.

오늘은 방수밴드 붙이고 가야지

안빼먹고 완주하자~~

댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

첫번째로 Create Project하고 화면 껍데기는 만들었음

이번에는 메뉴를 추가하고 Click 됐는지 확인만 한다.


총 15개의 TODO


<!--TODO (1) Add a string resource called search with the title "Search"-->

app > res > values > strings.xml에 search 라는 단어 추가

<resources>
    <string name="app_name">GithubSearch</string>

    <!--TODO (1) Add a string resource called search with the title "Search"-->
    <string name="search">Search</string>
</resources>
 


// Do 2 - 7 in menu.xml

// TODO (2) Create a menu xml called 'main.xml' in the res->menu folder
// TODO (3) Add one menu item to your menu

메뉴는 기본 프로젝트 생성에서 만들어지지 않기 때문에 직접 만들어야 한다.


왼쪽 프로젝트의 app 에서 오른쪽 버튼 클릭 Android Resource File 클릭

팝업으로 나타난 New Resource File 에
file name은 main으로 하고

Resouce type 은 Menu로 선택한다.(다른것을 선택하면 다른 폴더에 생성 됨)

생성이 끝나면 res > menu > main.xml 파일이 생성되어 있다.

여기에 사용할 menu를 정의한다.




// TODO (4) Give the menu item an id of @+id/action_search
// TODO (5) Set the orderInCategory to 1
// TODO (6) Show this item if there is room (use app:showAsAction, not android:showAsAction)
// TODO (7) Set the title to the search string ("Search") from strings.xml

main.xml 에서 item을 추가

menu item에 id 설정

정렬 순서(order in category) 설정

show as action 설정

버튼 text=search 설정 : string.xml에 있는 값을 사용

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_search"
        android:orderInCategory="1"
        app:showAsAction="ifRoom"
        android:title="@string/search"/>

</menu> 


다음부터는 MainActivity.java에서


// TODO (8) Override onCreateOptionsMenu
   

onCreateOptionsMenu method를 추가(Override)

import android.view.Menu;

...

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    return true;


// TODO (9) Within onCreateOptionsMenu, use getMenuInflater().inflate to inflate the menu
// TODO (10) Return true to display your menu

그 안에서 추가한 item 설정

전체소스: TODO 8,9,10

onCreateOptionsMenu 가 return type이 boolean이기 때문에

return true 또는 false로 지정해야함.

TODO 10에서 return true;로 하면서 화면에 보이도록 한다고 설정한 것임.

// TODO (8) Override onCreateOptionsMenu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // TODO (9) Within onCreateOptionsMenu, use getMenuInflater().inflate to inflate the menu
    getMenuInflater().inflate(R.menu.main, menu);
    // TODO (10) Return true to display your menu
    return true;


메뉴를 추가했으면 해당 메뉴를 선택했을 때 어떻게 동작하는지 정의가 필요

// TODO (11) Override onOptionsItemSelected

onOptionsItemSelected method를 추가(Override)

import android.view.MenuItem;

...

@Override
public boolean onOptionsItemSelected(MenuItem item){
    return false;
}


onOptionsItemSelected 안에서 선택된 item의 id를 확인하고
search 면 임시로 toast message 표시.

toast message 표시할 때에는 반드시   .show() 를 사용해야 함.

// TODO (12) Within onOptionsItemSelected, get the ID of the item that was selected
// TODO (13) If the item's ID is R.id.action_search, show a Toast and return true to tell Android that you've handled this menu click
// TODO (14) Don't forgot to call .show() on your Toast
// TODO (15) If you do NOT handle the menu click, return super.onOptionsItemSelected to let Android handle the menu click

import android.content.Context;
import android.widget.Toast;

...

// TODO (11) Override onOptionsItemSelected
@Override
public boolean onOptionsItemSelected(MenuItem item){
    // TODO (12) Within onOptionsItemSelected, get the ID of the item that was selected
    int itemThatWasClickedId = item.getItemId();

    // TODO (13) If the item's ID is R.id.action_search, show a Toast and return true to tell Android that you've handled this menu click
    if (itemThatWasClickedId == R.id.action_search) {
        Context context = MainActivity.this;
        String textToShow = "Search clicked";
        // TODO (14) Don't forgot to call .show() on your Toast
        Toast.makeText(context, textToShow, Toast.LENGTH_SHORT).show();
        return true;
    }

    // TODO (15) If you do NOT handle the menu click, return super.onOptionsItemSelected to let Android handle the menu click
    return super.onOptionsItemSelected(item);
}



실행시켜보면

상단에 menu로 SEARCH 가 있고 그것을 클릭했을 때

toast message로 'Search clicked' 가 나타남.



댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

첫번째 App은 장난감 목록을 보여주는 것인데

ToyBox라는 class에 있는 것들을 보여주는 것이었다.


두번째 App : Github-Repo-Search

Github에 있는 project를 검색하여 해당 목록을 보여주는 것이다.

network통신 및 parsing 작업


Ex1에서는 프로젝트 생성이다.

T01 프로젝트와 같이 프로젝트 생성

예제 프로젝트의 TODO 를 Complete 하면 된다.

- activity_main.xml 에서 25개

- MainActivity.java 에서 6개

- build.gradle에서 1개

총 3개의 파일에 32개의 TODO가 있다.

먼저 activity_main.xml

<!--TODO (1) Change the ConstraintLayout to a LinearLayout-->
<!--TODO (2) Make the orientation vertical-->
<!--TODO (3) Give left, right, and top padding of 16dp-->
<!--TODO (4) Remove the line that declares the id, we don't need it-->
<!--TODO (5) Remove the xmlns:app declaration, we don't need that anymore-->

ConstraintLayout -> LinearLayout 로 바꾼다.

이때 LinearLayout은 한줄로 세우는 것이므로 가로로 세울지 세로로 세울지 지정해야한다

orientation=vertical 은 세로, horizontal은 가로

왼쪽,오른쪽,위,아래 여백 설정(16dp)

android:id=activity_main은 필요없으므로 제거

xmlns:app 도 필요없으므로

 <android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

...

</android.support.constraint.ConstraintLayout>

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"

    tools:context=".MainActivity">
</LinearLayout>

...

</LinearLayout>


<!--TODO (6) Delete this TextView-->

기본으로 정의 된 Hello World TextView를 제거한다.

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" /> 


<!--TODO (7) Add an EditText-->
<!--TODO (8) Give the EditText an id of @+id/et_search_box-->
<!--TODO (9) Set the text size to 22sp-->
<!--TODO (10) Set the width to match_parent and the height to wrap_content-->
<!--TODO (11) Provide a hint telling the user to enter a query and then click search-->

EditText를 추가하고

id 설정하고

text size=22sp

width, height 설정

hint 넣기 : edit text에 아무것도 입력이 안되었을 때 가이드하는 문장

<EditText
    android:id="@+id/et_search_box"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Enter a query, then click Search"
    android:textSize="22sp" /> 


<!--TODO (12) Add a TextView-->
<!--TODO (13) Give the TextView an id of @+id/tv_url_display-->
<!--TODO (14) Set the text size to 22sp-->
<!--TODO (15) Set the width to wrap_content and the height to wrap_content-->
<!--TODO (16) Give the TextView a top margin of 8dp-->
<!--TODO (17) Set the text to tell the user their search URL will show up here when they click search-->

TextView 추가

id 설정

text size=22sp

width, height

margin 설정

textview에 표시할 글자 'Click search and your URL will show up here!' 설정

<TextView
    android:id="@+id/tv_url_display"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:text="Click search and your URL will show up here!"
    android:textSize="22sp" /> 


<!--TODO (18) Add a ScrollView-->
<!--TODO (19) Set the width to match_parent and the height to wrap_content-->
<!--TODO (20) Set the top margin to 16dp-->

Scrollview 추가

width, height, margin 설정

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="16dp">
   
</ScrollView> 


<!--TODO (21) Within the ScrollView, add a TextView-->
<!--TODO (22) Give the TextView an id of @+id/tv_github_search_results_json-->
<!--TODO (23) Set the text size to 18sp-->
<!--TODO (24) Set the height and width to wrap_content-->
<!--TODO (25) Set the text to something that tells the user to make a search-->

ScrollView 안에 TextView 추가

id 설정

textsize=18

width, height 설정

textview에 표시할 글씨 'Make a Search!' 설정

(scrollView는 이미 추가했으므로 TextView만 ScrollView아래에 추가한다)

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="16dp">
    <TextView
        android:id="@+id/tv_github_search_results_json"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Make a search!"
        android:textSize="18sp" />

</ScrollView> 


여기까지 main_activity.xml


MainActivity.java에서 나머지 TODO

// TODO (26) Create an EditText variable called mSearchBoxEditText
// TODO (27) Create a TextView variable called mUrlDisplayTextView
// TODO (28) Create a TextView variable called mSearchResultsTextView

사용자 입력 EditText 변수 정의

조회된 내용 중 url 표시 TextView 변수 정의

조회결과 TextView 변수 정의

import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // TODO (26) Create an EditText variable called mSearchBoxEditText
    private EditText mSearchBoxEditText;
    // TODO (27) Create a TextView variable called mUrlDisplayTextView
    private TextView mUrlDisplayTextView;
    // TODO (28) Create a TextView variable called mSearchResultsTextView
    private TextView mSearchResultsTextView;

...   
}


// TODO (29) Use findViewById to get a reference to mSearchBoxEditText
// TODO (30) Use findViewById to get a reference to mUrlDisplayTextView
// TODO (31) Use findViewById to get a reference to mSearchResultsTextView

onCreate Method 안에서

editText 변수에 xml에 정의 된 EditText 연결

TextView 변수에 xml에 정의 된 TextView 연결


 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // TODO (29) Use findViewById to get a reference to mSearchBoxEditText
    mSearchBoxEditText = (EditText) findViewById(R.id.et_search_box);

    // TODO (30) Use findViewById to get a reference to mUrlDisplayTextView
    mUrlDisplayTextView = (TextView) findViewById(R.id.tv_url_display);

    // TODO (31) Use findViewById to get a reference to mSearchResultsTextView
    mSearchResultsTextView = (TextView) findViewById(R.id.tv_github_search_results_json);
}


마지막으로

settings.gradle 파일 수정

// TODO (32) Remove the ConstraintLayout dependency as we aren't using it for these simple projects


맨 처음에 ConstraintLayout 을 LinearLayout으로 바꿨음.

없애지 않아도 무관하나 깔끔하게 제거.

ConstraintLayout은 기본Layout이 아니라 android.support를 통해 제공되므로 불필요함.

자동으로 수정되어 include:app 만 있는 경우는 그냥 진행하면 됨.

원래는 setting.gradle에 아래와 같이 정의되어 있음.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:25.1.0'

    // TODO (32) Remove the ConstraintLayout dependency as we aren't using it for these simple projects
    compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'



모든 수정이 끝났으면 실행

필요한 항목만 만들어놓은 껍데기 이므로 실제 동작하지 않음.

조회버튼과 입력된 내용으로 검색하는 로직은 다음 프로젝트에서 계속...

댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

EX1 : 프로젝트 생성, Textview 추가

EX2 : TextView에 내용 넣기


ToyList를 보면 수 많은 장난감이 있으나 실제 보이는 장남감 갯수는 처음 몇 개 뿐이다.


화면길이를 넘어가기 때문인데

이 경우 ScrollView로 감싸주면 해결된다.


TODO 확인


<!--TODO (1) Add a ScrollView around the TextView so you can scroll through the list of toys-->

ScrollView로 TextView를 감싼다.

<ScrollView
        android:layout_width=""
        android:layout_height="">
        <TextView...>
</ScrollView>


<!--TODO (2) Make the width of the ScrollView match_parent and the height wrap_content-->

ScrollView내 속성을 width=match_parent, height=wrap_content 로 한다.


<ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">


전체 소스

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_toy_names"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:padding="16dp"
android:textSize="20sp" />
</ScrollView>
</FrameLayout>


실행해보면 Scroll이되어 모든 장난감 목록을 볼 수 있다.


댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

첫번째 프로젝트에서는 프로젝트 생성하고 layout을 변경했으니

두번째 프로젝트에서는 Toylist를 보여주는 것을 한다.


Excercise 에서 Todo 를 확인한다.

만들던 프로젝트에서 쭉 해도 되고

Excercise를 수정해도 된다.

만들던 프로젝트에는 Todo가 표시되지 않으니 알아서 선택.


MainActivity 에 ToDo1

    // TODO (1) Declare a TextView variable called mToysListTextView
    private TextView mToysListTextView;


activity_main.xml 에 ToDo2 tv_toy_names 추가

before

 after

 <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!"
    android:padding="16dp"
    android:textSize="20sp" />

 <TextView
    android:id="@+id/tv_toy_names"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:textSize="20sp" />


MainActivity 에 ToDo3

onCreate method 에서 Textview와 mToysListTextView 연결


// TODO (3) Use findViewById to get a reference to the TextView from the layout

mToysListTextView = (TextView) findViewById(R.id.tv_toy_names);


// TODO (4) Use the static ToyBox.getToyNames method and store the names in a String array

String[] toyNames = ToyBox.getToyNames();


그런데 Excercise에서 작업을 하면 문제가 없으나

기존 프로젝트에서 작업하는 경우에는 ToyBox class가 없으므로 Error가 난다.

ToyBox라는 class를 만들거나 복사해 온다.

package com.example.nobang.favoritetoys;

public final class ToyBox {

    public static String[] getToyNames() {
        return new String[] {
                "Red Toy Wagon",
                "Chemistry Set",
               
                "Squirt Guns",
                "Miniature Replica Animals Stuffed with Beads that you swore to your parents would be worth lots of money one day",
                "Creepy Gremlin Doll",
                "Neodymium-Magnet Toy"
        };
    }


에러가 없으면 다음 Todo

// TODO (5) Loop through each toy and append the name to the TextView (add \n for spacing)

for (String toyName : toyNames) {
    mToysListTextView.append(toyName + "\n\n\n");
}


ToyBox class에 있는 장난감이름들을 불러와서

TextView에 일렬로 쭉(for문으로) 붙이는 거다.



todo 3을 진행하지 않으면 mToysListTextView가 초기화되어있지 않기 떄문에 아래와 같이 에러가 난다.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.nobang.favoritetoys/com.example.nobang.favoritetoys.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.append(java.lang.CharSequence)' on a null object reference
 

MainActivity

- solution 프로젝트에는 TODO가 COMPLETED로 되어있음.

- todo를 진행했으면 COMPLETED로 바꿔주는 것이 좋음.

결과

"\n\n\n"으로 줄바꿈이 됨.


댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

안드로이드 빌드를 했을 때

'Your project path contains non-ASCII characters' 같은 에러가 나오며 안될 때가 있다.


Your project path contains non-ASCII characters. This will most likely cause the build to fail on Windows. Please move your project to a different directory. See http://b.android.com/95744 for details. This warning can be disabled by adding the line 'android.overridePathCheck=true' to gradle.properties file in the project directory.
Open File
 

Open File을 누르면 build.gradle 파일이 열리는데

프로젝트의 경로가 영어가 아닐 때 발생하는 에러다.

(project path is not english. ex. Korean)


gradle.properties 파일에  com.android.build.gradle.overridePathCheck=true 를 추가 한다.


그리고는 try again 하면 된다.

댓글을 달아주세요:: 네티켓은 기본, 스팸은 사절

BLOG main image
"그게 뭐 어쨌다는 거냐?" 늘 누가 나에게 나에대한 말을할 때면 이말을 기억해라. by nobang

카테고리

nobang이야기 (1694)
Life With Gopro (7)
Life With Mini (72)
Diary (934)
너 그거 아니(do you know) (131)
난 그래 (129)
속지말자 (9)
Project (34)
Poem (14)
Song (0)
Study (166)
Photo (113)
낙서장 (45)
일정 (0)
C.A.P.i (2)
PodCast (0)
nobang (27)
고한친구들 (4)
recieve (0)
History (0)
android_app (2)

최근에 받은 트랙백

Total : 537,959
Today : 67 Yesterday : 76