<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stone</title>
    <description>The latest articles on DEV Community by Stone (@yuyalei).</description>
    <link>https://dev.to/yuyalei</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F463526%2F3436eb47-bb6a-49a4-b89c-d50f0c63c93a.png</url>
      <title>DEV Community: Stone</title>
      <link>https://dev.to/yuyalei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yuyalei"/>
    <language>en</language>
    <item>
      <title>Jump to the specified Activity of the other app</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Sat, 03 Apr 2021 09:23:49 +0000</pubDate>
      <link>https://dev.to/yuyalei/jump-to-the-specified-activity-of-the-other-app-2971</link>
      <guid>https://dev.to/yuyalei/jump-to-the-specified-activity-of-the-other-app-2971</guid>
      <description>&lt;p&gt;Recently, the company has a demand to click on the link of H5 page or the button of the APP(I named A here) to go directly to a specified activity of other app(named B). After research, I summarized some methods.&lt;/p&gt;

&lt;p&gt;-----------------------------App B--------------------------------&lt;/p&gt;

&lt;p&gt;First of all, For app B,in the AndroidManifest.xml You can configure it by adding an intent filter to the corresponding activity, as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;activity android:name=".SecondActivity"&amp;gt;
            &amp;lt;intent-filter&amp;gt;
                &amp;lt;action android:name="android.intent.action.VIEW" /&amp;gt;
                &amp;lt;category android:name="android.intent.category.DEFAULT"/&amp;gt;
                &amp;lt;category android:name="android.intent.category.BROWSABLE"/&amp;gt;
                &amp;lt;data android:scheme="hello" /&amp;gt;
            &amp;lt;/intent-filter&amp;gt;
        &amp;lt;/activity&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the relevant test code to the corresponding activity, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Intent intent = getIntent();
        String action = intent.getAction();
        if (Intent.ACTION_VIEW.equals(action)) {
            Uri uri = intent.getData();
            if (uri != null) {
                String host = uri.getHost();
                String dataString = intent.getDataString();
                String id = uri.getQueryParameter("id");
                String path = uri.getPath();
                String path1 = uri.getEncodedPath();
                String queryString = uri.getQuery();
                Log.d("Stone", "host:" + host);
                Log.d("Stone", "dataString:" + dataString);
                Log.d("Stone", "id:" + id);
                Log.d("Stone", "path:" + path);
                Log.d("Stone", "path1:" + path1);
                Log.d("Stone", "queryString:" + queryString);
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the log is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;host:schemedemo
dataString:hello://schemedemo/get/info?id=001
id:001
path:/get/info
path1:/get/info
queryString:id=001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-------------------------------App A------------------------------&lt;br&gt;
Go straight to the code.&lt;br&gt;
**1. jump to ther app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//luanch App
    public static void launchApp(Context context,String packageNAME) {
        //Is the app installed or not
        if (isAppInstalled(context,packageNAME)){
            //if have installed,open app
            startActivityXXX(params...);
        }else{
            //If not, go into the system appstore to find this app and prompt you to download the app
            goToMarket(context, packageNAME);
        }
    }

    //Enter the app store and download the corresponding app。
    private static void goToMarket(Context context, String packageName) {
        Uri uri = Uri.parse("market://details?id=" + packageName);
        Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
        try {
            context.startActivity(goToMarket);
        } catch (Exception e) {
        }
    }
    //Determine whether the app has been installed
    private static boolean isAppInstalled(Context context, String packageName) {
        try {
            context.getPackageManager().getPackageInfo(packageName,0);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;**2. luch other app outside this app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static void LunchAppByUri(Context context, String url) {
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_DEFAULT);//filter condition
        context.startActivity(intent); 
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or You can also change the form like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static void LunchAppByUri(Context context, String url){
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(Intent.ACTION_VIEW);
        intent.addCategory(Intent.CATEGORY_DEFAULT);//filter condition
        intent.setData(Uri.parse(url));
        context.startActivity(intent);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;----------------------------------- H5 --------------------------------&lt;br&gt;
this part is easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="paraches://schemedemo/get/info?id=10000"&amp;gt;open android app&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;----------------------------- jump to B inside A ----------------------&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public static void lunchAppInside(Context context,String packageName,String classNme){
        Intent intent = new Intent(Intent.ACTION_MAIN);
//such as :"com.mogujie.B", "com.mogujie.B.SecondActivity
        ComponentName componentName = new ComponentName(packageName, classNme);
        intent.setComponent(componentName);
        context.startActivity(intent);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note that：&lt;br&gt;
For app B,in the AndroidManifest.xml，you need add One more attribute —— android:exported="true"，finally like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;activity android:name=".SecondActivity" android:exported="true"/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Simple demo of Android reverse /hook</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Fri, 02 Apr 2021 10:51:51 +0000</pubDate>
      <link>https://dev.to/yuyalei/simple-demo-of-android-reverse-hook-1i33</link>
      <guid>https://dev.to/yuyalei/simple-demo-of-android-reverse-hook-1i33</guid>
      <description>&lt;h3&gt;
  
  
  what is xposed
&lt;/h3&gt;

&lt;p&gt;Xposed is a special Android application. By replacing the files such as app_process witch under system\bin\Process to control the zygote process, so as to control all the app processes on the mobile phone; the disadvantage is that it can't hook the functions in the so application&lt;/p&gt;

&lt;h3&gt;
  
  
  how to install xposed
&lt;/h3&gt;

&lt;p&gt;refer to &lt;a href="https://dev.to/yuyalei/installation-of-xposed-framework-for-android-phone-5ei8"&gt;Install xposed for Android phone&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  a demo for xposed
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;create a new Android project&lt;/li&gt;
&lt;li&gt;modify(alter, change? I dont konw..)the AndroidManifest,xml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- Whether it is an xposed module. Xposed judges whether it is a module based on this
        &amp;lt;meta-data
            android:name="xposedmodule"
            android:value="true" /&amp;gt;

        &amp;lt;!-- The module description --&amp;gt;
        &amp;lt;meta-data
            android:name="xposeddescription"
            android:value="xposed demo" /&amp;gt;

        &amp;lt;!-- The minimum version supported is 30--&amp;gt;
        &amp;lt;meta-data
            android:name="xposedminversion"
            android:value="30" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.add dependency&lt;br&gt;
open buile.gradle (module:app)File, add the following code in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; compileOnly 'de.robv.android.xposed:api:82'
 compileOnly 'de.robv.android.xposed:api:82:sources'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;IXposedHookLoadPackage&lt;br&gt;
Create a new Java class(MainIntercept) and implements Ixposedhookloadpackage and override the handleloadpackage method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;xposed_init&lt;br&gt;
Create an assets under Src/Mian, add xposed_init under it,, the code inside is your hook class package name + class name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rewrite the Mainactivity code as follows:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public class MainActivity extends BaseActivity

    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ............
        textView.setText(getText());
        ............
    }

    private String getText(){
          return "-----ha ha !!-----";
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6.change the code in MainIntercept:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MainIntercept implements IXposedHookLoadPackage {

    @Override
     public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
    if(!lpparam.packageName.equals("com.xxx.xxx")) return;

  XposedHelpers.findAndHookMethod("com.xxx.xxx.xxx.MainActivity", lpparam.classLoader, "getText", new XC_MethodHook() {

            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                param.setResult("----I was changed-----");
            }

        });

    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7.Rebuild, &lt;strong&gt;select the app in xposedinstaller and restart it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fmi0rrax5kw5osincw4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fmi0rrax5kw5osincw4.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8m1jap4rdqrehctk677.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8m1jap4rdqrehctk677.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6jgoafphowuzpomgzh2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh6jgoafphowuzpomgzh2.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8.after restart the app,When this method is executed，you will see the result is '----I was changed-----' instead of '-----ha ha !!-----'&lt;/p&gt;

</description>
      <category>android</category>
      <category>xposed</category>
    </item>
    <item>
      <title>View which activity is open in the current app</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Mon, 29 Mar 2021 10:01:47 +0000</pubDate>
      <link>https://dev.to/yuyalei/view-which-activity-is-open-in-the-current-app-16kl</link>
      <guid>https://dev.to/yuyalei/view-which-activity-is-open-in-the-current-app-16kl</guid>
      <description>&lt;p&gt;&lt;strong&gt;Method 1&lt;/strong&gt;&lt;br&gt;
open Android Studio,At the bottom, there is a terminal button,click and open it.&lt;br&gt;
Enter: adb shell dumpsys activity | findstr "ResumedActivity" ,and press enter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 2&lt;/strong&gt;&lt;br&gt;
Click the window key (on the right side of the CTRL key) and enter the power shell.&lt;br&gt;
Enter: adb shell dumpsys activity | findstr "ResumedActivity" ,and press enter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 3&lt;/strong&gt;&lt;br&gt;
"Window key + R key" to open the computer's "run" window, enter "CMD",Enter your adb.exe Directory&lt;br&gt;
Enter:adb shell "dumpsys window | grep mCurrentFocus",and press enter&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Install xposed for Android phone</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Fri, 26 Mar 2021 13:20:51 +0000</pubDate>
      <link>https://dev.to/yuyalei/installation-of-xposed-framework-for-android-phone-5ei8</link>
      <guid>https://dev.to/yuyalei/installation-of-xposed-framework-for-android-phone-5ei8</guid>
      <description>&lt;p&gt;Reverse app, hook, etc. all need to use xposed framework. Before doing these things, you need to do mobile root, install xposed, etc. After Android 8.0, the author of xposed framework is not updating, instead of edxpose&lt;/p&gt;

&lt;h2&gt;
  
  
  content
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;flash rom
2、ROOT
3、Xposed &amp;amp; EdXpose&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  flash rom
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.google.cn/android/images#sailfish"&gt;https://developers.google.cn/android/images#sailfish&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M-SWbi2X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ublnbom2g3gpyy11vgnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M-SWbi2X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ublnbom2g3gpyy11vgnx.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
find the version of your phone, you'd better choose a highter version , and there will be a flash back phenomenon. If you are a mobile phone of other models, you can look at the directory on the left and find the corresponding model and version &lt;/p&gt;

&lt;p&gt;download the tool -- platform-tools.zip&lt;br&gt;
windows：&lt;br&gt;
&lt;a href="https://dl.google.com/android/repository/platform-tools_r29.0.5-windows.zip"&gt;https://dl.google.com/android/repository/platform-tools_r29.0.5-windows.zip&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mac ：&lt;br&gt;
&lt;a href="https://dl.google.com/android/repository/platform-tools_r29.0.5-darwin.zip"&gt;https://dl.google.com/android/repository/platform-tools_r29.0.5-darwin.zip&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Linux ：&lt;br&gt;
&lt;a href="https://dl.google.com/android/repository/platform-tools_r29.0.5-linux.zip"&gt;https://dl.google.com/android/repository/platform-tools_r29.0.5-linux.zip&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take Windows 7 as an example，aster download ,rename platform-tools&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--InsTarlP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90bdo7rsehbx2s3ixefo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--InsTarlP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90bdo7rsehbx2s3ixefo.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
When the mobile phone is turned off, press and hold the power key and + volume down key for a long time (or execute ADB reboot bootloader on the boot interface), and the mobile phone will enter the robot interface&lt;br&gt;
Remember to connect the computer with a data cable&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oy6OLhn2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lnp2mudffro0q52pei0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oy6OLhn2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lnp2mudffro0q52pei0d.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;double click flash-all.bat&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cjb1zelj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ehxi2zo6avz0a54ouv44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cjb1zelj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ehxi2zo6avz0a54ouv44.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  root
&lt;/h2&gt;

&lt;p&gt;turn on the Developer options&lt;br&gt;
down load the Magisk on the website:&lt;br&gt;
&lt;a href="https://github.com/topjohnwu/Magisk/releases"&gt;https://github.com/topjohnwu/Magisk/releases&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9fwwTNCO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ryypqfl689xlvnfxwr7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9fwwTNCO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ryypqfl689xlvnfxwr7u.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
Put the downloaded zip file(Magisk.zip) into the sdcard,and remember the path&lt;br&gt;
download root tools：&lt;br&gt;
&lt;a href="https://github.com/eseGithub/AndroidTools/blob/master/Sailfish-twrp-recovery-Tools-3.2.3-0.rar"&gt;https://github.com/eseGithub/AndroidTools/blob/master/Sailfish-twrp-recovery-Tools-3.2.3-0.rar&lt;/a&gt;&lt;br&gt;
Unzip to platform-toolsJust put it in the directory&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dkreH_4e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1lo6ou8dvm9qpwu7b8id.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dkreH_4e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1lo6ou8dvm9qpwu7b8id.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click start bootloader.bat  t&lt;br&gt;
During this period, the mobile phone and computer are connected by data cable, and it is in USB debugging mode.&lt;br&gt;
Then running Sailfish-twrp-recovery-Tools.bat&lt;br&gt;
Then the installation interface will appear in the screen.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wj1Od1Lj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0k6j5kthkfgpvxw852qo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wj1Od1Lj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0k6j5kthkfgpvxw852qo.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
select  Install ---&amp;gt; swipe to Allow Modifications --&amp;gt; find and slect the filel Magisk.zip --&amp;gt; swipe to confirm flash after done,click Reboot System&lt;/p&gt;

&lt;p&gt;USB debugging should be turned off and on again..&lt;br&gt;
Then you execute the Su command on your computer and authorize it on your phone&lt;/p&gt;

&lt;h2&gt;
  
  
  Xposed &amp;amp; EdXpose
&lt;/h2&gt;

&lt;p&gt;Xposed wont be updated after Android 7.0. So I use edxposed instead;Edxposed depends on Riru-core so install Riru-core first:&lt;br&gt;
&lt;a href="https://github.com/RikkaApps/Riru/releases"&gt;https://github.com/RikkaApps/Riru/releases&lt;/a&gt;&lt;br&gt;
after downlad copy it into the phone&lt;br&gt;
install it by Magisk&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SPRs-R2l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jd0vxgmale1s9da55p26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SPRs-R2l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jd0vxgmale1s9da55p26.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--laPdKmy2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xc6epw84qx3y846ssizu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--laPdKmy2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xc6epw84qx3y846ssizu.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
then restart(重启)&lt;br&gt;
download EdXposed&lt;br&gt;
&lt;a href="https://github.com/ElderDrivers/EdXposed/releases/"&gt;https://github.com/ElderDrivers/EdXposed/releases/&lt;/a&gt;&lt;br&gt;
Install EdXposed in the same way as installing Riru-core&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vDOU_cH8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95udxu8lmhb4l8rfp11e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vDOU_cH8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/95udxu8lmhb4l8rfp11e.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;refer :&lt;a href="https://blog.csdn.net/tangyuan569/article/details/103751699"&gt;https://blog.csdn.net/tangyuan569/article/details/103751699&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>reserve</category>
    </item>
    <item>
      <title>Solution to incomplete display of Scrollview nested ConstraintLayout or LinearLayout</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Mon, 16 Nov 2020 06:13:24 +0000</pubDate>
      <link>https://dev.to/yuyalei/solution-to-incomplete-display-of-scrollview-nested-constraintlayout-or-linearlayout-56c9</link>
      <guid>https://dev.to/yuyalei/solution-to-incomplete-display-of-scrollview-nested-constraintlayout-or-linearlayout-56c9</guid>
      <description>&lt;p&gt;The content exceeds screen's length,so use a ConstraintLayout wrap the contents up,then use a Scrollview nested outside,but after run on phone,the content can't display completely display.see the source code of Scrollview&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (!mFillViewport) {
            return;
        }

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode == MeasureSpec.UNSPECIFIED) {
            return;
        }

        if (getChildCount() &amp;gt; 0) {
            final View child = getChildAt(0);
            final int widthPadding;
            final int heightPadding;
            final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
            final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
            if (targetSdkVersion &amp;gt;= VERSION_CODES.M) {
                widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
                heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
            } else {
                widthPadding = mPaddingLeft + mPaddingRight;
                heightPadding = mPaddingTop + mPaddingBottom;
            }

            final int desiredHeight = getMeasuredHeight() - heightPadding;
            if (child.getMeasuredHeight() &amp;lt; desiredHeight) {
                final int childWidthMeasureSpec = getChildMeasureSpec(
                        widthMeasureSpec, widthPadding, lp.width);
                final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                        desiredHeight, MeasureSpec.EXACTLY);
                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all,we see, when mfillview is false, it will be returned. The explanation of mfillview is: when this variable is set to true, Scrollview will make its child views fill in the currently visible area,I Try to add the attribute android:fillViewport under the Scrollview tag&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android:fillViewport="true"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;android:layout_marginBottom="xxdp"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;under the ConstraintLayout/Linearlayout&lt;/p&gt;

</description>
      <category>android</category>
    </item>
    <item>
      <title>In and out type variant of Kotlin</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Sat, 19 Sep 2020 14:53:29 +0000</pubDate>
      <link>https://dev.to/yuyalei/in-and-out-type-variant-of-kotlin-3dp7</link>
      <guid>https://dev.to/yuyalei/in-and-out-type-variant-of-kotlin-3dp7</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CB4makip--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3dmw4upfy2e23rrq5v38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CB4makip--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3dmw4upfy2e23rrq5v38.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
If you ever defined generic in kotlin,you'll notice many a times,it would propose to use the in or outkeyword to define the .It puzzles me at a start on when which is used,and for what&lt;/p&gt;

&lt;p&gt;Formally,this is a way to define &lt;em&gt;contravariance&lt;/em&gt; and &lt;em&gt;covariant&lt;/em&gt;.It took me a while to learn about it,I'll dive in here to explain what how I understand and memorize their different.&lt;/p&gt;
&lt;h1&gt;
  
  
  In &amp;amp; Out easily remembered
&lt;/h1&gt;
&lt;h2&gt;
  
  
  out(covariant type)
&lt;/h2&gt;

&lt;p&gt;if your generic class only use the generic type as output of it's function/s,then out is used i.e.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Production&amp;lt;out T&amp;gt; {
    fun produce(): T
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I call it production class/interface,as it is mainly to produce output of the generic type.hence very simple one could remember&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;produce = output = out&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  In (contravariance type)
&lt;/h2&gt;

&lt;p&gt;If your generic class only use the generic type as input of it's function/s,then in is used i.e.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Consumer&amp;lt;in T&amp;gt; {
    fun consume(item: T)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I call it consumer class/interface,as it is mainly consuming the generic type.Hence very simple one could remember&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;consume = input = in&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Invariant Type
&lt;/h2&gt;

&lt;p&gt;In the event one generic class uses the generic type as input and output to it's function,then no in or out is used,it is invariant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface ProductionConsumer&amp;lt;T&amp;gt; {
    fun produce(): T
    fun consume(item: T)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Why use In and Out?
&lt;/h1&gt;

&lt;p&gt;Well,now you could easily remember when  inandoutis stated,what is their significance? Before we go there,let's define &lt;em&gt;burger&lt;/em&gt; class object.It is a &lt;em&gt;fastfood&lt;/em&gt; ,which is a type of &lt;em&gt;food&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The simple class hierarchy as bleow&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vcBVQoUk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0uzxi4b1spesr6ko1vr0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vcBVQoUk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0uzxi4b1spesr6ko1vr0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;open class Food
open class FastFood : Food() 
class Burger : FastFood()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Burger Production
&lt;/h2&gt;

&lt;p&gt;Looking at the generic &lt;strong&gt;Production&lt;/strong&gt; interface defined above,Let's further expand them to product &lt;em&gt;food&lt;/em&gt;,&lt;em&gt;fastfood&lt;/em&gt; and &lt;em&gt;burger&lt;/em&gt; as below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class FoodStore : Production&amp;lt;Food&amp;gt; {
    override fun produce(): Food {
        println("Produce food")
        return Food()
    }
}

class FastFoodStore : Production&amp;lt;FastFood&amp;gt; {
    override fun produce(): FastFood {
        println("Produce food")
        return FastFood()
    }
}

class InOutBurger : Production&amp;lt;Burger&amp;gt; {
    override fun produce(): Burger {
        println("Produce burger")
        return Burger()
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, lets have Food Production holders, we could assigned all of them to it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val production1 : Production&amp;lt;Food&amp;gt; = FoodStore()
val production2 : Production&amp;lt;Food&amp;gt; = FastFoodStore()
val production3 : Production&amp;lt;Food&amp;gt; = InOutBurger()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Either a &lt;em&gt;burger&lt;/em&gt; or &lt;em&gt;fastFood&lt;/em&gt; production, is still a &lt;em&gt;food&lt;/em&gt; production. Hence&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For 'out' generic, we could assign a class of subtype to class of super-type&lt;br&gt;
If we change to below, it would error out, because &lt;em&gt;food&lt;/em&gt; or &lt;em&gt;fastFood&lt;/em&gt; is not just a &lt;em&gt;burger&lt;/em&gt; production.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val production1 : Production&amp;lt;Burger&amp;gt; = FoodStore()  // Error
val production2 : Production&amp;lt;Burger&amp;gt; = FastFoodStore()  // Error
val production3 : Production&amp;lt;Burger&amp;gt; = InOutBurger()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Burger Consumer
&lt;/h2&gt;

&lt;p&gt;Now, looking at the generic &lt;strong&gt;Consumer&lt;/strong&gt; interface defined above, let’s further expand them to consume &lt;em&gt;food&lt;/em&gt;, &lt;em&gt;fastfood&lt;/em&gt; and &lt;em&gt;burger&lt;/em&gt; as below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Everybody : Consumer&amp;lt;Food&amp;gt; {
    override fun consume(item: Food) {
        println("Eat food")
    }
}

class ModernPeople : Consumer&amp;lt;FastFood&amp;gt; {
    override fun consume(item: FastFood) {
        println("Eat fast food")
    }
}

class American : Consumer&amp;lt;Burger&amp;gt; {
    override fun consume(item: Burger) {
        println("Eat burger")
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, lets have Burger Consumer holders, we could assigned all of them to it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val consumer1 : Consumer&amp;lt;Burger&amp;gt; = Everybody()
val consumer2 : Consumer&amp;lt;Burger&amp;gt; = ModernPeople()
val consumer3 : Consumer&amp;lt;Burger&amp;gt; = American()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here, a burger consumer is an &lt;em&gt;American&lt;/em&gt;, who is also part of &lt;em&gt;ModernPeople&lt;/em&gt;, who is part of &lt;em&gt;Everybody&lt;/em&gt;. Hence&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For ‘in' generic, we could assign a class of super-type to class of subtype&lt;br&gt;
If we change to below,it would error out,because consumer of &lt;em&gt;Food&lt;/em&gt; althought could be &lt;em&gt;American&lt;/em&gt; or &lt;em&gt;ModernPeople&lt;/em&gt;,it is not just &lt;em&gt;American&lt;/em&gt; or just &lt;em&gt;ModernPeople&lt;/em&gt; .&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val consumer1 : Consumer&amp;lt;Food&amp;gt; = Everybody()
val consumer2 : Consumer&amp;lt;Food&amp;gt; = ModernPeople()  // Error
val consumer3 : Consumer&amp;lt;Food&amp;gt; = American()  // Error
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Another way to remember In and Out
&lt;/h1&gt;

&lt;p&gt;Given the above, another to know when to use what is, for&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SuperType could be assigned subtype, use IN&lt;br&gt;
SubType could be assigned to SuperType, use OUT&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3iew5HDa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4whe0r6gh56hzcsqj01t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3iew5HDa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4whe0r6gh56hzcsqj01t.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/mobile-app-development-publication/in-and-out-type-variant-of-kotlin-587e4fa2944c"&gt;from &amp;gt; In and out type variant of Kotlin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
    </item>
    <item>
      <title>Determine if recycleviw slides to the bottom</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Sat, 12 Sep 2020 12:30:51 +0000</pubDate>
      <link>https://dev.to/yuyalei/determine-if-recycleviw-slides-to-the-bottom-3ig7</link>
      <guid>https://dev.to/yuyalei/determine-if-recycleviw-slides-to-the-bottom-3ig7</guid>
      <description>&lt;p&gt;How to judge whether recycleviw slides to the bottom，combine my experience and online examples,I summarize the following 4 methods:&lt;/p&gt;

&lt;h1&gt;
  
  
  method 1:
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; mRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    //The number of items seen on the current screen
val childCount = mRecyclerView.childCount
                   //or
                   //val childCount = mRecyclerView.layoutManager.childCount
                   //number of all items of the RecyclerView
                    val itemCount = mRecyclerView.layoutManager.itemCount
                  //The position of the first visible item in the screen
                    val firstVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
                    if (firstVisibleItem + childCount == itemCount) {
                        //have slide to the bottom...
                    }
                }
            }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  method 2:
&lt;/h1&gt;

&lt;p&gt;in fact,this method is same as first method,see the codes directly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    //The number of items seen on the current screen
                    val childCount = mRecyclerView.childCount
                    //or
                    val childCount = mRecyclerView.layoutManager.childCount
                    //number of all items of the RecyclerView
                    val itemCount = mRecyclerView.layoutManager.itemCount
                    //The position of the last visible item in the screen
                    val lastVisibleItem = (mRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
                    if (childCount &amp;gt; 0 &amp;amp;&amp;amp; lastVisibleItem== itemCount - 1) {
                   //have slide to the bottom...
                    }
                }
            }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  method 3:
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static boolean isSlideToBottom(RecyclerView recyclerView) {    
   if (recyclerView == null) return false; 
   if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() 
        &amp;gt;= recyclerView.computeVerticalScrollRange())   
     return true;  
   return false;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4YfUuSOE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/osotn077smbz10s9pvsl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4YfUuSOE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/osotn077smbz10s9pvsl.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Computeverticalscrollextent() is the height of the area displayed on the current screen&lt;br&gt;
Computeverticalscrolloffset() is the distance that the current screen has swiped before&lt;br&gt;
Computeverticalscrollrange() is the height of the entire view&lt;/p&gt;
&lt;h1&gt;
  
  
  method 4:
&lt;/h1&gt;

&lt;p&gt;RecyclerView.canScrollVertically (1) The value of indicates whether it can scroll up or not, false indicates that it has been scrolled to the bottom;&lt;br&gt;
RecyclerView.canScrollVertically (-1) indicates whether it can scroll down or not, false indicates that it has scrolled to the top&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if(mRecyclerView.canScrollVertically(1)){
                    Log.i(TAG, "direction 1: true");
                }else {
                    Log.i(TAG, "direction 1: false");//has been scrolled to the bottom
                }
                if(mRecyclerView.canScrollVertically(-1)){
                    Log.i(TAG, "direction -1: true");
                }else {
                    Log.i(TAG, "direction -1: false");//has scrolled to the top
                }
            }
        });
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>android</category>
    </item>
    <item>
      <title>kotlin not-null judgment</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Fri, 11 Sep 2020 14:11:56 +0000</pubDate>
      <link>https://dev.to/yuyalei/kotlin-not-null-judgment-d1e</link>
      <guid>https://dev.to/yuyalei/kotlin-not-null-judgment-d1e</guid>
      <description>&lt;h1&gt;
  
  
  ?
&lt;/h1&gt;

&lt;p&gt;When declaring an object instance,add ? after the type name indicates that the object can be null&lt;br&gt;
When an object method is called, add ? after the instance name to indicate that null is returned once the instance is empty&lt;/p&gt;

&lt;h1&gt;
  
  
  ?.
&lt;/h1&gt;

&lt;p&gt;var length = str?.length;&lt;br&gt;
when str is null,return null;when str is not null,return str.length.&lt;/p&gt;

&lt;h1&gt;
  
  
  ?:
&lt;/h1&gt;

&lt;p&gt;var length = str?.length?: -1&lt;br&gt;
if str is null, return -1,else return str.lenght&lt;/p&gt;

&lt;h1&gt;
  
  
  !!
&lt;/h1&gt;

&lt;p&gt;var length = str!!.length&lt;br&gt;
if str is null,trow NullPointerException&lt;/p&gt;

</description>
      <category>kotlin</category>
    </item>
    <item>
      <title>multi-thread —— handler</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Tue, 08 Sep 2020 12:56:04 +0000</pubDate>
      <link>https://dev.to/yuyalei/multi-thread-handler-f36</link>
      <guid>https://dev.to/yuyalei/multi-thread-handler-f36</guid>
      <description>&lt;p&gt;when it come to handler,we will think of handler, looper, message.&lt;br&gt;
&lt;strong&gt;handler&lt;/strong&gt;:the processor of message,communicate with looper,push the new message into the MessageQueue or receive message send by Looper from MessageQueue&lt;br&gt;
&lt;strong&gt;Looper&lt;/strong&gt;:the processor or circulator of MessageQueue,a thread can product a Looper object,it manages the MessageQueue of this thread&lt;br&gt;
&lt;strong&gt;MessageQueue&lt;/strong&gt;:as the name suggest,it used to store the message witch put in by the thread.it follow the first in and first out principle&lt;br&gt;
&lt;strong&gt;message&lt;/strong&gt;:linked list data structure.it can be reused,in order to avoid wasting memory by creating a large of object&lt;/p&gt;

&lt;h1&gt;
  
  
  the function of handler
&lt;/h1&gt;

&lt;p&gt;1) schedule message or runnable,receive message,hand out and process message&lt;br&gt;
2) Executing tasks in different threads("to enqueue an action to be performed on a different thread than your own")&lt;/p&gt;

&lt;h1&gt;
  
  
  how to use
&lt;/h1&gt;

&lt;p&gt;in development,we can't update UI in child thread,so we send the UI message that need to be updated to the handler,and overrid handleMessage() to deal with the UI operations.Message and handler two classes will be used,Message is responsible for loading message,marking messages with target and storing contents with obj;Handler is responsible for the hand out and processing of messages&lt;br&gt;
to avoid memory leaks,we'd better do 2 things:&lt;br&gt;
1) Call removeCallbacksAndMessages(null) in the onDestroy()&lt;br&gt;
2) Set static inner class and weakreference&lt;br&gt;
&lt;em&gt;tips:&lt;br&gt;
a:one thead can only bind one looper,but can have several handler&lt;br&gt;
b:one looper can bind more than one handler&lt;br&gt;
c:one handler can onely bind one looper&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  workflow of handler
&lt;/h1&gt;

&lt;p&gt;The workflow of handler is executed in the order of message &amp;gt; message queen &amp;gt; loop &amp;gt; handler.&lt;br&gt;
In general, create a handler in the main thread, will directly create the Loop, MessageQueue, and Handler objects in the main thread. The loop object is usually created through the prepare() method.when the looper object is created MessageQueue will be automatically created at the same time.In the worker thread, the handler sends the message through sendmessage() or post(), and in the send() method, enqueuemessage() is used to transmit the message to the message queue,Then looper will take out the message in the MessageQueue through the next () , and send message to the handler through dispatchmessage(). The handler will start processing the message after receiving the message. If the message is not available, the thread will be blocked until there is a message in the message queue.&lt;/p&gt;

</description>
      <category>android</category>
    </item>
    <item>
      <title>Some understandings about MVC \ MVP \ MVVM</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Sun, 06 Sep 2020 14:42:30 +0000</pubDate>
      <link>https://dev.to/yuyalei/some-misunderstandings-about-mvc-mvp-mvvm-1ca</link>
      <guid>https://dev.to/yuyalei/some-misunderstandings-about-mvc-mvp-mvvm-1ca</guid>
      <description>&lt;p&gt;Recently, there is a new project that I want to develop with MVVM。So I try to learned about the MVVM；I found I have some misunderstandings about MVC / MVP / MVVM or have somethings that doesn't have a deep understanding,I sort out the functions of each module.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;mvc:&lt;/em&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oM47EH8m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oc2gxr0n60v00dmj587w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oM47EH8m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oc2gxr0n60v00dmj587w.png" alt="mvc"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;mvp:&lt;/em&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nz1GQHG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3kjhbltnvm1kf84rt45z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nz1GQHG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3kjhbltnvm1kf84rt45z.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;mvvm:&lt;/em&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z6l1K3Uj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r0897x5z7yzjyy6nqvzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z6l1K3Uj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r0897x5z7yzjyy6nqvzb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Ⅰ：presenter/ViewModel
&lt;/h1&gt;

&lt;p&gt;Presenter Or ViewModel is used to deal with presentation level logic,otherwise business logic belongs to m layer&lt;/p&gt;

&lt;p&gt;Suppose the application has a user information page. This page has two states, one is browsing state, the other is editing state. The state transition is triggered by an edit button. When editing, some information items can be edited. Then there is an presentation layer logic, that is, click the button to switch Browse / edit status.&lt;/p&gt;

&lt;p&gt;The view layer needs to do very little, basically accepting user events and passing them to presenter or ViewModel(the view layer is responsible for receiving the click event of the Edit button, and then notifies the presenter / ViewModel), and then the presenter / ViewModel informs the view layer whether to display the view in browsing status or in editing status&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class InformationView {
    void initView() {
        // responsible for receiving the click event of the Edit button, 
//and then notifies the presenter / ViewModel
        editStateButton.setOnClickListener(new OnClickListener() {
            presenter.onEditStateButtonClicked();
        })
        ...
    }
    public void showNormalState() {
        // 
        editStateButton.setText("edit");
        nickName.setEditable(false);
        ...
    }
    public void showEditState() {
        editStateButton.setText("finish");
        nickName.setEditable(true);
        ...
    }
}


public class ProfilePresenter {
    private State curState = State.NORMAL;
    public void onEditStateButtonClicked() {
        // When the button is clicked, judge whether the view should
               //switch the displayed state according to the current state
        // This is the presentation logic
        if (isInEditState()) {
            curState = State.NORMAL;
            view.showNormalState();
        } else {
            curState = State.EDIT;
            view.showEditState();
        }
    }
    private boolean isInEditState() {
        return curState == State.EDIT;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;the presenter / ViewModel decides what to display according to the current state, and what view does is how to display them&lt;/p&gt;

&lt;h1&gt;
  
  
  model
&lt;/h1&gt;

&lt;p&gt;The model layer contains business data and operations on business data.&lt;/p&gt;

&lt;p&gt;Suppose there is a page for displaying a list of recommended blogs. how do we write it in MVP? Let's ignore that there is no interactive view with the model layer. In addition to handling the presentation layer logic, the presenter also issues business instructions to the model layer. So the presenter does not handle business logic, and the real business logic is still completed by the model layer. The sample code looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class RecommendBlogPresenter {
    private RecommendBlogView view;
    private BlogMode model;
    public void onStart() {
        view.showLoadWait();
        model.loadRecommendBlogs(new LoadCallback&amp;lt;&amp;gt;() {
            @Override
            public void onLoaded(List&amp;lt;Blog&amp;gt; blogs) {
                view.showBlogs(blogs);
            }
        })
    }
}


public interface BlogModel {
    void loadRecommendBlogs(LoadCallback&amp;lt;List&amp;lt;Blog&amp;gt;&amp;gt; callback);
}
public class BlogModelImpl implements BlogModel {
    private BlogRepository repo;
    @Override
    public void loadRecommendBlogs(LoadCallback&amp;lt;List&amp;lt;Blog&amp;gt;&amp;gt; callback) {
        // BlogRepository.fetch()
                //usally execute on no main thread
        callback.onLoaded(repo.fetch("recommend"));
    }
}
public interface BlogRepository {
    List&amp;lt;Blog&amp;gt; fetch(String tag);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The business logic layer is not responsible for getting data , getting data should be at a lower level of the model layer(blogrepository),the model layer only deals with business logic&lt;/p&gt;

&lt;p&gt;summary:The presenter / ViewModel relies on the model layer through the interface, and the model layer does not rely on the presenter / ViewModel at all&lt;/p&gt;

</description>
      <category>android</category>
    </item>
    <item>
      <title>kotlin learning notes Ⅴ—— kotlin and java</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Sat, 05 Sep 2020 15:16:49 +0000</pubDate>
      <link>https://dev.to/yuyalei/kotlin-learning-notes-kotlin-and-java-17n3</link>
      <guid>https://dev.to/yuyalei/kotlin-learning-notes-kotlin-and-java-17n3</guid>
      <description>&lt;h1&gt;
  
  
  Mutual call between kotlin and Java
&lt;/h1&gt;

&lt;p&gt;If you declare a function in kotlin, how do you call it in Java?&lt;br&gt;
Suppose that in the KotlinDemo.kt file Write a kotlin function in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun getName(name:String):String{

    return name;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, we create a new Java file called javademo. How do we call the function getName in the file KotlinDemo.kt?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public static void main(String[] args){
        KotlinDemoKt.getName("I am xxx");
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As we can see, we can call this function only by using the file name in kotlin and the function name to be called in the java file. The format is:&lt;br&gt;
.  to be called&lt;br&gt;
This way you can call the Kotlin function in Java.&lt;/p&gt;
&lt;h1&gt;
  
  
  Anonymous Inner Class in kotlin
&lt;/h1&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object Test{
    fun sayHello(){
        print("hello!!");
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Using anonymous inner class in kotlin is very simple. You can use type directly. Function name can be used&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun getTest(){
    Test.sayHello();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;How to use it in Java? It's also very simple&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  public static void main(String[] args){
        Test.INSTANCE.sayHello();
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  static in kotlin
&lt;/h1&gt;

&lt;p&gt;There is no concept of static variables and static methods in kotlin, that is, there is no static keyword in kotlin. So what if we want to have a method similar to public static in Java in kotlin? In fact, this is also very simple. We only need a modifier @ jvmstatic to modify the sayhello function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object Test{
    @JvmStatic
    fun sayHello(){
        print("hello!!");
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this way, sayhello becomes a static method, which can be used directly in Java Test.sayHello () instead of using instance.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>kotlin learning notes Ⅳ—— interface</title>
      <dc:creator>Stone</dc:creator>
      <pubDate>Sat, 05 Sep 2020 14:31:40 +0000</pubDate>
      <link>https://dev.to/yuyalei/kotlin-learning-notes-interface-3if2</link>
      <guid>https://dev.to/yuyalei/kotlin-learning-notes-interface-3if2</guid>
      <description>&lt;h1&gt;
  
  
  interface
&lt;/h1&gt;

&lt;p&gt;The kotlin interface, similar to Java 8, uses the interface keyword to define the interface, allowing methods to have &lt;strong&gt;default implementations&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface MyInterface {
    fun bar()    // not implemented
    fun foo() {  //implemented
      // Optional method body
      println("foo")
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  implement interface
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A class or object can implement one or more interfaces&lt;/strong&gt;&lt;br&gt;
example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface MyInterface {
    fun bar()
    fun foo() {
        // optional function
        println("foo")
    }
}
class Child : MyInterface {
    override fun bar() {
        println("bar")
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Properties in the interface
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The attribute in the interface can only be abstract, and initialization value is not allowed. The interface will not save the property value. When implementing the interface, the property must be rewritten&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;(接口中的属性只能是抽象的，不允许初始化值，接口不会保存属性值，实现接口时，必须重写属性)&lt;/em&gt;&lt;br&gt;
example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface MyInterface {
    var name:String //name , abstract
    fun bar()
    fun foo() {
        // 可选的方法体
        println("foo")
    }
}
class Child : MyInterface {
    override var name: String = "runoob" //override name
    override fun bar() {
        println("bar")
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  override function
&lt;/h2&gt;

&lt;p&gt;When implementing multiple interfaces, you may encounter the problem that the same method inherits multiple implementations. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface A {
    fun foo() { print("A") }   // implemented
    fun bar()                  // abstract, not implemented
}

interface B {
    fun foo() { print("B") }   // implemented
    fun bar() { print("bar") } // implemented
}

class C : A {
    override fun bar() { print("bar") }   // override
}

class D : A, B {
    override fun foo() {
        super&amp;lt;A&amp;gt;.foo()
        super&amp;lt;B&amp;gt;.foo()
    }

    override fun bar() {
        super&amp;lt;B&amp;gt;.bar()
    }
}

fun main(args: Array&amp;lt;String&amp;gt;) {
    val d =  D()
    d.foo();
    d.bar();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ABbar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>kotlin</category>
    </item>
  </channel>
</rss>
