jetpack中的常用知識(shí)點(diǎn)筆記(2)

5,Room

Android采用SQLite作為數(shù)據(jù)庫(kù)存儲(chǔ),開(kāi)源社區(qū)常見(jiàn)的ORM(Object Relation Mapping)庫(kù)有ORMLite,Green DAO等善玫,Room和其他庫(kù)一樣,也是SQLite上提供了一層封裝密强。
Room重要的三個(gè)概念

  • Entity:實(shí)體類(lèi)茅郎,對(duì)應(yīng)的是數(shù)據(jù)庫(kù)的一張表結(jié)構(gòu),使用注釋@Entity標(biāo)記或渤。(相當(dāng)于java Bean)
  • Dao:包含訪(fǎng)問(wèn)一系列訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的方法v系冗,使用注釋@Dao標(biāo)記
  • Database:數(shù)據(jù)庫(kù)持有者,作為與應(yīng)用持久化相關(guān)數(shù)據(jù)的低層連接的主要接入點(diǎn)薪鹦。使用注解@Database標(biāo)記掌敬。另外需要滿(mǎn)足以下條件:定義的類(lèi)必須是一個(gè)繼承了RoomDatabase的抽象類(lèi)惯豆,在注解中需要定義與數(shù)據(jù)庫(kù)相關(guān)聯(lián)的實(shí)體類(lèi)表。包含一個(gè)沒(méi)有參數(shù)的抽象方法并且返回一個(gè)Dao對(duì)象奔害。
    首先build中
 implementation 'androidx.room:room-runtime:2.2.5'
 annotationProcessor 'androidx.room:room-compiler:2.2.5'
@Entity(tableName = "student")
public class Student {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
    public int id;

    @ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
    public String name;

    @ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)
    public int age;

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    @Ignore
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Ignore
    public Student(int id) {
        this.id = id;
    }
}
@Dao
public interface StudentDao {

    @Insert
    void insertStudent(Student... students);

    @Delete
    void deleteStudent(Student... students);

    @Update
    void updateStudent(Student... students);

    @Query("SELECT * FROM student")
    List<Student> getAllStudent();

    @Query("SELECT * FROM student WHERE id = :id")
    List<Student> getStudentById(int id);
}
@Database(entities = {Student.class}, version = 1, exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {

    private static final String DATABASE_NAME = "my_db.db";
    private static MyDatabase mInstance;

    //private MyDatabase(){}

    public static synchronized MyDatabase getInstance(Context context){
        if(mInstance == null){
            mInstance = Room.databaseBuilder(context.getApplicationContext(),
                    MyDatabase.class,
                    DATABASE_NAME)
                    //.allowMainThreadQueries()
                    .build();
        }
        return mInstance;
    }

    public abstract StudentDao getStudentDao();

}

在A(yíng)ctivity的代碼

public class MainActivity extends AppCompatActivity {

    private StudentRecyclerViewAdapter adapter;
    private StudentDao studentDao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RecyclerView recycleView = findViewById(R.id.recycleView);
        recycleView.setLayoutManager(new LinearLayoutManager(this));
        List<Student> students = new ArrayList<>();
        adapter = new StudentRecyclerViewAdapter(students);
        recycleView.setAdapter(adapter);

        MyDatabase database = MyDatabase.getInstance(this);
        studentDao = database.getStudentDao();
    }

    public void mInsert(View view) {
        Student s1 = new Student("Jack", 20);
        Student s2 = new Student("Rose", 18);
        new InsertStudentTask(studentDao).execute(s1,s2);
    }

    class InsertStudentTask extends AsyncTask<Student, Void, Void> {

        private StudentDao studentDao;

        public InsertStudentTask(StudentDao studentDao) {
            this.studentDao = studentDao;
        }

        @Override
        protected Void doInBackground(Student... students) {
            studentDao.insertStudent(students);
            return null;
        }
    }

    public void mDelete(View view) {
        Student s1 = new Student(2);
        new DeleteStudentTask(studentDao).execute(s1);
    }

    class DeleteStudentTask extends AsyncTask<Student, Void, Void> {

        private StudentDao studentDao;

        public DeleteStudentTask(StudentDao studentDao) {
            this.studentDao = studentDao;
        }

        @Override
        protected Void doInBackground(Student... students) {
            studentDao.deleteStudent(students);
            return null;
        }
    }

    public void mUpdate(View view) {
        Student s1 = new Student(3,"Jason", 21);
        new UpdateStudentTask(studentDao).execute(s1);
    }

    class UpdateStudentTask extends AsyncTask<Student, Void, Void> {

        private StudentDao studentDao;

        public UpdateStudentTask(StudentDao studentDao) {
            this.studentDao = studentDao;
        }

        @Override
        protected Void doInBackground(Student... students) {
            studentDao.updateStudent(students);
            return null;
        }
    }

    public void mQuery(View view) {
        new GetAllStudentTask(studentDao).execute();
    }

    class GetAllStudentTask extends AsyncTask<Void,Void,Void>{

        private StudentDao studentDao;

        public GetAllStudentTask(StudentDao studentDao) {
            this.studentDao = studentDao;
        }

        @Override
        protected Void doInBackground(Void... voids) {
            List<Student> students = studentDao.getAllStudent();
            adapter.setStudents(students);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            adapter.notifyDataSetChanged();
        }
    }
}

怎樣升級(jí)數(shù)據(jù)庫(kù):
使用Migration升級(jí)數(shù)據(jù)庫(kù)
Room會(huì)先判斷當(dāng)前有沒(méi)有直接從1到3的升級(jí)方案楷兽,如果有,就直接執(zhí)行從1到3的升級(jí)方案华临,如果沒(méi)有芯杀,那么Room會(huì)按照順序先后執(zhí)行Migration(1,2)雅潭,Migration(2揭厚,3)以完成升級(jí)
修改MyDatabase的代碼如下

public static synchronized MyDatabase getInstance(Context context){
        if(mInstance == null){
            mInstance = Room.databaseBuilder(context.getApplicationContext(),
                    MyDatabase.class,
                    DATABASE_NAME)
                    //.allowMainThreadQueries()
                    .addMigrations(MIGRATION_1_2,MIGRATION_2_3,MIGRATION_3_4)
                    //.fallbackToDestructiveMigration()
                    .createFromAsset("prestudent.db")
                    .build();
        }
        return mInstance;
    }

    static final Migration MIGRATION_1_2 = new Migration(1,2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE student ADD COLUMN sex INTEGER NOT NULL DEFAULT 1");
        }
    };

    static final Migration MIGRATION_2_3 = new Migration(2,3) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE student ADD COLUMN bar_data INTEGER NOT NULL DEFAULT 1");
        }
    };

    static final Migration MIGRATION_3_4 = new Migration(3,4) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("CREATE TABLE temp_student (" +
                    "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"+
                    "name TEXT,"+
                    "age INTEGER NOT NULL,"+
                    "sex TEXT DEFAULT 'M',"+
                    "bar_data INTEGER NOT NULL DEFAULT 1)");
            database.execSQL("INSERT INTO temp_student (name,age,sex,bar_data)" +
                    "SELECT name,age,sex,bar_data FROM student");
            database.execSQL("DROP TABLE student");
            database.execSQL("ALTER TABLE temp_student RENAME TO student");
        }
    };

Schema文件:Room在每次數(shù)據(jù)升級(jí)過(guò)程中,都會(huì)導(dǎo)出一個(gè)Schema文件寻馏,這是一個(gè)json格式的文件棋弥,其中包含了數(shù)據(jù)庫(kù)的基本信息,有了該文件能清楚的知道數(shù)據(jù)庫(kù)的歷次變更情況诚欠,極大地方便了開(kāi)發(fā)者排查問(wèn)題。


添加配置.png

schema.png

6漾岳,Navigation

Navigation的誕生是方便我們管理頁(yè)面的App Bar轰绵。

  • 優(yōu)勢(shì)如下:
    1,可視化的頁(yè)面導(dǎo)航圖尼荆,類(lèi)似于A(yíng)pple Xcode中的StoryBoard左腔,便于我們理清頁(yè)面關(guān)系。
    2捅儒,通過(guò)destination和action完成頁(yè)面導(dǎo)航液样。
    3,方便添加頁(yè)面切換動(dòng)畫(huà)巧还。
    4鞭莽,頁(yè)面間類(lèi)型安全的參數(shù)傳遞。
    5麸祷,通過(guò)Navigation UI澎怒,對(duì)菜單,底部導(dǎo)航阶牍,抽屜菜單導(dǎo)航進(jìn)行統(tǒng)一的處理喷面。
    6,支持深層鏈接DeepLink走孽。
  • 主要元素
    1诫欠,Navigation Graph,一種新的XML資源文件锐极,包含應(yīng)用程序所有的頁(yè)面沿猜,以及頁(yè)面間的關(guān)系。
    2,NavHostFragment县昂,一個(gè)特殊的Fragment肮柜,可以將它看成其他Fragment的容器,Navigation Graph中的Fragment正是通過(guò)NavHostFragment進(jìn)行展示的倒彰。
    3审洞,NavController,用于在代碼中完成Navigation Graph中具體的頁(yè)面切換工作待讳。
    三者之間的關(guān)系:當(dāng)你想切換Fragment時(shí)芒澜,使用NavController對(duì)象,告訴它你想要去Navigation Graph中的哪個(gè)Fragment创淡,NavController會(huì)將你想去的Fragment展示NavHostFragment中痴晦。
  • NavigationUI的作用
    Fragment的切換,除了Fragment頁(yè)面本身的切換琳彩,通常還伴有App bar的變化誊酌。為了方便統(tǒng)一管理,Navigation組件引入了NavigationUI類(lèi)露乏。
    示例代碼如下:
    首先創(chuàng)建一個(gè)navigation資源文件碧浊,位置如圖所示


    navigation

    其中代碼如下

<?xml version="1.0" encoding="utf-8"?>
<navigation 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/my_nav_graph"
    app:startDestination="@id/homeFragment">

    <fragment
        android:id="@+id/homeFragment"
        android:name="com.dongnaoedu.navigation.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" >
        <action
            android:id="@+id/action_homeFragment_to_detailFragment"
            app:destination="@id/detailFragment"
            app:enterAnim="@anim/nav_default_enter_anim"
            app:exitAnim="@anim/nav_default_exit_anim" />
        <argument
            android:name="user_name"
            app:argType="string"
            android:defaultValue="unknown"/>
        <argument
            android:name="age"
            app:argType="integer"
            android:defaultValue="0"/>
    </fragment>
    <fragment
        android:id="@+id/detailFragment"
        android:name="com.dongnaoedu.navigation.DetailFragment"
        android:label="fragment_detail"
        tools:layout="@layout/fragment_detail" >
        <action
            android:id="@+id/action_detailFragment_to_homeFragment"
            app:destination="@id/homeFragment" />
    </fragment>
</navigation>

activity_main.xml的布局如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <fragment
        android:id="@+id/fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/my_nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity中的代碼如下

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        NavController navController = Navigation.findNavController(this, R.id.fragment);
        NavigationUI.setupActionBarWithNavController(this,navController);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.fragment);
        return navController.navigateUp();
    }
}

如果兩個(gè)Fragment之間要通信的話(huà)代碼如下

public class HomeFragment extends Fragment {
    public HomeFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Button button = getView().findViewById(R.id.button);
        button.setOnClickListener((v)->{
            /*Bundle args = new Bundle();
            args.putString("user_name","jack");*/
            Bundle args = new HomeFragmentArgs.Builder()
                    .setUserName("rose")
                    .setAge(18)
                    .build().toBundle();
            NavController navController = Navigation.findNavController(v);
            navController.navigate(R.id.action_homeFragment_to_detailFragment,args);
        });
    }
}
public class DetailFragment extends Fragment {
    public DetailFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_detail, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Button button = getView().findViewById(R.id.button2);
        /*Bundle args = getArguments();
        String userName = args.getString("user_name");*/
        //Log.d("ning","userName:"+userName);

        HomeFragmentArgs args = HomeFragmentArgs.fromBundle(getArguments());
        String userName = args.getUserName();
        int age = args.getAge();
        Log.d("ning",userName+","+age);

        button.setOnClickListener((v)->{
            NavController navController = Navigation.findNavController(v);
            navController.navigate(R.id.action_detailFragment_to_homeFragment);
        });
    }
}
  • 深層連接DeepLink
    PendingIntent方式
    當(dāng)App收到某個(gè)通知推送,我們希望用戶(hù)在點(diǎn)擊該通知時(shí)瘟仿,能夠直接跳轉(zhuǎn)到展示該通知內(nèi)容的頁(yè)面箱锐,可以通過(guò)PendingIntent來(lái)完成。
    URL方式
    當(dāng)用戶(hù)通過(guò)手機(jī)瀏覽器瀏覽網(wǎng)站上某個(gè)頁(yè)面時(shí)劳较,可以在網(wǎng)頁(yè)上放置一個(gè)類(lèi)似于“在應(yīng)用內(nèi)打開(kāi)”的按鈕驹止,如果用戶(hù)已經(jīng)安裝有我們app,那么通過(guò)DeepLink就能打開(kāi)相應(yīng)的頁(yè)面观蜗;如果用戶(hù)沒(méi)有安裝臊恋,那么網(wǎng)站可以導(dǎo)航到應(yīng)用程序的下載頁(yè)面,引導(dǎo)用戶(hù)安裝應(yīng)用程序嫂便。
    adb shell am start -a android.intent.action.VIEW -d"http:// "

7捞镰,WorkMarager

WorkMarager的作用:在后臺(tái)執(zhí)行任務(wù),可能會(huì)消耗大量電量毙替,WorkMarager為應(yīng)用程序中那些不需要及時(shí)完成的任務(wù)岸售,提供了一個(gè)統(tǒng)一的解決方案,以便在設(shè)備電量和用戶(hù)體驗(yàn)之間達(dá)到一個(gè)較好的平衡厂画。
特點(diǎn):
不需要及時(shí)完成的任務(wù)凸丸。
保證任務(wù)一定會(huì)執(zhí)行。
兼容范圍廣袱院。最低兼容API14
使用方法:
1屎慢,添加依賴(lài)
2瞭稼,使用Work類(lèi)定義任務(wù)
3,使用WorkRequests配置任務(wù)
設(shè)置任務(wù)觸發(fā)條件
將任務(wù)觸發(fā)條件設(shè)置到WorkRequest
設(shè)置延遲執(zhí)行任務(wù)
設(shè)置指數(shù)退避策略
為任務(wù)設(shè)置tag標(biāo)簽
4腻惠,將任務(wù)提交給系統(tǒng)
5环肘,觀(guān)察任務(wù)的狀態(tài)
6,取消任務(wù)
7集灌,參數(shù)傳遞
8悔雹,周期性任務(wù)
9,任務(wù)鏈
注意:WorkManager在原生系統(tǒng)執(zhí)行是沒(méi)問(wèn)題的欣喧,在真機(jī)腌零,如小米,華為等是不一定執(zhí)行的唆阿,因?yàn)椴煌瑥S(chǎng)家對(duì)系統(tǒng)的修改都不一樣益涧,所以在真機(jī)上測(cè)試不一定有效,要做一定的適配驯鳖。
添加依賴(lài)

 implementation 'androidx.work:work-runtime:2.4.0-alpha03'

自定義MyWork

public class MyWork extends Worker {

    public MyWork(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        String inputData = getInputData().getString("input_data");
        Log.d("ning","inputData:"+inputData);

        //SystemClock.sleep(2000);
        Log.d("ning","MyWork doWork");

        //任務(wù)執(zhí)行完之后闲询,返回?cái)?shù)據(jù)
        Data outputData = new Data.Builder()
                .putString("output_data", "執(zhí)行成功")
                .build();
        return Result.success(outputData);
    }
}
public class MainActivity extends AppCompatActivity {

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

    public void mAddWork(View view) {
        //設(shè)置觸發(fā)條件
        Constraints constraints = new Constraints.Builder()
                // .setRequiredNetworkType(NetworkType.CONNECTED)//網(wǎng)絡(luò)連接時(shí)執(zhí)行
                // .setRequiresBatteryNotLow(true) //不在電量不足執(zhí)行
                // .setRequiresCharging(true) //在充電時(shí)執(zhí)行
                // .setRequiresStorageNotLow(true) //不在存儲(chǔ)容量不足時(shí)執(zhí)行
                // .setRequiresDeviceIdle(true) //在待機(jī)狀態(tài)下執(zhí)行 調(diào)用需要API級(jí)別最低為23
                // NetworkType.NOT_REQUIRED:對(duì)網(wǎng)絡(luò)沒(méi)有要求
                // NetworkType.CONNECTED:網(wǎng)絡(luò)連接的時(shí)候執(zhí)行
                // NetworkType.UNMETERED:不計(jì)費(fèi)的網(wǎng)絡(luò)比如WIFI下執(zhí)行
                // NetworkType.NOT_ROAMING:非漫游網(wǎng)絡(luò)狀態(tài)
                // NetworkType.METERED:計(jì)費(fèi)網(wǎng)絡(luò)比如3G,4G下執(zhí)行浅辙。
                //注意:不代表恢復(fù)網(wǎng)絡(luò)了嘹裂,就立馬執(zhí)行
                .setRequiredNetworkType(NetworkType.NOT_REQUIRED)
                .build();

        Data inputData = new Data.Builder()
                .putString("input_data","jack")
                .build();

        //配置任務(wù)
        //一次性執(zhí)行的任務(wù)
        OneTimeWorkRequest workRequest1 = new OneTimeWorkRequest.Builder(MyWork.class)
                //設(shè)置觸發(fā)條件
                .setConstraints(constraints)
                //設(shè)置延遲執(zhí)行
                .setInitialDelay(5, TimeUnit.SECONDS)
                //指數(shù)退避策略
                .setBackoffCriteria(BackoffPolicy.LINEAR, Duration.ofSeconds(2))
                //設(shè)置tag標(biāo)簽
                .addTag("workRequest1")
                //參數(shù)傳遞
                .setInputData(inputData)
                .build();

        //周期性任務(wù)
        //不能少于15分鐘
        PeriodicWorkRequest workRequest2 = new PeriodicWorkRequest.Builder(MyWork.class,Duration.ofMinutes(15))
                .build();

        //任務(wù)提交給WorkManager
        WorkManager workManager = WorkManager.getInstance(this);
        workManager.enqueue(workRequest1);

        //觀(guān)察任務(wù)狀態(tài)
        workManager.getWorkInfoByIdLiveData(workRequest1.getId()).observe(this, new Observer<WorkInfo>() {
            @Override
            public void onChanged(WorkInfo workInfo) {
                Log.d("ning",workInfo.toString());
                if(workInfo != null && workInfo.getState() == WorkInfo.State.SUCCEEDED){
                    String outputData = workInfo.getOutputData().getString("output_data");
                    Log.d("ning","outputData:"+outputData);
                }
            }
        });

        //取消任務(wù)
        /*new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                workManager.cancelWorkById(workRequest1.getId());
            }
        }, 2000);*/

    }
}
public class SecondActivity extends AppCompatActivity {

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

    public void mAddWork(View view) {
        OneTimeWorkRequest workA = new OneTimeWorkRequest.Builder(AWorker.class)
                .build();
        OneTimeWorkRequest workB = new OneTimeWorkRequest.Builder(BWorker.class)
                .build();

        OneTimeWorkRequest workC = new OneTimeWorkRequest.Builder(CWorker.class)
                .build();
        OneTimeWorkRequest workD = new OneTimeWorkRequest.Builder(DWorker.class)
                .build();
        OneTimeWorkRequest workE = new OneTimeWorkRequest.Builder(EWorker.class)
                .build();

        //任務(wù)組合
        WorkContinuation workContinuation1 = WorkManager.getInstance(this)
                .beginWith(workA)
                .then(workB);

        WorkContinuation workContinuation2 = WorkManager.getInstance(this)
                .beginWith(workC)
                .then(workD);

        List<WorkContinuation> taskList = new ArrayList<>();
        taskList.add(workContinuation1);
        taskList.add(workContinuation2);

        WorkContinuation.combine(taskList)
                .then(workE)
                .enqueue();

        //任務(wù)鏈
        /*WorkManager.getInstance(this)
                .beginWith(workA)
                .then(workB)
                .enqueue();*/
    }
}

8,Paging

Paging是為了方便開(kāi)發(fā)者完成分頁(yè)加載而設(shè)計(jì)的一個(gè)組件摔握,它為幾種常見(jiàn)的分頁(yè)機(jī)制提供了統(tǒng)一的解決方案。
Paging有3個(gè)核心類(lèi)

  • PageListAdapter
    RecyclerView需要搭配適配器使用丁寄,如果希望使用Paging組件氨淌,適配器需要繼承自PageListAdapter
  • PageList
    負(fù)責(zé)通知DataSource何時(shí)獲取數(shù)據(jù),以及如何獲取數(shù)據(jù)伊磺。從DataSource獲取的數(shù)據(jù)將存儲(chǔ)在PageList中盛正。
  • DataSource
    有三種PositionDataSource,PageKeyedDataSource屑埋,ItemKeyedDataSource
    執(zhí)行具體的數(shù)據(jù)加載工作豪筝,數(shù)據(jù)可以來(lái)源網(wǎng)絡(luò),數(shù)據(jù)庫(kù)摘能,網(wǎng)絡(luò)+數(shù)據(jù)庫(kù)续崖。數(shù)據(jù)的載入需要在子線(xiàn)程中進(jìn)行。
    1团搞,PositionDataSource
    適用于可通過(guò)任意位置加載數(shù)據(jù)严望,且目標(biāo)數(shù)據(jù)源數(shù)固定的情況。
    2逻恐,PageKeyedDataSource
    適用于數(shù)據(jù)源已頁(yè)的方式進(jìn)行請(qǐng)求的情況像吻。
    3峻黍,ItemKeyedDataSource
    適用于當(dāng)目標(biāo)數(shù)據(jù)的下一頁(yè)需要依賴(lài)上一頁(yè)數(shù)據(jù)中最后一個(gè)對(duì)象中的某個(gè)字段最為key的情況,此類(lèi)分頁(yè)形式常見(jiàn)于評(píng)論功能的實(shí)現(xiàn)拨匆。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姆涩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惭每,更是在濱河造成了極大的恐慌骨饿,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洪鸭,死亡現(xiàn)場(chǎng)離奇詭異样刷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)览爵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)置鼻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蜓竹,你說(shuō)我怎么就攤上這事箕母。” “怎么了俱济?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵嘶是,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蛛碌,道長(zhǎng)聂喇,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任蔚携,我火速辦了婚禮希太,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酝蜒。我一直安慰自己誊辉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布亡脑。 她就那樣靜靜地躺著堕澄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霉咨。 梳的紋絲不亂的頭發(fā)上蛙紫,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音躯护,去河邊找鬼惊来。 笑死,一個(gè)胖子當(dāng)著我的面吹牛棺滞,可吹牛的內(nèi)容都是我干的裁蚁。 我是一名探鬼主播矢渊,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼枉证!你這毒婦竟也來(lái)了矮男?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤室谚,失蹤者是張志新(化名)和其女友劉穎毡鉴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體秒赤,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猪瞬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了入篮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陈瘦。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖潮售,靈堂內(nèi)的尸體忽然破棺而出痊项,到底是詐尸還是另有隱情,我是刑警寧澤酥诽,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布鞍泉,位于F島的核電站,受9級(jí)特大地震影響肮帐,放射性物質(zhì)發(fā)生泄漏咖驮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一训枢、第九天 我趴在偏房一處隱蔽的房頂上張望游沿。 院中可真熱鬧,春花似錦肮砾、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至枣宫,卻和暖如春婆誓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背也颤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工洋幻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翅娶。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓文留,卻偏偏與公主長(zhǎng)得像好唯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子燥翅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容