<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>APP开发 &#8211; Blog of Code</title>
	<atom:link href="https://www.cztcode.com/category/app/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.cztcode.com</link>
	<description></description>
	<lastBuildDate>Thu, 27 Oct 2022 02:05:57 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://www.cztcode.com/wp-content/uploads/2024/02/cropped-logo-32x32.webp</url>
	<title>APP开发 &#8211; Blog of Code</title>
	<link>https://www.cztcode.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">217219486</site>	<item>
		<title>Android Compose UI组件继承</title>
		<link>https://www.cztcode.com/2022/4266/</link>
					<comments>https://www.cztcode.com/2022/4266/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Thu, 27 Oct 2022 02:05:57 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4266</guid>

					<description><![CDATA[组件继承其实就是，你之前写了一个组件A，后来想在A组件的基础上拓展一些功能，但又不想把A复制一份，所以继承了A并提供更多功能。]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>
<p>组件继承其实就是，你之前写了一个组件A，后来想在A组件的基础上拓展一些功能，但又不想把A复制一份，所以继承了A并提供更多功能。</p>



<h2 class="wp-block-heading">举例</h2>



<p>比如在项目里写了左边这个组件</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20221027095517269.png" alt="image-20221027095517269"/></figure>



<p>但是后来在别的地方又有类似的布局，这里就可以用继承</p>



<figure class="wp-block-image"><img decoding="async" src="https://markdown.cztcode.com/image-20221027095618565.png" alt="image-20221027095618565"/></figure>



<h2 class="wp-block-heading">实现方法</h2>



<p>利用kotlin中函数可以作为参数传递的特性，将子组件传递进父组件，再在父组件中调用即可</p>



<p>下面给了父组件的参数，compoent参数就是接收函数，这里赋值初值为null表示在父组件使用时可以不传递此参数（就是更简洁一些）</p>



<pre class="wp-block-preformatted">@Composable<br>fun ProfileCard(<br> &nbsp; &nbsp;profile: ProfileEntity,<br> &nbsp; &nbsp;component: @Composable (() -&gt; Unit)? = null,<br>)</pre>



<p>然后在你想放置子组件的地方使用</p>



<pre class="wp-block-preformatted">component?.invoke()</pre>



<p>这样子组件就会在父组件的列或者行中调用了</p>



<h2 class="wp-block-heading">语法糖</h2>



<p>注意kotlin有一个语法糖：当函数作为参数调用时，函数可以放在括号外面的大括号内，也就是你可以这样调用父函数：</p>



<pre class="wp-block-preformatted">ProfileCard(profile = profile) {<br> &nbsp; &nbsp;Text(<br> &nbsp; &nbsp; &nbsp; &nbsp;modifier = Modifier.padding(top = 25.dp),<br> &nbsp; &nbsp; &nbsp; &nbsp;text = stringResource(R.string.测试成绩),<br> &nbsp; &nbsp; &nbsp; &nbsp;color = TrolleyColors.TextColor,<br> &nbsp; &nbsp; &nbsp; &nbsp;style = TrolleyStyles.BodyLarge,<br> &nbsp;  )<br> }</pre>



<p>简单的小技巧get</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2022/4266/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4266</post-id>	</item>
		<item>
		<title>JetPack之WorkManager</title>
		<link>https://www.cztcode.com/2021/4036/</link>
					<comments>https://www.cztcode.com/2021/4036/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Thu, 19 Aug 2021 13:29:46 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4036</guid>

					<description><![CDATA[JetPack之WorkManager
一次性请求、周期性请求
触发条件
观察任务状态
取消任务
传递参数
任务链与任务组合]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<p class="is-style-iw-2em">依赖：</p>



<pre class="wp-block-code"><code>def work_version = "2.5.0"

// (Java only)
implementation "androidx.work:work-runtime:$work_version"</code></pre>



<p class="is-style-iw-2em">创建一个任务。需要继承Worker类：</p>



<pre class="wp-block-code"><code>public class MyWork extends Worker {
    public MyWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.i("shopkeeperTag", "doWork:");
        return Result.success();
    }
}</code></pre>



<p class="is-style-iw-2em">创建一个任务请求，任务请求有一次性的和多次的。以一次性为例，通过工厂方法，传入任务类：</p>



<pre class="wp-block-code"><code>        OneTimeWorkRequest request1=new OneTimeWorkRequest.Builder(MyWork.class)
                .build();</code></pre>



<p class="is-style-iw-2em">将任务请求交给WorkManager安排执行：</p>



<pre class="wp-block-code"><code>        WorkManager manager=WorkManager.getInstance(this);
        manager.enqueue(request1);</code></pre>



<p class="is-style-iw-2em">可以为一个任务请求设置限制、延时等其它选项：</p>



<pre class="wp-block-preformatted">        OneTimeWorkRequest request1=new OneTimeWorkRequest.Builder(MyWork.class)
//                设置触发条件
                .setConstraints(constraints)
//                设置延迟执行
                .setInitialDelay(5<strong>, </strong>TimeUnit.<em>SECONDS</em>)
//                退避策略，当worker返回retry时自动执行推迟策略
                .setBackoffCriteria(BackoffPolicy.<em>LINEAR</em><strong>, </strong>Duration.<em>ofSeconds</em>(2))
//                设置Tag标签
                .addTag("workRequest1")
                .build()<strong>;</strong></pre>



<p class="is-style-iw-2em">触发条件：</p>



<pre class="wp-block-code"><code>//        设置触发条件
        Constraints constraints=new Constraints.Builder()
                .setRequiredNetworkType(NetworkType.NOT_REQUIRED)
//                .setRequiresBatteryNotLow() //电量充足
//                .setRequiresCharging() //充电时
//                .setRequiresDeviceIdle() //设备空闲时
//                .setRequiresStorageNotLow() //内存充足
//  NOT_REQUIRED, A network is not required for this work.
//  CONNECTED, Any working network connection is required for this work.
//  UNMETERED, An unmetered network connection is required for this work.
//  NOT_ROAMING, A non-roaming network connection is required for this work.
                .build();</code></pre>



<p class="is-style-iw-2em">观察任务状态：</p>



<pre class="wp-block-code"><code>//        观察任务状态
        manager.getWorkInfoByIdLiveData(request1.getId()).observe(this, new Observer&lt;WorkInfo&gt;() {
            @Override
            public void onChanged(WorkInfo workInfo) {
                Log.i("shopkeeperTag", "WorkInfo onChanged: "+workInfo.getState());
            }
        });</code></pre>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/08/image-25.png" alt="" class="wp-image-4038" /></figure>



<p class="is-style-iw-2em">取消任务：</p>



<pre class="wp-block-code"><code>//        取消任务
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                manager.cancelWorkById(request1.getId());
            }
        },2000);</code></pre>



<p class="is-style-iw-2em">传递参数：</p>



<p class="is-style-iw-2em">向worker传递参数：</p>



<pre class="wp-block-code"><code>        Data inputData=new Data.Builder()
                .putString(inputDataTag,"sk")
                .build();


        OneTimeWorkRequest request1=new OneTimeWorkRequest.Builder(MyWork.class)
                .setInputData(inputData)
                .build();</code></pre>



<p class="is-style-iw-2em">worker中接收参数，并返回结果参数：</p>



<pre class="wp-block-code"><code>    public Result doWork() {
        String stringData=getInputData().getString(inputDataTag);
        Log.i("shopkeeperTag", "doWork: get input data: "+stringData);

        Data outputData=new Data.Builder()
                .putString(outputDataTag,"执行成功")
                .build();
        return Result.success(outputData);
    }</code></pre>



<p class="is-style-iw-2em">在监听任务状态时接收worker的结果参数：</p>



<pre class="wp-block-code"><code>manager.getWorkInfoByIdLiveData(request1.getId()).observe(this<strong>, </strong>new Observer&lt;WorkInfo&gt;() {<br>    @Override<br>    public void onChanged(WorkInfo workInfo) {<br>        Log.<em>i</em>("shopkeeperTag"<strong>, </strong>"WorkInfo onChanged: state = "+workInfo.getState()+", data = "+workInfo.getOutputData().getString(<em>outputDataTag</em>))<strong>;<br></strong><strong>    </strong>}<br>})<strong>;</strong></code></pre>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/08/image-26.png" alt="" class="wp-image-4039" /></figure>



<p class="is-style-iw-2em">周期任务的创建：</p>



<pre class="wp-block-code"><code>//        周期任务
//        周期不能小于15分钟
        PeriodicWorkRequest request2=new PeriodicWorkRequest.Builder(MyWork.class,Duration.ofMinutes(15)).build();
</code></pre>



<p class="is-style-iw-2em">任务链的简单使用：</p>



<pre class="wp-block-code"><code>public void addWork(View view){<br>    OneTimeWorkRequest workA=new OneTimeWorkRequest<br>            .Builder(AWorker.class)<br>            .build()<strong>;<br></strong><strong>    </strong>OneTimeWorkRequest workB=new OneTimeWorkRequest<br>            .Builder(BWorker.class)<br>            .build()<strong>;<br></strong><strong>    </strong>WorkManager.<em>getInstance</em>(this)<br>            .beginWith(workA)<br>            .then(workB)<br>            .enqueue()<strong>;<br></strong>}</code></pre>



<p class="is-style-iw-2em">任务组合：</p>



<pre class="wp-block-preformatted">public void addWork(View view){<br>    OneTimeWorkRequest workA=new OneTimeWorkRequest<br>            .Builder(AWorker.class)<br>            .build()<strong>;<br></strong><strong>    </strong>OneTimeWorkRequest workB=new OneTimeWorkRequest<br>            .Builder(BWorker.class)<br>            .build()<strong>;<br></strong><strong>    </strong>OneTimeWorkRequest workC=new OneTimeWorkRequest<br>            .Builder(CWorker.class)<br>            .build()<strong>;<br></strong><strong>    </strong>OneTimeWorkRequest workD=new OneTimeWorkRequest<br>            .Builder(DWorker.class)<br>            .build()<strong>;<br></strong><strong>    </strong>OneTimeWorkRequest workE=new OneTimeWorkRequest<br>            .Builder(EWorker.class)<br>            .build()<strong>;<br></strong><strong>    </strong>WorkContinuation continuation1=WorkManager.<em>getInstance</em>(this)<br>            .beginWith(workA)<br>            .then(workB)<strong>;<br></strong><strong>    </strong>WorkContinuation continuation2=WorkManager.<em>getInstance</em>(this)<br>            .beginWith(workC)<br>            .then(workD)<strong>;<br></strong><strong>    </strong>List&lt;WorkContinuation&gt; taskList=new ArrayList&lt;&gt;()<strong>;<br></strong><strong>    </strong>taskList.add(continuation1)<strong>;<br></strong><strong>    </strong>taskList.add(continuation2)<strong>;<br></strong><strong>    </strong>WorkContinuation.<em>combine</em>(taskList)<br>            .then(workE)<br>            .enqueue()<strong>;<br></strong>}</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4036/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4036</post-id>	</item>
		<item>
		<title>Android RecyclerView结合DataBinding和LiveData</title>
		<link>https://www.cztcode.com/2021/4008/</link>
					<comments>https://www.cztcode.com/2021/4008/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sun, 15 Aug 2021 02:39:11 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=4008</guid>

					<description><![CDATA[Android RecyclerView结合DataBinding和LiveData
记录使用DataBinding实现对拥有RecyclerView组件的页面进行较大程度的解耦的方式。]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<p class="is-style-iw-2em">本文目的：记录使用DataBinding实现对拥有RecyclerView组件的页面进行较大程度的解耦的方式。</p>



<p class="is-style-iw-2em">RecyclerView数据源：从本地SQLite数据库中使用Room获取一个LiveData并存储在ViewModel中：</p>



<pre class="wp-block-code"><code>public class StudentViewModel extends AndroidViewModel {

    private StudentRepository repository;
    private LiveData&lt;List&lt;Student&gt;&gt; studentsLD;

    public StudentViewModel(@NonNull Application application) {
        super(application);
        this.repository=new StudentRepository(application);
        studentsLD=repository.getAllStudentsLive();
    }

    public void insert(){
        Student s1=new Student("jack",18);
        Student s2=new Student("rose",17);
        insertStudents(s1,s2);
    }

    public void update(){
        Student s1=new Student(3,"jason",20);
        updateStudents(s1);
    }

    public void clear(){
        deleteAllStudents();
    }

    public void delete(){
        Student s1=new Student(2,"rose",17);
        deleteStudents(s1);
    }


    private void insertStudents(Student... students){
        repository.insertStudents(students);
    }

    private void updateStudents(Student... students){
        repository.updateStudents(students);
    }

    private void deleteStudents(Student... students){
        repository.deleteStudents(students);
    }

    private void deleteAllStudents(){
        repository.deleteAllStudents();
    }

//  错误！！！
//    public LiveData&lt;List&lt;Student&gt;&gt; getAllStudentLive(){
//        return repository.getAllStudentsLive();
//    }

//   正确
    public LiveData&lt;List&lt;Student&gt;&gt; getStudentsLD() {
        return studentsLD;
    }
}</code></pre>



<p class="is-style-iw-2em">将获取到的LiveData&lt;List&lt;Student&gt;&gt;对象通过DataBinding传给Activity的xml布局中：</p>



<pre class="wp-block-code"><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;layout 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"&gt;

    &lt;data&gt;
        &lt;variable
            name="viewModel"
            type="com.shopkeeper.room2.StudentViewModel" /&gt;
    &lt;/data&gt;

    &lt;androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"&gt;

        &lt;Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="60dp"
            android:text="增加"
            android:onClick="@{()-&gt;viewModel.insert()}"
            app:layout_constraintBottom_toBottomOf="@+id/button2"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/button2" /&gt;

        &lt;Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="60dp"
            android:layout_marginEnd="60dp"
            android:text="删除"
            android:onClick="@{()-&gt;viewModel.delete()}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" /&gt;

        &lt;Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="60dp"
            android:text="修改"
            android:onClick="@{()-&gt;viewModel.update()}"
            app:layout_constraintEnd_toEndOf="@+id/button"
            app:layout_constraintStart_toStartOf="@+id/button"
            app:layout_constraintTop_toBottomOf="@+id/button" /&gt;

        &lt;Button
            android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="清空"
            android:onClick="@{()-&gt;viewModel.clear()}"
            app:layout_constraintBottom_toBottomOf="@+id/button3"
            app:layout_constraintEnd_toEndOf="@+id/button2"
            app:layout_constraintStart_toStartOf="@+id/button2"
            app:layout_constraintTop_toTopOf="@+id/button3" /&gt;

        &lt;androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycleView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginTop="30dp"
            app:studentBinder="@{viewModel.studentsLD}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/button3" /&gt;
    &lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;
&lt;/layout&gt;</code></pre>



<p class="is-style-iw-2em">此处定义了一个studentBinder的BindingAdapter，用于处理传递过来的数据：</p>



<pre class="wp-block-code"><code>public class RVAdapter {

    @BindingAdapter("studentBinder")
    public static void studentsBindAdapter(RecyclerView recyclerView, List&lt;Student&gt; students){
        StudentAdapter adapter = (StudentAdapter) recyclerView.getAdapter();
        assert adapter != null;
        adapter.setStudents(students);
    }
}</code></pre>



<p class="is-style-iw-2em">由于绑定的是LiveData数据，所以每当列表发生改变时，就会自动执行BindingAdapter中的方法，进而通过RecyclerView的Adapter更新并显示数据（每一个Item也是通过DataBinding来绑定数据的）。Adapter内容：</p>



<pre class="wp-block-code"><code>public class StudentAdapter extends RecyclerView.Adapter&lt;StudentAdapter.StudentViewHolder&gt; {

    List&lt;Student&gt; students;

    public StudentAdapter(List&lt;Student&gt; students) {
        this.students = students;
    }

    @NonNull
    @Override
    public StudentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemBinding binding= DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),R.layout.item,parent,false);
        return new StudentViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull StudentViewHolder holder, int position) {
        holder.binding.setStudent(students.get(position));
    }

    @Override
    public int getItemCount() {
        return students==null?0:students.size();
    }

    static class StudentViewHolder extends RecyclerView.ViewHolder{
        ItemBinding binding;
        public StudentViewHolder(@NonNull ItemBinding binding) {
            super(binding.getRoot());
            this.binding=binding;
        }
    }

    public void setStudents(List&lt;Student&gt; students) {
        this.students = students;
        notifyDataSetChanged();
    }
}</code></pre>



<p class="is-style-iw-2em">通过这种写法，在Activity中的代码量就很少了，甚至不需要使用Observer来监听LiveData的数据变化：</p>



<pre class="wp-block-code"><code>public class MainActivity extends AppCompatActivity {

    ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding= DataBindingUtil.setContentView(this,R.layout.activity_main);
        StudentViewModel viewModel = new ViewModelProvider(this,
                new ViewModelProvider.AndroidViewModelFactory(getApplication()))
                .get(StudentViewModel.class);
        binding.recycleView.setAdapter(new StudentAdapter(viewModel.getStudentsLD().getValue()));
        binding.recycleView.setLayoutManager(new LinearLayoutManager(this));
        binding.setViewModel(viewModel);
        binding.setLifecycleOwner(this);
    }
}</code></pre>



<p class="is-style-iw-2em">效果图：</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/08/GIF-2021-8-15-10-37-24.gif" alt="" class="wp-image-4009" /></figure>



<p class="is-style-iw-2em"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/4008/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4008</post-id>	</item>
		<item>
		<title>Jetpack之DataBinding</title>
		<link>https://www.cztcode.com/2021/3977/</link>
					<comments>https://www.cztcode.com/2021/3977/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Tue, 10 Aug 2021 11:48:59 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=3977</guid>

					<description><![CDATA[Jetpack之DataBinding
DataBinding的基础使用
对include的组件进行数据绑定
使用BaseAdapter对不可直接绑定的组件绑定数据
使用BaseObservable进行双向绑定
使用ObservableField进行双向绑定
对RecyclerView进行数据绑定
结合ViewModel和LiveData使用]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">DataBinding的基础使用</h2>



<p class="is-style-iw-2em">将.xml文件转为DataBinding的文件，会出现一个&lt;data&gt;的标签，在其中可以定义变量&lt;variables&gt;或导入&lt;import&gt;：</p>



<pre class="wp-block-code"><code>    &lt;data&gt;

        &lt;variable
            name="idol"
            type="com.shopkeeper.databinding.Idol" /&gt;

        &lt;import type="com.shopkeeper.databinding.StarUtils" /&gt;

        &lt;variable
            name="eventHandler"
            type="com.shopkeeper.databinding.EventHandleListener" /&gt;
    &lt;/data&gt;</code></pre>



<p class="is-style-iw-2em">在绑定数据时，使用@{}语法：</p>



<pre class="wp-block-code"><code>        &lt;TextView
            android:text="@{idol.name}"/&gt;
        &lt;TextView
            android:text="@{StarUtils.getDarling(idol.star)}"/&gt;</code></pre>



<p class="is-style-iw-2em">在绑定事件的监听时，以onClick为例，可以使用@{}传入一个方法：</p>



<pre class="wp-block-code"><code>        &lt;Button
            android:onClick="@{eventHandler.btnOnClick}"/&gt;</code></pre>



<p class="is-style-iw-2em">该方法会传入一个View的实例</p>



<pre class="wp-block-code"><code>public class EventHandleListener {
    private Context context;

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

    public void btnOnClick(View view){
        Toast.makeText(context,"like 02",Toast.LENGTH_SHORT).show();
    }
}</code></pre>



<p class="is-style-iw-2em">也可以绑定一个监听器（可以传入任意参数），以一个viewModel的add方法为例：</p>



<pre class="wp-block-code"><code>        &lt;Button
            android:onClick="@{()-&gt;viewModel.add()}"/&gt;</code></pre>


]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/3977/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3977</post-id>	</item>
		<item>
		<title>Jeppack之lifecycle</title>
		<link>https://www.cztcode.com/2021/3975/</link>
					<comments>https://www.cztcode.com/2021/3975/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Mon, 09 Aug 2021 13:55:27 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=3975</guid>

					<description><![CDATA[Jeppack之lifecycle
使用lifecycle解耦页面和组件
使用LifecycleService解耦Service与组件
使用ProcessLifecycleOwner监听应用程序生命周期]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">使用lifecycle解耦页面和组件</h2>



<p class="is-style-iw-2em">对于一个需要在activity生命周期的某个阶段执行响应操作的组件，可以让其实现LifecycleObserver接口，并通过注解的方式，在响应的阶段进行操作：</p>



<pre class="wp-block-code"><code>public class MyChronometer extends Chronometer implements LifecycleObserver {<br><br>    private long elapsedTime;<br><br>    public MyChronometer(Context context, AttributeSet attrs) {<br>        super(context, attrs);<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_RESUME</em>)<br>    private void startMeter(){<br>        setBase(SystemClock.<em>elapsedRealtime</em>() - elapsedTime);<br>        start();<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_PAUSE</em>)<br>    private void stopMeter(){<br>        elapsedTime = SystemClock.<em>elapsedRealtime</em>()-getBase();<br>        stop();<br>    }<br>}</code></pre>



<p class="is-style-iw-2em">并在activity中注册：</p>



<pre class="wp-block-code"><code>public class MainActivity extends AppCompatActivity {

    ActivityMainBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding= DataBindingUtil.<em>setContentView</em>(this,R.layout.<em>activity_main</em>);
        getLifecycle().addObserver(binding.chronometer);
    }
}</code></pre>



<h2 class="wp-block-heading">使用LifecycleService解耦Service与组件</h2>



<p class="is-style-iw-2em">执行的操作放在一个实现了LifecycleObserver接口的观察者中：</p>



<pre class="wp-block-code"><code>public class MyLocationObserver implements LifecycleObserver {<br>    private Context context;<br>    private MyLocationListener listener;<br>    private LocationManager locationManager;<br>    private static String <em>TAG</em>="shopkeepertag";<br><br>    public MyLocationObserver(Context context) {<br>        this.context = context;<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_CREATE</em>)<br>    private void startGetLocation() {<br>        Log.<em>d</em>(<em>TAG</em>, "startGetLocation: ");<br>        locationManager = (LocationManager) context.getSystemService(Context.<em>LOCATION_SERVICE</em>);<br>        listener = new MyLocationListener();<br>        if (ActivityCompat.<em>checkSelfPermission</em>(context, Manifest.permission.<em>ACCESS_FINE_LOCATION</em>) != PackageManager.<em>PERMISSION_GRANTED </em>&amp;&amp; ActivityCompat.<em>checkSelfPermission</em>(context, Manifest.permission.<em>ACCESS_COARSE_LOCATION</em>) != PackageManager.<em>PERMISSION_GRANTED</em>) {<br>            return;<br>        }<br>        locationManager.requestLocationUpdates(LocationManager.<em>GPS_PROVIDER</em>, 3000, 1, listener);<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_DESTROY</em>)<br>    private void stopGetLocation(){<br>        Log.<em>d</em>(<em>TAG</em>, "stopGetLocation: ");<br>        locationManager.removeUpdates(listener);<br>    }<br><br>    static class MyLocationListener implements LocationListener{<br><br>        @Override<br>        public void onLocationChanged(@NonNull Location location) {<br>            Log.<em>d</em>(<em>TAG</em>, "onLocationChanged: "+location.toString());<br>        }<br>    }<br>}</code></pre>



<p class="is-style-iw-2em">service要继承自LifecycleService，并注册一个观察者：</p>



<pre class="wp-block-code"><code>public class MyLocationService extends LifecycleService {<br>    public MyLocationService() {<br>        Log.<em>d</em>("sk", "MyLocationService: ");<br>        MyLocationObserver observer=new MyLocationObserver(this);<br>        getLifecycle().addObserver(observer);<br>    }<br>}</code></pre>



<p class="is-style-iw-2em">在activity中启动或者关闭服务时，观察者类就能自动执行操作。</p>



<h2 class="wp-block-heading">使用ProcessLifecycleOwner监听应用程序生命周期</h2>



<p class="is-style-iw-2em">在Application的不同生命周期要执行的操作用注解的方式放在一个实现了LifecycleObserver接口的观察者中：</p>



<pre class="wp-block-code"><code>public class ApplicationObserver implements LifecycleObserver {<br>    private static String <em>TAG</em>="shopkeepertag";<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_CREATE</em>)<br>    public void onCreated(){<br>        Log.<em>d</em>(<em>TAG</em>, "onCreated: ");<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_START</em>)<br>    public void onStart(){<br>        Log.<em>d</em>(<em>TAG</em>, "onStart: ");<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_RESUME</em>)<br>    public void onResume(){<br>        Log.<em>d</em>(<em>TAG</em>, "onResume: ");<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_PAUSE</em>)<br>    public void onPause(){<br>        Log.<em>d</em>(<em>TAG</em>, "onPause: ");<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_STOP</em>)<br>    public void onStop(){<br>        Log.<em>d</em>(<em>TAG</em>, "onStop: ");<br>    }<br><br>    @OnLifecycleEvent(Lifecycle.Event.<em>ON_DESTROY</em>)<br>    public void onDestroy(){<br>        Log.<em>d</em>(<em>TAG</em>, "onDestroy: ");<br>    }<br>}</code></pre>



<p class="is-style-iw-2em">在application通过ProcessLifecycleOwner注册一个观察者：</p>



<pre class="wp-block-code"><code>public class MyApplication extends Application {<br><br>    @Override<br>    public void onCreate() {<br>        super.onCreate();<br>        ProcessLifecycleOwner.<em>get</em>().getLifecycle()<br>                .addObserver(new ApplicationObserver());<br>    }<br>}</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/3975/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3975</post-id>	</item>
		<item>
		<title>RxAndroid学习总结（二）</title>
		<link>https://www.cztcode.com/2021/3752/</link>
					<comments>https://www.cztcode.com/2021/3752/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sun, 17 Jan 2021 11:44:49 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=3752</guid>

					<description><![CDATA[RxAndroid学习总结（二）
线程控制Scheduler]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">线程控制Scheduler</h2>



<h4 class="wp-block-heading">Scheduler的APl:</h4>



<p class="is-style-iw-2em">用于控制操作符和被观察者事件，所执行的线程。不同的调度器，对应不同的线程</p>



<p class="is-style-iw-2em">调度器的分类:</p>



<p class="is-style-iw-2em">Schedulers.immediate():默认线程</p>



<p class="is-style-iw-2em">Schedulers.newThread():新建线程</p>



<p class="is-style-iw-2em">Schedulers.io()︰适用于I/o操作（线程池)</p>



<p class="is-style-iw-2em">Schedulers.computation():适用于计算工作（线程池)</p>



<p class="is-style-iw-2em">Schedulers.trampoline():当前线程，队列执行</p>



<h4 class="wp-block-heading">进行线程调度：</h4>



<p class="is-style-iw-2em">subscribeOn():指定subscribe()所发生的线程，即Observable.OnSubscribe被激活时所处的线程。或者叫做事件产生的线程。</p>



<p class="is-style-iw-2em">observeOn():指定Subscriber所运行在的线程。或者叫做事件消费的线程。</p>



<pre class="wp-block-preformatted"><em>/**
 * Schedulers的API
 */
</em>public void test05(){
    Observable.<em>from</em>(<em>getData</em>())
            .subscribeOn(Schedulers.<em>io</em>())//指定所运行的线程（线程调度）
            .observeOn(AndroidSchedulers.<em>mainThread</em>())//指定observer的线程
            .subscribe(new Action1&lt;Integer&gt;() {
                @Override
                public void call(Integer integer) {
                    Log.<em>d</em>(<em>TAG</em>, "call: "+String.<em>valueOf</em>(integer));
                }
            });
}

private static List&lt;Integer&gt; getData(){
    List&lt;Integer&gt; list=new ArrayList&lt;&gt;();
    for (int i=0;i&lt;10;i++){
        list.add(i);
        try {
            Thread.<em>sleep</em>(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    return list;
}</pre>



<p><strong>RxJava遵循的是线程不变的原则:</strong></p>



<p class="is-style-iw-2em">在哪调用subscribe()，就在哪个线程生产事件</p>



<p class="is-style-iw-2em">在哪生产事件，就在哪个线程消费事件。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/3752/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3752</post-id>	</item>
		<item>
		<title>RxAndroid学习总结（一）</title>
		<link>https://www.cztcode.com/2021/3749/</link>
					<comments>https://www.cztcode.com/2021/3749/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sun, 17 Jan 2021 11:17:19 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=3749</guid>

					<description><![CDATA[RxAndroid学习总结（一）
观察者、被观察者、订阅
]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">观察者、被观察者、订阅</h2>



<h4 class="wp-block-heading">1.创建Observable</h4>



<p class="is-style-iw-2em">Observable的创建操作符:</p>



<p class="is-style-iw-2em">比如: create(),from(),just(),repeat(),defer(),rangeinterval(),和timer()等等</p>



<h4 class="wp-block-heading">2.创建Observer</h4>



<p class="is-style-iw-2em">Observer用于处理Observable发送过来的各类事件。</p>



<p class="is-style-iw-2em">可以用Operators(操作符)对事件进行各种拦截和操作。</p>



<p class="is-style-iw-2em">RxJava还创建了一个继承了Observer的抽象类:Subscriber:</p>



<p class="is-style-iw-2em">Subscriber进行了一些扩展，基本使用方式是一样的，这也是以后我们主要用到的一个类</p>



<h4 class="wp-block-heading">3.Subscribe订阅</h4>



<p class="is-style-iw-2em">通过subscribe()方法订阅，把observable和observer关联起来订阅后，observable就会调用observer的onNext()、onCompleted()、onError()等方法。</p>



<h4 class="wp-block-heading">下面是使用create方法创建被观察者，并创建观察者、订阅的一个例子：</h4>



<pre class="wp-block-preformatted">Observable&lt;String&gt; observable=Observable.<em>create</em>(new Observable.OnSubscribe&lt;String&gt;() {<br>    @Override<br>    public void call(Subscriber&lt;? super String&gt; subscriber) {<br>        subscriber.onNext("hello world");<br>        subscriber.onNext("hello RxJava");<br>        subscriber.onCompleted();<br>    }<br>});<br><br>Observer&lt;String&gt; observer=new Observer&lt;String&gt;() {<br>    @Override<br>    public void onCompleted() {<br>        Log.<em>i</em>(<em>TAG</em>, "onCompleted: 观察者执行");<br>    }<br><br>    @Override<br>    public void onError(Throwable e) {<br><br>    }<br><br>    @Override<br>    public void onNext(String s) {<br>        Log.<em>i</em>(<em>TAG</em>, "onNext: "+s);<br>    }<br>};<br><br>observable.subscribe(observer);</pre>



<h4 class="wp-block-heading">使用from方法可以快速创建一个事件队列：</h4>



<pre class="wp-block-preformatted">String[] array=new String[]{"hello world","hello RxJava","hello shopkeeper"};<br>Observable&lt;String&gt; observable=Observable.<em>from</em>(array);<br>Observer&lt;String&gt; observer=new Observer&lt;String&gt;() {<br>    @Override<br>    public void onCompleted() {<br>        Log.<em>i</em>(<em>TAG</em>, "onCompleted: 观察者执行");<br>    }<br><br>    @Override<br>    public void onError(Throwable e) {<br><br>    }<br><br>    @Override<br>    public void onNext(String s) {<br>        Log.<em>i</em>(<em>TAG</em>, "onNext: "+s);<br>    }<br>};<br><br>observable.subscribe(observer);</pre>



<h4 class="wp-block-heading">使用just方法可以直接传入事件：</h4>



<pre class="wp-block-preformatted">Observable&lt;String&gt; observable=Observable.<em>just</em>("hello world","hello RxJava","hello shopkeeper");<br>Observer&lt;String&gt; observer=new Observer&lt;String&gt;() {<br>    @Override<br>    public void onCompleted() {<br>        Log.<em>i</em>(<em>TAG</em>, "onCompleted: 观察者执行");<br>    }<br><br>    @Override<br>    public void onError(Throwable e) {<br><br>    }<br><br>    @Override<br>    public void onNext(String s) {<br>        Log.<em>i</em>(<em>TAG</em>, "onNext: "+s);<br>    }<br>};<br><br>observable.subscribe(observer);</pre>



<h4 class="wp-block-heading">创建不完全的回调：</h4>



<pre class="wp-block-preformatted">Observable&lt;String&gt; observable=Observable.<em>just</em>("hello world","hello RxJava","hello shopkeeper");<br>Action1&lt;String&gt; onNextAction1=new Action1&lt;String&gt;() {<br><br>    @Override<br>    public void call(String s) {<br>        Log.<em>i</em>(<em>TAG</em>, "call: "+s);<br>    }<br>};<br><br>Action1&lt;Throwable&gt; onErrorAction=new Action1&lt;Throwable&gt;() {<br>    @Override<br>    public void call(Throwable throwable) {<br>        Log.<em>d</em>(<em>TAG</em>, "call: onError "+ throwable.getMessage());<br>    }<br>};<br><br>Action0 onCompletedAction= new Action0() {<br>    @Override<br>    public void call() {<br>        Log.<em>i</em>(<em>TAG</em>, "call: completed");<br>    }<br>};<br><br>observable.subscribe(onNextAction1,onErrorAction,onCompletedAction);</pre>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/3749/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3749</post-id>	</item>
		<item>
		<title>Android JetPack学习总结（二十二）</title>
		<link>https://www.cztcode.com/2021/3745/</link>
					<comments>https://www.cztcode.com/2021/3745/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Sat, 16 Jan 2021 03:58:35 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=3745</guid>

					<description><![CDATA[Android JetPack学习总结（二十二）
完善PhotoGallery，保存图片]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">完善PhotoGallery，保存图片</h2>



<p class="is-style-iw-2em">根据欲加载的图片高度设置ImageView的高度：</p>



<pre class="wp-block-preformatted">imageView.getLayoutParams().height=getItem(position).getPhotoHeight();</pre>



<p class="is-style-iw-2em">增加显示了一些新的数据。</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cztcode.com/wp-content/uploads/2021/01/image-4.png" alt="" class="wp-image-3746" /></figure>



<h5 class="wp-block-heading">图片保存</h5>



<p class="is-style-iw-2em">首先创建一个Drawable资源，为一个按压之后状态会发生改变的按钮。</p>



<pre class="wp-block-preformatted">&lt;?xml version="1.0" encoding="utf-8"?&gt;<br>&lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&gt;<br>    &lt;item android:state_pressed="true" android:drawable="@drawable/ic_baseline_saved_24"/&gt;<br>    &lt;item android:drawable="@drawable/ic_baseline_save_24"/&gt;<br>&lt;/selector&gt;</pre>



<p class="is-style-iw-2em"><strong>申请写存储器权限：</strong></p>



<p class="is-style-iw-2em">首先要先在manifests中声明权限</p>



<pre class="wp-block-preformatted">&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/&gt;</pre>



<p class="is-style-iw-2em">在点击保存按钮时动态申请权限</p>



<pre class="wp-block-preformatted">saveButton.setOnClickListener(new View.OnClickListener() {<br>    @Override<br>    public void onClick(View view) {<br><br>        if (Build.VERSION.<em>SDK_INT</em>&lt;29&amp;&amp; ContextCompat.<em>checkSelfPermission</em>(requireContext(),<br>                Manifest.permission.<em>WRITE_EXTERNAL_STORAGE</em>)!= PackageManager.<em>PERMISSION_GRANTED</em>){<br>            Toast.<em>makeText</em>(getContext(),"onclick",Toast.<em>LENGTH_LONG</em>).show();<br>            requestPermissions(new String[]{Manifest.permission.<em>WRITE_EXTERNAL_STORAGE</em>},<em>REQUEST_WRITE</em>);<br>        }<br>    }<br>});</pre>



<p class="is-style-iw-2em">API 29以上的不需要动态申请权限了。</p>



<p class="is-style-iw-2em"><strong>保存图片：</strong></p>



<pre class="wp-block-preformatted">    private void savePhoto(){<br>        PagerPhotoViewHolder holder=(PagerPhotoViewHolder) ((RecyclerView)viewPager2.getChildAt(0)).findViewHolderForAdapterPosition(viewPager2.getCurrentItem());<br>        Bitmap bitmap=((BitmapDrawable)((ImageView)holder.itemView.findViewById(R.id.<em>pagerPhoto</em>)).getDrawable()).getBitmap();<br><br>        Uri saveUri=requireContext().getContentResolver().insert(MediaStore.Images.Media.<em>EXTERNAL_CONTENT_URI</em>,new ContentValues());<br>        if (saveUri == null) {<br>            Toast.<em>makeText</em>(requireContext(),"存储失败",Toast.<em>LENGTH_LONG</em>).show();<br>            return;<br>        }else {<br>            OutputStream outputStream = null;<br>            try {<br>                outputStream=requireContext().getContentResolver().openOutputStream(saveUri);<br>                bitmap.compress(Bitmap.CompressFormat.<em>JPEG</em>,90,outputStream);<br>                Toast.<em>makeText</em>(requireContext(),"存储成功",Toast.<em>LENGTH_LONG</em>).show();<br>            } catch (FileNotFoundException e) {<br>                Toast.<em>makeText</em>(requireContext(),"存储失败",Toast.<em>LENGTH_LONG</em>).show();<br>                e.printStackTrace();<br>            }finally {<br>                try {<br>                    outputStream.close();<br>                } catch (IOException e) {<br>                    e.printStackTrace();<br>                }<br>            }<br>        }<br>        //低版本<br>//        if (MediaStore.Images.Media.insertImage(requireContext().getContentResolver(),bitmap,"","")==null){<br>//            Toast.makeText(requireContext(),"存储失败",Toast.LENGTH_LONG).show();<br>//        }else {<br>//            Toast.makeText(requireContext(),"存储成功",Toast.LENGTH_LONG).show();<br>//        }<br><br>    }</pre>



<p class="is-style-iw-2em">首先得获取保存图片的imageView，然后将其图片内容（drawable）转化为BItmap。注意这里有一个bug，当图片没加载出来时，点击保存按钮会将展位图保存，会报错：vectorDrawable can not cast to Bitmap。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/3745/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3745</post-id>	</item>
		<item>
		<title>Android JetPack学习总结（二十一）</title>
		<link>https://www.cztcode.com/2021/3742/</link>
					<comments>https://www.cztcode.com/2021/3742/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Fri, 15 Jan 2021 12:15:31 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=3742</guid>

					<description><![CDATA[Android JetPack学习总结（二十一）
Service(二) 前台服务ForeGround]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">Service(二) 前台服务ForeGround</h2>



<p class="is-style-iw-2em">在安卓9之后创建前台服务需要申请权限:</p>



<pre class="wp-block-preformatted"><strong>&lt;uses-permission android:name="android.permission.FOREGROUND_SERVICE"/&gt;</strong></pre>



<p class="is-style-iw-2em">创建前台服务的过程和之前创建后台服务的过程类似,只不过要在onCreate方法中加上一个方法:</p>



<pre class="wp-block-preformatted">startForeground()</pre>



<p class="is-style-iw-2em">具体设置过程如下:</p>



<pre class="wp-block-preformatted">Notification notification=new NotificationCompat<br>        .Builder(MyService.this,"fdasf")<br>        .setSmallIcon(R.drawable.<em>ic_android_black_24dp</em>)<br>        .setContentTitle("this is a title")<br>        .setContentText("this is a notification")<br>        .build();<br>startForeground(1,notification);</pre>



<p class="is-style-iw-2em">其中第一个参数是id(不能为0),第二个参数是一个通知.</p>



<p class="is-style-iw-2em">在notification的设置中,Builder的第二个参数不能是一个任意的字符串,否则会爆出<strong>Bad notification for startForeground</strong>的错误,必须要创建一个真实的channelId:</p>



<pre class="wp-block-preformatted">@Override
public void onCreate() {
    ...
    createNotificationChannel();
    Notification notification=new NotificationCompat
            .Builder(MyService.this,CHANNEL_ID)
            .setSmallIcon(R.drawable.<em>ic_android_black_24dp</em>)
            .setContentTitle("this is a title")
            .setContentText("this is a notification")
            .build();
    startForeground(1,notification);
}

    private void createNotificationChannel() {
        if (Build.VERSION.<em>SDK_INT </em>&gt;= Build.VERSION_CODES.<em>O</em>) {
            CharSequence name = "my notification channel";
            int importance = NotificationManager.<em>IMPORTANCE_DEFAULT</em>;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }</pre>



<p class="is-style-iw-2em">触摸通知以触发事件:</p>



<pre class="wp-block-preformatted">PendingIntent pendingIntent=PendingIntent.<em>getActivity</em>(<br>        MyService.this,<br>        0,<br>        new Intent(MyService.this,MainActivity.class),<br>        0<br>);<br>Notification notification=new NotificationCompat<br>        .Builder(MyService.this,CHANNEL_ID)<br>        .setSmallIcon(R.drawable.<em>ic_android_black_24dp</em>)<br>        .setContentTitle("this is a title")<br>        .setContentText("this is a notification")<br>        .setContentIntent(pendingIntent)<br>        .build();<br>startForeground(1,notification);</pre>



<p class="is-style-iw-2em">在manifest中设置以保证一个activity只会被创建一次:</p>



<pre class="wp-block-preformatted">android:launchMode="singleInstance"</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/3742/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3742</post-id>	</item>
		<item>
		<title>Android JetPack学习总结（二十）</title>
		<link>https://www.cztcode.com/2021/3739/</link>
					<comments>https://www.cztcode.com/2021/3739/#respond</comments>
		
		<dc:creator><![CDATA[Jellow]]></dc:creator>
		<pubDate>Fri, 15 Jan 2021 09:11:21 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<guid isPermaLink="false">https://www.cztcode.com/?p=3739</guid>

					<description><![CDATA[Android JetPack学习总结（二十）
Service(一)]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div>


<h2 class="wp-block-heading">Service(一)</h2>



<p class="is-style-iw-2em">创建一个Service如同创建其它三大组件一样，需要在Manifests中声明之。</p>



<p class="is-style-iw-2em">启动服务：</p>



<pre class="wp-block-preformatted">@Override<br>protected void onStart() {<br>    super.onStart();<br>    Log.<em>i</em>(TAG, "onStart: activity");<br>    Intent intent=new Intent(this,MyService.class);<br>    this.startService(intent);<br>}</pre>



<p class="is-style-iw-2em">关停服务：</p>



<pre class="wp-block-preformatted">@Override<br>protected void onStop() {<br>    super.onStop();<br>    Log.<em>i</em>(TAG, "onStop: activity");<br>    Intent intent=new Intent(this,MyService.class);<br>    this.stopService(intent);<br>}</pre>



<p class="is-style-iw-2em">在Service内部关停服务：</p>



<pre class="wp-block-preformatted">@Override<br>public int onStartCommand(Intent intent, int flags, int startId) {<br>    Log.<em>i</em>("hello","onStartCommand: Service");<br>    stopSelf();<br>    return super.onStartCommand(intent, flags, startId);<br>}</pre>



<h5 class="wp-block-heading">使用具有生命周期的LifeCycleService：</h5>



<p class="is-style-iw-2em">添加依赖</p>



<pre class="wp-block-code"><code>implementation "android.arch.lifecycle:extensions:1.1.1"</code></pre>



<p class="is-style-iw-2em">java不支持协程。</p>



<h5 class="wp-block-heading">绑定服务</h5>



<p class="is-style-iw-2em">在Service中增加继承Binder的子类，并重写OnBind方法：</p>



<pre class="wp-block-preformatted">public class MyService extends LifecycleService {
    private MutableLiveData&lt;Integer&gt; number=new MutableLiveData&lt;&gt;();
    public MyService() {
        number.setValue(0);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // <em>TODO: Return the communication channel to the service.
        </em>super.onBind(intent);
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    try {
                        Thread.<em>sleep</em>(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    number.postValue(number.getValue()+1);
                }
            }
        }).start();
        return new MyBinder();
    }

    public class MyBinder extends Binder{
        MyService service=MyService.this;
    }

    public MutableLiveData&lt;Integer&gt; getNumber() {
        return number;
    }
}</pre>



<p class="is-style-iw-2em">在Activity中启动绑定：</p>



<pre class="wp-block-preformatted">buttonBind.setOnClickListener(new View.OnClickListener() {<br>    @Override<br>    public void onClick(View view) {<br>        Log.<em>i</em>(TAG,"onclick");<br>        Intent bindIntent=new Intent(MainActivity.this,MyService.class);<br>        ServiceConnection connection=new ServiceConnection() {<br>            @Override<br>            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {<br>                ((MyService.MyBinder)iBinder).service.getNumber().observe(MainActivity.this, new Observer&lt;Integer&gt;() {<br>                    @Override<br>                    public void onChanged(Integer integer) {<br>                        textView.setText(integer.toString());<br>                    }<br>                });<br>            }<br><br>            @Override<br>            public void onServiceDisconnected(ComponentName componentName) {<br><br>            }<br>        };<br>        bindService(bindIntent,connection,<em>BIND_AUTO_CREATE</em>);<br>    }<br>});</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.cztcode.com/2021/3739/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3739</post-id>	</item>
	</channel>
</rss>
