반응형

안드로이드 앱 프로그래밍 with 코틀린 11-5 뷰페이저2

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".OneFragment">
 
    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FF0000"
        android:gravity="center_horizontal|center_vertical"
        android:text="One Fragment" />
 
</FrameLayout>
 

 

fragment_one.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.example.myapplication
 
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
 
class OneFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_one, container, false)
    }
}
 

 

OneFragment.kt

같은 형태로 TextView 배경색만 바꿔서 TwoFragment, ThreeFragment도 만들어 준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<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">
 
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
 

 

activity_main.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.example.myapplication
 
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
 
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        val viewPager2: ViewPager2 = findViewById(R.id.viewpager)
        viewPager2.adapter = MyFragmentPagerAdapter(this)
 
        //viewPager2.orientation = ViewPager2.ORIENTATION_VERTICAL
        // 이 설정을 적용하면 스와이프 방향이 세로로 바뀐다.
    }
}
 
class MyFragmentPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
    val fragments: List<Fragment>
    init {
        fragments = listOf(OneFragment(), TwoFragment(), ThreeFragment())
        Log.d("Sean""Fragments size: ${fragments.size}")
    }
 
    override fun getItemCount(): Int {
        return fragments.size
    }
 
    override fun createFragment(position: Int): Fragment {
        return fragments[position]
    }
}
 

 

MainActivity.kt

 

실행 화면

 

반응형
Posted by J-sean
:

ViewPager2 뷰페이저2

Android 2023. 7. 11. 16:53 |
반응형

안드로이드 앱 프로그래밍 with 코틀린 11-5 뷰페이저2

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<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">
 
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
 

 

activity_main.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<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">
 
    <TextView
        android:id="@+id/itemPagerTextView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal|center_vertical"
        android:text="TextView" />
</LinearLayout>
 

 

item_main.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.myapplication
 
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
 
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        val data = mutableListOf<String>()
        for(i in 1..3){
            data.add("Item: $i")
        }
 
        val viewPager2: ViewPager2 = findViewById(R.id.viewpager)
        viewPager2.adapter = MyPagerAdapter(data)
    }
}
 
class MyPagerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val itemPagerTextView: TextView = itemView.findViewById(R.id.itemPagerTextView)
}
 
class MyPagerAdapter(private val itemList: MutableList<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>(){
    override fun getItemCount(): Int {
        return itemList.size
    }
 
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_main, parent, false)
        return MyPagerViewHolder(view)
    }
 
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        (holder as MyPagerViewHolder).itemPagerTextView.text = itemList[position]
        when (position % 3) {
            0 -> (holder as MyPagerViewHolder).itemPagerTextView.setBackgroundColor(Color.RED)
            1 -> (holder as MyPagerViewHolder).itemPagerTextView.setBackgroundColor(Color.BLUE)
            2 -> (holder as MyPagerViewHolder).itemPagerTextView.setBackgroundColor(Color.GREEN)
        }
    }
}
 

 

MainActivity.kt

 

실행 화면

 

반응형
Posted by J-sean
:
반응형

안드로이드 앱 프로그래밍 with 코틀린 11-4 리사이클러뷰

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<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">
 
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
 

 

activity_main.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/item_root"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
 
    <TextView
        android:id="@+id/item_data"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="TextView" />
</LinearLayout>
 

 

item_main.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.example.myapplication
 
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
 
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
 
        setContentView(R.layout.activity_main)
 
        val data = mutableListOf<String>()
        for(i in 1..10){
            data.add("Item: $i")
        }
 
        val recyclerView: RecyclerView = findViewById(R.id.recyclerview)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = MyAdapter(data)
        recyclerView.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
    }
}
 
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val textView: TextView = itemView.findViewById(R.id.item_data)
}
 
class MyAdapter(private val itemList: MutableList<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>(){
    override fun getItemCount(): Int {
        return itemList.size
    }
 
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_main, parent, false)
        return MyViewHolder(view)
    }
 
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        (holder as MyViewHolder).textView.text = itemList[position]
        (holder as MyViewHolder).textView.setOnClickListener {
            Log.d("Sean""Item clicked: $position")
        }
    }
}
 

 

Main_Activity.kt

 

실행 화면

 

반응형
Posted by J-sean
:
반응형

안드로이드 UI는 메인 스레드나 UI 스레드 외 다른 스레드에서 조작 할 수 없다. 다른 스레드에서 UI 조작 시 별다른 에러 없이 Virtual Device에서 잘 작동 되더라도 실제 기기에서는 종료되어 버린다. 아니면 테스트 시 Logcat에 아래와 같은 에러가 표시된다.

 

CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

 

텍스트뷰와 버튼을 적당히 배치한다.

 

다른 스레드에서 텍스트뷰에 접근하는 코드를 작성한다.

 

위 예제의 경우 AVD에서는 별 이상없이 동작 하지만 실제 기기에서 버튼을 터치하면 바로 종료되어 버린다. 메인스레드나 UI 스레드가 아닌 다른 스레드에서 텍스트뷰에 접근하기 때문이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.example.myapplication;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
 
    TextView textView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        textView = findViewById(R.id.textView);
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MyThread thread = new MyThread();
                thread.start();
            }
        });
    }
 
    class MyThread extends Thread {
        @Override
        public void run() {
            textView.post(new Runnable() {
                @Override
                public void run() {
                    textView.setText("My Thread.");
                }
            });
        }
    }
}
 

 

위와 같이 소스를 수정하고 빌드한다.

 

문제없이 잘 실행된다.

 

 

1
2
3
4
5
6
7
8
9
10
11
class MyThread extends Thread {
    @Override
    public void run() {
        textView.postDelayed(new Runnable() {
            @Override
            public void run() {
                textView.setText("My Thread");
            }
        }, 5000);
    }
}
 

 

.post()가 아닌 .postDelayed()를 사용하면 Thread.sleep()를 사용하지 않고 일정시간 후 실행할 수 있다. 위 예제는 버튼 터치 5초 후 텍스트를 바꾼다.

 

다른 스레드에서 UI 스레드에 접근 하는 방법은 여러가지가 있다. 아래 링크를 참고하자.

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)

프로세스 및 스레드 개요

 

반응형
Posted by J-sean
:
반응형

You can stream a video file with VideoView.


<AndroidManifest.xml>

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



<MainActivity.java>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public class MainActivity extends AppCompatActivity {
 
    VideoView videoView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        videoView = findViewById(R.id.videoView);
 
        MediaController mediaController = new MediaController(this);
        videoView.setMediaController(mediaController);
 
        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                videoView.setVideoURI(Uri.parse("http://nexoft.tk/data/WhileYouWereSleeping.mp4")); // or your video file url.
                videoView.requestFocus();
                videoView.start();
            }
        });
 
        videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                Toast.makeText(getApplicationContext(), "Video play completed", Toast.LENGTH_SHORT).show();
            }
        });
 
        videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                String message;
 
                switch (what) {
                    case MediaPlayer.MEDIA_ERROR_UNKNOWN:
                        message = "MEDIA_ERROR_UNKNOWN";
                        break;
 
                    case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
                        message = "MEDIA_ERROR_SERVER_DIED";
                        break;
 
                    default:
                        message = "No what";
                }
 
                switch (extra) {
                    case MediaPlayer.MEDIA_ERROR_IO:
                        message += ", MEDIA_ERROR_IO";
                        break;
 
                    case MediaPlayer.MEDIA_ERROR_MALFORMED:
                        message += ", MEDIA_ERROR_MALFORMED";
                        break;
 
                    case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
                        message += ", MEDIA_ERROR_UNSUPPORTED";
                        break;
 
                    case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
                        message += ", MEDIA_ERROR_TIMED_OUT";
                        break;
 
                    default:
                        message += ", No extra";
                }
                Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
 
                //    Returns true if the method handled the error, false if it didn't. Returning false, or not having an OnErrorListener
                //    at all, will cause the OnCompletionListener to be called.
                return true;
            }
        });
    }
}




Run the app and click the PLAY button.


It may not be able to stream the video and show an error message in AVD.


It can stream the video in the actual device.


반응형
Posted by J-sean
: