Android

될 때까지 안드로이드 정리 (오준석의 생존코딩) 1

 

  1. 2장 첫 번째 앱 만들기, 3장 뷰와 뷰그룹
  2. 5장 레이아웃: 화면에 뷰를 수 놓는 방법
  3. 6장 안드로이드는 액티비티로부터
  4. 7장 인텐트와 인텐트 필터
  5. 8장 UpNavigation과 메뉴 구현하기
  6. 9장 웹뷰 웹 페이지 표기하기
  7. 10장 화면 제약을 극복하는 방법 – ListView
  8. 11장 기기에 데이터 저장하기 SharedPreference
  9. 12장 액티비티 생명주기
  10. 13장 프래그먼트

 


 

될 때까지 안드로이드 #1 [2장 첫 번째 앱 만들기, 3장 뷰와 뷰그룹]

 

  • activity_main.xml

 

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/edit_message"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:hint="@string/edit_message" />  // 나중에 국제화를 위해서 string 값을 리소스로 빼기
                                                // (2가지 방법: values/strings.xml 파일에 직접 입력, Extract string resource 메뉴 이용)
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="sendMessage"       // xml에서 직접 클릭 이벤트 추가
            android:text="@string/button_send" />

</LinearLayout>

 

 

MainActivity.java

 

public class MainActivity extends AppCompatActivity {
    public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE"; // 실수 방지 위해 변수 등록

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

    public void sendMessage(View view) {
        Intent intent = new Intent(this, DisplayMessageActivity.class);
        EditText editText = findViewById(R.id.edit_message);
        String message = editText.getText().toString();
        intent.putExtra(EXTRA_MESSAGE, message);
        startActivity(intent);
    }
}

 


 

activity_display_message.xml

 

<LinearLayout 
    android:id="@+id/activity_display_message"
    android:orientation="vertical">

</LinearLayout>

 

 

DisplayMessageActivity.java

 

public class DisplayMessageActivity extends AppCompatActivity {

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

        Intent intent = getIntent();
        String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);

        TextView textView = new TextView(this);  // 텍스트뷰를 코드로 추가
        textView.setTextSize(40);
        textView.setText(message);

        ViewGroup layout = findViewById(R.id.activity_display_message);
        layout.addView(textView);
    }
}

 


 

values/strings.xml

 

<resources>
    <string name="app_name">01_MyFirstApp</string>
    <string name="edit_message">메시지를 입력하세요.</string>
    <string name="button_send">보내기</string>
</resources>

 



 

 

될 때까지 안드로이드 #2 [5장 레이아웃: 화면에 뷰를 수 놓는 방법]

 

 


 

 

될 때까지 안드로이드 #3 [6장 안드로이드는 액티비티로부터]

 

 

activity_main.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/name_edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="이름" />

    <EditText
        android:id="@+id/age_edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="나이" />

    <Button
        android:id="@+id/submit_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="전송" />
</LinearLayout>

 

activity_second.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/message_edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffff00" />

    <Button
        android:id="@+id/result_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="결과 전달" />
</LinearLayout>

 

MainActivity.java

 

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    public static final int REQUEST_CODE = 1000;
    private EditText mNameEditText;
    private EditText mAgeEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 화면에 layout 표시
        setContentView(R.layout.activity_main);
        // 이름, 나이
        mNameEditText = (EditText) findViewById(R.id.name_edit);
        mAgeEditText = (EditText) findViewById(R.id.age_edit);
        // 버튼 이벤트 처리
        findViewById(R.id.submit_button).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // SecondActivity로 전환하겠다는 intent
        Intent intent = new Intent(this, SecondActivity.class);
        // 이름, 나이 가져와서 intent에 추가
        intent.putExtra("name", mNameEditText.getText().toString());
        intent.putExtra("age", mAgeEditText.getText().toString());
        // intent의 정보를 토대로 다른 Activity를 시작
        startActivityForResult(intent, REQUEST_CODE);
    }

    // SecondActivity에서 돌려받은 결과를 처리하는 콜백
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE
                && resultCode == RESULT_OK
                && data != null) {
            // 결과를 받음
            String result = data.getStringExtra("result");
            // 토스트 메시지 표시
            Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
        }
    }
}

 

 

SecondActivity.java

 

public class SecondActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView mMessageTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        // 넘어온 값을 화면에 표시
        Intent intent = getIntent();
        String name = intent.getStringExtra("name");
        String age = intent.getStringExtra("age");

        mMessageTextView = (TextView) findViewById(R.id.message_edit_text);
        mMessageTextView.setText(age + "살 " + name);
        // 버튼 이벤트 연결
        findViewById(R.id.result_button).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        intent.putExtra("result", mMessageTextView.getText().toString());
        // 결과 전달
        setResult(RESULT_OK, intent);
        // 이 액티비티 종료
        finish();
    }
}

 

 

 


 

될 때까지 안드로이드 #4 [7장 인텐트와 인텐트 필터]

 

<LinearLayout
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/phone_number_edit"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:hint="전화번호를 입력 해 주세요"
        android:inputType="phone" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="dialPhone"
        android:text="전화걸기" />
</LinearLayout>

 

public void dialPhone(View view) {
    EditText editText = (EditText) findViewById(R.id.phone_number_edit);
    dialPhoneNumber(editText.getText().toString());
}

// 전화걸기
public void dialPhoneNumber(String phoneNumber) {
    // 암시적 인텐트인 ACTION_DIAL을 설정
    Intent intent = new Intent(Intent.ACTION_DIAL);
    // URI 형태의 전화번호를 데이터로 설정
    intent.setData(Uri.parse("tel:" + phoneNumber));
    // 이러한 Intent를 처리할 수 있는 Activity를 찾는다면 액티비티를 시작
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

 

common intents
https://developer.android.com/guide/components/intents-common?hl=ko

 


 

될 때까지 안드로이드 #5 [8장 메뉴 구현하기] + UpNavigation

AndroidManifest.xml

 

<application
    <activity android:name=".ChildActivity" android:parentActivityName=".ParentActivity" />
    <activity android:name=".ParentActivity" android:parentActivityName=".MainActivity" />

        <!-- 4.0 이하
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".MainActivity" />
        -->

 

 

activity_main.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="moveParentActivity"
        android:text="ParentActivity로 이동" />

</LinearLayout>

 

 

activity_parent.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ParentActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="moveChildActivity"
        android:text="ChildActivity로 이동" />

</LinearLayout>

 

 

activity_child.xml

 

<LinearLayout>
비었음
</LinearLayout>

 

 

MainActivity.java

 

public void moveParentActivity(View view) {
    startActivity(new Intent(this, ParentActivity.class));
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_menu1:
            Toast.makeText(this, "첫 번째 메뉴", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.action_menu2:
            Toast.makeText(this, "두 번째 메뉴", Toast.LENGTH_SHORT).show();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

 

 

ParentActivity.java

 

public void moveChildActivity(View view) {
    startActivity(new Intent(this, ChildActivity.class));
}

 

 

ChildActivity.java

 

추가 없음

 

 

menu/main_menu.xml

 

<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/action_menu1"
        android:icon="@drawable/ic_launcher_foreground"   // title 보다 icon 이 우선
        android:title="Item"
        app:showAsAction="ifRoom" />  // 공간이 있다면 전면에 표시
    <item
        android:id="@+id/action_menu2"
        android:title="Item"
        app:showAsAction="never" />  // 전면에 표시 안함
</menu>

 

 


 

될 때까지 안드로이드 #6 [9장 웹뷰 웹 페이지 표기하기]

 

<uses-permission android:name="android.permission.INTERNET" />
android:usesCleartextTraffic="true"

 

 

MainActivity.java

 

public class MainActivity extends AppCompatActivity {

    private EditText mAddressEdit;
    private WebView myWebView;
    private Button mMoveButton;

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

        myWebView = (WebView) findViewById(R.id.web_view);

        // WebView의 설정
        WebSettings webSettings = myWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        myWebView.setWebViewClient(new WebViewClient());

        mAddressEdit = (EditText) findViewById(R.id.address_edit);
        mMoveButton = (Button) findViewById(R.id.move_button);

        // 소프트키보드의 돋보기를 클릭했을 때 이동 버튼을 클릭하도록 함
        mAddressEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                    mMoveButton.callOnClick();

                    // 키보드 내리기
                    InputMethodManager imm = (InputMethodManager)
                            getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                    return true;
                }
                return false;
            }
        });
    }

    public void onClick(View view) {
        String address = mAddressEdit.getText().toString();
        if (address.startsWith("http://") == false) {
            address = "http://" + address;
        }
        myWebView.loadUrl(address);
    }

    @Override
    public void onBackPressed() {
        if (myWebView.canGoBack()) {
            myWebView.goBack();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_back:
                // 뒤로 가기
                if (myWebView.canGoBack()) {
                    myWebView.goBack();
                }
                break;
            case R.id.action_forward:
                // 앞으로 가기
                if (myWebView.canGoForward()) {
                    myWebView.goForward();
                }
                break;
            case R.id.action_refresh:
                // 새로고침
                myWebView.reload();
                break;
        }
        return super.onOptionsItemSelected(item);
    }
}

 

activity_main.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/address_edit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="http://"
            android:imeOptions="actionSearch"  // 돋보기 버튼 나오게
            android:inputType="textUri"
            android:maxLines="1" />

        <Button
            android:id="@+id/move_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClick"
            android:visibility="gone"
            android:text="이동" />

    </LinearLayout>

    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

 

back, forward, refresh 아이콘 추가

drawable 폴더에서 New -> Vector Asset

 

 

menu_main.xml

 

<menu>
    <item
        android:id="@+id/action_back"
        android:icon="@drawable/ic_arrow_back"
        android:title="뒤로 가기"
        app:showAsAction="always" />
    <item
        android:id="@+id/action_forward"
        android:icon="@drawable/ic_arrow_forward"
        android:title="앞으로 가기"
        app:showAsAction="always" />
    <item
        android:id="@+id/action_refresh"
        android:icon="@drawable/ic_refresh"
        android:title="새로고침"
        app:showAsAction="always" />
</menu>

 

 


 

될 때까지 안드로이드 #7 [10장 화면 제약을 극복하는 방법 – ListView ]

 

 

ScrollView 예제

 

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

        <!-- 스크롤뷰는 반드시 하나의 자식만 가질 수 있음 -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                android:textSize="100dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                android:textSize="100dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                android:textSize="100dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                android:textSize="100dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                android:textSize="100dp" />
        </LinearLayout>
    </ScrollView>

</LinearLayout>

 

 

ListView 예제 (안드로이드 기본 제공 레이아웃 사용 : android.R.layout.simple_list_item_1)

 

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 

public class MainActivity extends AppCompatActivity {

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

        ArrayList<String> data = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            data.add("data " + i);
        }

        // 어댑터
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, data);
        
        // 뷰 (리스트뷰에 어댑터를 설정하면 어댑터가 데이터를 표시)
        ListView listView = findViewById(R.id.list_view);
        listView.setAdapter(adapter);

        // 클릭
       listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                Toast.makeText(MainActivity.this, position + " 번째 아이템 선택", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

 


 

ListView Custom Adapter 최종 예제

 

 

activity_main.xml

 

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 

item_weather.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/weather_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@mipmap/ic_launcher" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="vertical"
        android:padding="8dp">

        <TextView
            android:id="@+id/city_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="도시명"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/temp_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:gravity="end"
            android:text="기온" />

    </LinearLayout>

</LinearLayout>

 

 

MainActivity.java

 

public class MainActivity extends AppCompatActivity {

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

        ArrayList<Weather> data = new ArrayList<>();
        data.add(new Weather("수원", "25도", "맑음"));
        data.add(new Weather("서울", "26도", "비"));
        data.add(new Weather("안양", "24도", "구름"));
        data.add(new Weather("부산", "29도", "구름"));
        data.add(new Weather("인천", "23도", "맑음"));
        data.add(new Weather("대구", "28도", "비"));
        data.add(new Weather("용인", "25도", "비"));
        data.add(new Weather("수원", "25도", "맑음"));
        data.add(new Weather("서울", "26도", "비"));
        data.add(new Weather("안양", "24도", "구름"));
        data.add(new Weather("부산", "29도", "구름"));
        data.add(new Weather("인천", "23도", "맑음"));
        data.add(new Weather("대구", "28도", "비"));
        data.add(new Weather("용인", "25도", "비"));

        MyFirstAdapter adapter = new MyFirstAdapter(data);
        
        // 뷰 (리스트뷰에 어댑터를 설정하면 어댑터가 데이터를 표시)
        ListView listView = findViewById(R.id.list_view);
        listView.setAdapter(adapter);

        // 클릭
       listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                Toast.makeText(MainActivity.this, position + " 번째 아이템 선택", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

 

 

MyFirstAdapter.java

 

public class MyFirstAdapter extends BaseAdapter {
    private List<Weather> mData;
    private Map<String, Integer> mWeatherImageMap;

    public MyFirstAdapter(List<Weather> data) {
        mData = data;

        mWeatherImageMap = new HashMap<>();
        mWeatherImageMap.put("맑음", R.drawable.sunny);
        mWeatherImageMap.put("폭설", R.drawable.blizzard);
        mWeatherImageMap.put("구름", R.drawable.cloudy);
        mWeatherImageMap.put("비", R.drawable.rainy);
        mWeatherImageMap.put("눈", R.drawable.snow);
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int i) {
        return mData.get(i);
    }

    // 데이터 베이스 커서 관련해서 쓰이지만 평소에는 그대로 i를 넘겨줌
    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        // 계속 뷰의 레이아웃을 인플레이트 하는 것은 비용이 많이 든다. 그래서 재사용을 한다.
        if (convertView == null) {  // 처음에는 null
            holder = new ViewHolder();
            convertView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item_weather, parent, false);

            // 날씨, 도시, 기온 View
            ImageView weatherImage = (ImageView) convertView.findViewById(R.id.weather_image);
            TextView cityText = (TextView) convertView.findViewById(R.id.city_text);
            TextView tempText = (TextView) convertView.findViewById(R.id.city_text);

            holder.weatherImage = weatherImage;
            holder.cityText = cityText;
            holder.tempText = tempText;

            convertView.setTag(holder);
        } else {  // 재사용될 때는 null 아님
            holder = (ViewHolder) convertView.getTag();
        }

        Weather weather = mData.get(position);

        holder.cityText.setText(weather.getCity());
        holder.tempText.setText(weather.getTemp());
        holder.weatherImage.setImageResource(mWeatherImageMap.get(weather.getWeather()));

        return convertView;
    }

    static class ViewHolder {
        ImageView weatherImage;
        TextView cityText;
        TextView tempText;
    }
}

 

 

Weather.java

 

public class Weather {
    private String city;        // 도시명
    private String temp;        // 기온
    private String weather;     // 날씨 (맑음, 비, 구름, 눈)

    public Weather(String city, String temp, String weather) {
        this.city = city;
        this.temp = temp;
        this.weather = weather;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getTemp() {
        return temp;
    }

    public void setTemp(String temp) {
        this.temp = temp;
    }

    public String getWeather() {
        return weather;
    }

    public void setWeather(String weather) {
        this.weather = weather;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Weather{");
        sb.append("city='").append(city).append('\'');
        sb.append(", temp='").append(temp).append('\'');
        sb.append(", weather='").append(weather).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

 

 

리스트뷰를 그리드뷰로 바꾸기

 

<GridView
    android:numColumns="2"
    android:id="@+id/list_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

 

GridView listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);

 

 


 

될 때까지 안드로이드 #8 [11장 기기에 데이터 저장하기 SharedPreference]

 

activity_main.xml

 

<LinearLayout
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/shortcut_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="#ff00ff"
        android:onClick="onImageClicked" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onButtonClicked"
        android:text="바로가기 추가" />

</LinearLayout>

 

 

item_app.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/icon_image"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/app_name_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginStart="8dp"
        android:text="앱 이름"
        android:textSize="24sp" />

</LinearLayout>

 

 

activity_app_list.xml

 

<RelativeLayout
    android:id="@+id/activity_app_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/item_app" />

</RelativeLayout>

 

 

AppInfoAdapter.java

 

public class AppInfoAdapter extends BaseAdapter {
    private List<ApplicationInfo> mInfos;

    public AppInfoAdapter(List<ApplicationInfo> data) {
        this.mInfos = data;
    }

    @Override
    public int getCount() {
        return mInfos.size();
    }

    @Override
    public Object getItem(int i) {
        return mInfos.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();

            convertView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.item_app, parent, false);
            holder.imageView = (ImageView) convertView.findViewById(R.id.icon_image);
            holder.textView = (TextView) convertView.findViewById(R.id.app_name_text);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        // 앱 정보
        ApplicationInfo info = mInfos.get(position);

        // 앱 아이콘
        Drawable icon = info.loadIcon(parent.getContext().getPackageManager());
        holder.imageView.setImageDrawable(icon);

        // 앱 이름
        String name =
                String.valueOf(info.loadLabel(parent.getContext().getPackageManager()));
        holder.textView.setText(name);

        return convertView;
    }

    // 뷰 홀더 패턴을 위한 홀더 클래스
    private static class ViewHolder {
        ImageView imageView;
        TextView textView;
    }
}

 

 

AppListActivity.java

 

public class AppListActivity extends AppCompatActivity {

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

        ListView listView = (ListView) findViewById(R.id.list_view);

        // 기기에 설치된 모든 앱 목록
        PackageManager pm = getPackageManager();
        List<ApplicationInfo> infos =
                pm.getInstalledApplications(PackageManager.GET_META_DATA);

        AppInfoAdapter adapter = new AppInfoAdapter(infos);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ApplicationInfo info = (ApplicationInfo)
                        (parent.getAdapter()).getItem(position);

                Intent intent = new Intent();
                intent.putExtra("info", info);

                setResult(RESULT_OK, intent);
                finish();
            }
        });
    }
}

 

 

MainActivity.java

 

public class MainActivity extends AppCompatActivity {
    public static final int REQUEST_CODE = 1000;
    private ImageView mShortcut;


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

        mShortcut = (ImageView) findViewById(R.id.shortcut_image);

        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        // 저장된 shortcut 값을 얻음. 만약 저장된 값이 없을 경우 기본값으로 null 반환
        String packageName = preferences.getString("shortcut", null);

        if (packageName != null) {
            try {
                Drawable icon = getPackageManager().getApplicationIcon(packageName);
                // 아이콘을 이미지뷰에 표시
                mShortcut.setImageDrawable(icon);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CODE && resultCode == RESULT_OK && data != null) {
            // AppListActivity.java로부터 넘겨받은 ApplicationInfo 객체
            // Pacelable 객체를 받기 위해 getParcelableExtra()로 얻음
            ApplicationInfo info = data.getParcelableExtra("info");

            // loadIcon()에 PackageManager를 넘겨주면 아이콘을 Drawable로 얻을 수 있음
            Drawable icon = info.loadIcon(getPackageManager());

            // 기본 SharedPreferences 환경을 얻음
            SharedPreferences preferences =
                    PreferenceManager.getDefaultSharedPreferences(this);
            // SharedPrefences를 수정하기 위한 객체를 얻음
            SharedPreferences.Editor edit = preferences.edit();
            // info 객체로 packageName을 얻고, shortcut 키와 함께 프리퍼런스에 저장
            edit.putString("shortcut", info.packageName);
            // 변경사항 적용
            edit.apply();

            mShortcut.setImageDrawable(icon);
        }
    }

    public void onButtonClicked(View view) {
        Intent intent = new Intent(this, AppListActivity.class);
        startActivityForResult(intent, REQUEST_CODE);
    }


    public void onImageClicked(View view) {
        // 클릭된 이미지뷰에서 Drawable 객체 얻음
        ImageView imageView = (ImageView) view;
        Drawable drawable = imageView.getDrawable();

        if (drawable != null) {
            // 프리퍼런스에 shortcut 키로 저장된 패키지명을 가져옴
            SharedPreferences preferences =
                    PreferenceManager.getDefaultSharedPreferences(this);
            String packageName = preferences.getString("shortcut", null);

            if (packageName != null) {
                // 이 패키지를 실행할 수 있는 인텐트를 얻어서 액티비티 시작
                Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
                startActivity(intent);
            }
        }
    }

    @Override
    public void onBackPressed() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("종료 확인");
        builder.setMessage("정말로 종료하시겠습니까?");
        builder.setPositiveButton("확인", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                finish();
            }
        });

        builder.setNegativeButton("취소", null);
        builder.show();
    }
}

 

BACK 버튼 눌렀을 때 DialogFragment 이용해서 창 띄우기

 

MainActivity.java

 

@Override
public void onBackPressed() {
    ExitDialogFragment fragment = new ExitDialogFragment();
    fragment.show(getSupportFragmentManager(), "exit");
}

 

ExitDialogFragment.java

 

public class ExitDialogFragment extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // AlertDialog 빌더 클래스를 이용해서 다이얼로그를 생성
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("종료 확인");
        builder.setMessage("정말로 종료하시겠습니까?");
        builder.setPositiveButton("확인", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 종료 처리
                getActivity().finish();
            }
        });
        builder.setNegativeButton("취소", null);

        // 생성된 다이얼로그를 반환함
        return builder.create();
    }
}

 

 


 

될 때까지 안드로이드 #9 [12장 액티비티 생명주기]

 

AndroidManifest.xml 에서 android:screenOrientation=”landscape” 화면을 고정한다하더라도 상태 정보를 저장해라.

 

<LinearLayout
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/level_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="레벨 : 0" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onLevelUp"
        android:text="레벨 증가" />

    <TextView
        android:id="@+id/score_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="점수 : 0" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onScoreUp"
        android:text="점수 증가" />

</LinearLayout>

 

 

public class MainActivity extends AppCompatActivity {
    static final String STATE_SCORE = "playerScore";
    static final String STATE_LEVEL = "playerLevel";

    private TextView mLevelText;
    private TextView mScoreText;

    private int mLevel = 0;
    private int mScore = 0;

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

        mLevelText = (TextView) findViewById(R.id.level_text);
        mScoreText = (TextView) findViewById(R.id.score_text);

        if (savedInstanceState == null) {
            // 초기화 할 코드
        } else {
            // 상태 복원
            mLevel = savedInstanceState.getInt(STATE_LEVEL);
            mScore = savedInstanceState.getInt(STATE_SCORE);
            mLevelText.setText("레벨 : " + mLevel);
            mScoreText.setText("점수 : " + mScore);
        }

    }

//    상태 복원을 위한 또 다른 방법
//    @Override
//    protected void onRestoreInstanceState(Bundle savedInstanceState) {
//        // EditText 등의 복원을 위해 항상 호출 해야 함
//        super.onRestoreInstanceState(savedInstanceState);
//
//        // 상태 복원
//        mLevel = savedInstanceState.getInt(STATE_LEVEL);
//        mScore = savedInstanceState.getInt(STATE_SCORE);
//        mLevelText.setText("레벨 : " + mLevel);
//        mScoreText.setText("점수 : " + mScore);
//    }


    public void onLevelUp(View view) {
        mLevel++;
        mLevelText.setText("레벨 : " + mLevel);
    }

    public void onScoreUp(View view) {
        mScore += 100;
        mScoreText.setText("점수 : " + mScore);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        // 상태 저장
        outState.putInt(STATE_SCORE, mScore);
        outState.putInt(STATE_LEVEL, mLevel);

        // 항상 슈퍼클래스의 메서드를 호출해야 합니다
        super.onSaveInstanceState(outState);
    }


}

 

 


 

될 때까지 안드로이드 #10 [13장 프래그먼트]

 

# 프래그먼트끼리 통신을 할 수 없으므로 콜백 인터페이스를 이용한다 : 프래그먼트1(콜백) -> 액티비티(콜백) -> 프래그먼트2

 

activity_main.xml

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/fragment_color_list"
        android:name="com.example.myfragmentapplication.ColorListFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/fragment_color"
        android:name="com.example.myfragmentapplication.ColorFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

 

 

ColorFragment.java

 

public class ColorFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return new View(getActivity());
    }

    public void setColor(int color) {
        getView().setBackgroundColor(color);
    }
}

onCreateView() : 뷰 생성 작업
onViewCreated() : 뷰 생성 이후의 연결 작업

 

ColorListFragment.java

 

public class ColorListFragment extends ListFragment {

    private OnColorSelectedListener mListener;

    interface OnColorSelectedListener {
        void onColorSelected(int color);
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        try {
            mListener = (OnColorSelectedListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(((Activity) context).getLocalClassName() + " 는 OnColorSelectedListener 를 구현해야 합니다.");
        }
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        List<String> colorList = Arrays.asList("Red", "Green", "Blue");
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, colorList);
        setListAdapter(adapter);
    }

    @Override
    public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) {
        ArrayAdapter<String> adapter = (ArrayAdapter<String>) l.getAdapter();
        // or ArrayAdapter<String> adapter = (ArrayAdapter<String>) getListAdapter();

        String colorString = adapter.getItem(position);
        int color = Color.RED;

        switch (colorString) {
            case "Red":
                color = Color.RED;
                break;
            case "Green":
                color = Color.GREEN;
                break;
            case "Blue":
                color = Color.BLUE;
                break;
        }

        if (mListener != null) {
            mListener.onColorSelected(color);
        }
    }
}

 

 

MainActivity.java

 

public class MainActivity extends AppCompatActivity implements ColorListFragment.OnColorSelectedListener {

    private ColorFragment mColorFragment;

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

        mColorFragment = (ColorFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_color);
    }

    @Override
    public void onColorSelected(int color) {
        mColorFragment.setColor(color);
    }
}

 

랜덤한 배경색을 가진 프래그먼트를 생성 예제

 

activity_main.xml

 

<FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1" >

    <fragment
        android:id="@+id/color_fragment"
        android:name="com.example.myfragmentapplication.ColorFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="change"
    android:text="교체" />

 

 

MainActivity.java

 

public void change(View view) {
    ColorFragment fragment = new ColorFragment();

    int red = new Random().nextInt(256);
    int green = new Random().nextInt(256);
    int blue = new Random().nextInt(256);

    fragment.setColor(Color.rgb(red, green, blue));

    getSupportFragmentManager().beginTransaction()
            .replace(R.id.container, fragment)
            .commit();
}

 

 

ColorFragment.java

 

private int color;

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    view.setBackgroundColor(color);
}

public void setColor(int color) {
    this.color = color;
}

 

 

 

 


 

될 때까지 안드로이드 (오준석의 생존코딩) 유튜브 강의
https://www.youtube.com/watch?v=euTtMnN-TgI&list=PLxTmPHxRH3VWTd-8KB67Itegihkl4SVKe&index=2

 

될 때까지 안드로이드 (오준석의 생존코딩) 깃헙
https://github.com/junsuk5/android-first-book

 

될 때까지 안드로이드 소스 다운로드
android-first-book-master.zip

 

Related posts

Leave a Comment